LCOV - code coverage report
Current view: top level - logging/source - RialtoLogging.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 69.3 % 176 122
Test Date: 2025-07-31 10:33:57 Functions: 83.3 % 12 10

            Line data    Source code
       1              : /*
       2              :  * If not stated otherwise in this file or this component's LICENSE file the
       3              :  * following copyright and licenses apply:
       4              :  *
       5              :  * Copyright 2022 Sky UK
       6              :  *
       7              :  * Licensed under the Apache License, Version 2.0 (the "License");
       8              :  * you may not use this file except in compliance with the License.
       9              :  * You may obtain a copy of the License at
      10              :  *
      11              :  * http://www.apache.org/licenses/LICENSE-2.0
      12              :  *
      13              :  * Unless required by applicable law or agreed to in writing, software
      14              :  * distributed under the License is distributed on an "AS IS" BASIS,
      15              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16              :  * See the License for the specific language governing permissions and
      17              :  * limitations under the License.
      18              :  */
      19              : 
      20              : #include <atomic>
      21              : #include <cstdarg>
      22              : #include <cstdio>
      23              : #include <cstring>
      24              : #include <ctime>
      25              : #include <mutex>
      26              : #include <sys/syscall.h>
      27              : #include <sys/uio.h>
      28              : #include <unistd.h>
      29              : 
      30              : #include "EnvVariableParser.h"
      31              : #include "LogFileHandle.h"
      32              : #include "RialtoLogging.h"
      33              : 
      34              : #ifdef USE_ETHANLOG
      35              : 
      36              : #include <ethanlog.h>
      37              : 
      38              : #define SYSTEM_LOG_FATAL(filename, function, line, ...) ethanlog(ETHAN_LOG_FATAL, filename, function, line, __VA_ARGS__)
      39              : #define SYSTEM_LOG_ERROR(filename, function, line, ...) ethanlog(ETHAN_LOG_ERROR, filename, function, line, __VA_ARGS__)
      40              : #define SYSTEM_LOG_WARN(filename, function, line, ...)                                                                 \
      41              :     ethanlog(ETHAN_LOG_WARNING, filename, function, line, __VA_ARGS__)
      42              : #define SYSTEM_LOG_MIL(filename, function, line, ...)                                                                  \
      43              :     ethanlog(ETHAN_LOG_MILESTONE, filename, function, line, __VA_ARGS__)
      44              : #define SYSTEM_LOG_INFO(filename, function, line, ...) ethanlog(ETHAN_LOG_INFO, filename, function, line, __VA_ARGS__)
      45              : #define SYSTEM_LOG_DEBUG(filename, function, line, ...) ethanlog(ETHAN_LOG_DEBUG, filename, function, line, __VA_ARGS__)
      46              : 
      47              : #else
      48              : 
      49              : #include <syslog.h>
      50              : 
      51              : #define SYSTEM_LOG_FATAL(filename, function, line, ...) syslog(LOG_CRIT, __VA_ARGS__)
      52              : #define SYSTEM_LOG_ERROR(filename, function, line, ...) syslog(LOG_ERR, __VA_ARGS__)
      53              : #define SYSTEM_LOG_WARN(filename, function, line, ...) syslog(LOG_WARNING, __VA_ARGS__)
      54              : #define SYSTEM_LOG_MIL(filename, function, line, ...) syslog(LOG_NOTICE, __VA_ARGS__)
      55              : #define SYSTEM_LOG_INFO(filename, function, line, ...) syslog(LOG_INFO, __VA_ARGS__)
      56              : #define SYSTEM_LOG_DEBUG(filename, function, line, ...) syslog(LOG_DEBUG, __VA_ARGS__)
      57              : 
      58              : #endif
      59              : 
      60              : namespace
      61              : {
      62              : /**
      63              :  * Log levels for each component. By default will print all fatals, errors, warnings & milestones.
      64              :  */
      65              : std::atomic<RIALTO_DEBUG_LEVEL> g_rialtoLogLevels[RIALTO_COMPONENT_LAST] = {};
      66              : 
      67              : /**
      68              :  * Default Log levels defined by RIALTO_DEBUG environment variable
      69              :  */
      70              : const firebolt::rialto::logging::EnvVariableParser g_envVariableParser;
      71              : 
      72              : /**
      73              :  * Log handler for each component. By default will use journaldLogHandler.
      74              :  */
      75              : void fdLogHandler(int fd, RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
      76              :                   const char *function, const char *message, size_t messageLen);
      77              : void journaldLogHandler(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
      78              :                         const char *function, const char *message, size_t messageLen);
      79              : 
      80              : firebolt::rialto::logging::LogHandler g_logHandler[RIALTO_COMPONENT_LAST] = {};
      81              : bool g_ignoreLogLevels[RIALTO_COMPONENT_LAST] = {};
      82              : std::mutex g_logHandlerMutex;
      83              : 
      84              : std::string componentToString(RIALTO_COMPONENT component);
      85              : std::string levelToString(RIALTO_DEBUG_LEVEL level);
      86              : 
      87         9167 : std::string componentToString(RIALTO_COMPONENT component)
      88              : {
      89         9167 :     switch (component)
      90              :     {
      91            7 :     case RIALTO_COMPONENT_DEFAULT:
      92           14 :         return "DEF";
      93              :         break;
      94         2940 :     case RIALTO_COMPONENT_CLIENT:
      95         5880 :         return "CLI";
      96              :         break;
      97         5611 :     case RIALTO_COMPONENT_SERVER:
      98        11222 :         return "SRV";
      99              :         break;
     100          153 :     case RIALTO_COMPONENT_IPC:
     101          306 :         return "IPC";
     102              :         break;
     103          387 :     case RIALTO_COMPONENT_SERVER_MANAGER:
     104          774 :         return "SMG";
     105              :         break;
     106           69 :     case RIALTO_COMPONENT_COMMON:
     107          138 :         return "COM";
     108              :         break;
     109            0 :     case RIALTO_COMPONENT_EXTERNAL:
     110            0 :         return "EXT";
     111              :         break;
     112            0 :     default:
     113            0 :         return "UNK";
     114              :         break;
     115              :     }
     116              : }
     117              : 
     118         9167 : std::string levelToString(RIALTO_DEBUG_LEVEL level)
     119              : {
     120         9167 :     switch (level)
     121              :     {
     122            2 :     case RIALTO_DEBUG_LEVEL_FATAL:
     123            4 :         return "FTL";
     124              :         break;
     125          963 :     case RIALTO_DEBUG_LEVEL_ERROR:
     126         1926 :         return "ERR";
     127              :         break;
     128          341 :     case RIALTO_DEBUG_LEVEL_WARNING:
     129          682 :         return "WRN";
     130              :         break;
     131          296 :     case RIALTO_DEBUG_LEVEL_MILESTONE:
     132          592 :         return "MIL";
     133              :         break;
     134         1309 :     case RIALTO_DEBUG_LEVEL_INFO:
     135         2618 :         return "NFO";
     136              :         break;
     137         6256 :     case RIALTO_DEBUG_LEVEL_DEBUG:
     138        12512 :         return "DBG";
     139              :         break;
     140            0 :     case RIALTO_DEBUG_LEVEL_EXTERNAL:
     141            0 :         return "EXT";
     142              :         break;
     143            0 :     default:
     144            0 :         return ":";
     145              :         break;
     146              :     }
     147              : }
     148              : 
     149              : /**
     150              :  * File descriptor logging function for the library.
     151              :  */
     152         9167 : void fdLogHandler(int fd, RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
     153              :                   const char *function, const char *message, size_t messageLen)
     154              : {
     155         9167 :     timespec ts = {0, 0};
     156         9167 :     clock_gettime(CLOCK_MONOTONIC, &ts);
     157              :     struct iovec iov[6];
     158              :     char tbuf[32];
     159              : 
     160         9167 :     iov[0].iov_base = tbuf;
     161         9167 :     iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "%.010lu.%.06lu ", ts.tv_sec, ts.tv_nsec / 1000);
     162         9167 :     iov[0].iov_len = std::min(iov[0].iov_len, sizeof(tbuf));
     163              : 
     164              :     char lbuf[8];
     165         9167 :     iov[1].iov_base = reinterpret_cast<void *>(lbuf);
     166         9167 :     iov[1].iov_len =
     167         9167 :         std::min(static_cast<size_t>(snprintf(lbuf, sizeof(lbuf), "%s: ", levelToString(level).c_str())), sizeof(lbuf));
     168              : 
     169              :     char cbuf[8];
     170         9167 :     iov[2].iov_base = reinterpret_cast<void *>(cbuf);
     171         9167 :     iov[2].iov_len =
     172         9167 :         std::min(static_cast<size_t>(snprintf(cbuf, sizeof(cbuf), "%s: ", componentToString(component).c_str())),
     173         9167 :                  sizeof(cbuf));
     174              : 
     175              :     static thread_local pid_t threadId = 0;
     176         9167 :     if (threadId <= 0)
     177           80 :         threadId = syscall(SYS_gettid);
     178              :     char fbuf[180];
     179         9167 :     iov[3].iov_base = reinterpret_cast<void *>(fbuf);
     180              : 
     181         9167 :     if (RIALTO_DEBUG_LEVEL_EXTERNAL == level)
     182              :     {
     183            0 :         iov[3].iov_len = snprintf(fbuf, sizeof(fbuf), "< T:%d >", threadId);
     184              :     }
     185         9167 :     else if (!file || !function || (line <= 0))
     186              :     {
     187            0 :         iov[3].iov_len = snprintf(fbuf, sizeof(fbuf), "< T:%d M:? F:? L:? > ", threadId);
     188              :     }
     189              :     else
     190              :     {
     191         9167 :         iov[3].iov_len =
     192         9167 :             snprintf(fbuf, sizeof(fbuf), "< T:%d M:%.*s F:%.*s L:%d > ", threadId, 64, file, 64, function, line);
     193              :     }
     194         9167 :     iov[3].iov_len = std::min(iov[3].iov_len, sizeof(fbuf));
     195         9167 :     iov[4].iov_base = const_cast<void *>(reinterpret_cast<const void *>(message));
     196         9167 :     iov[4].iov_len = messageLen;
     197         9167 :     iov[5].iov_base = const_cast<void *>(reinterpret_cast<const void *>("\n"));
     198         9167 :     iov[5].iov_len = 1;
     199              :     // TODO(RIALTO-38): consider using standard write(2) and handle EINTR properly.
     200         9167 :     std::ignore = writev(fd, iov, 6);
     201              : }
     202              : /**
     203              :  * Journald logging function for the library.
     204              :  */
     205            0 : void journaldLogHandler(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
     206              :                         const char *function, const char *message, size_t messageLen)
     207              : {
     208              :     static thread_local pid_t threadId = 0;
     209            0 :     if (threadId <= 0)
     210            0 :         threadId = syscall(SYS_gettid);
     211              :     char fbuf[180];
     212            0 :     if (RIALTO_DEBUG_LEVEL_EXTERNAL == level)
     213              :     {
     214            0 :         snprintf(fbuf, sizeof(fbuf), "%s: %s: < T:%d >", levelToString(level).c_str(),
     215            0 :                  componentToString(component).c_str(), threadId);
     216              :     }
     217            0 :     else if (!file || !function || (line <= 0))
     218              :     {
     219            0 :         snprintf(fbuf, sizeof(fbuf), "%s: %s: < T:%d M:? F:? L:? >", levelToString(level).c_str(),
     220            0 :                  componentToString(component).c_str(), threadId);
     221              :     }
     222              :     else
     223              :     {
     224            0 :         snprintf(fbuf, sizeof(fbuf), "%s: %s: < T:%d M:%.*s F:%.*s L:%d >", levelToString(level).c_str(),
     225            0 :                  componentToString(component).c_str(), threadId, 64, file, 64, function, line);
     226              :     }
     227              : 
     228            0 :     switch (level)
     229              :     {
     230            0 :     case RIALTO_DEBUG_LEVEL_FATAL:
     231            0 :         SYSTEM_LOG_FATAL(file, function, line, "%s %s", fbuf, message);
     232            0 :         break;
     233            0 :     case RIALTO_DEBUG_LEVEL_ERROR:
     234            0 :         SYSTEM_LOG_ERROR(file, function, line, "%s %s", fbuf, message);
     235            0 :         break;
     236            0 :     case RIALTO_DEBUG_LEVEL_WARNING:
     237            0 :         SYSTEM_LOG_WARN(file, function, line, "%s %s", fbuf, message);
     238            0 :         break;
     239            0 :     case RIALTO_DEBUG_LEVEL_MILESTONE:
     240            0 :         SYSTEM_LOG_MIL(file, function, line, "%s %s", fbuf, message);
     241            0 :         break;
     242            0 :     case RIALTO_DEBUG_LEVEL_INFO:
     243            0 :         SYSTEM_LOG_INFO(file, function, line, "%s %s", fbuf, message);
     244            0 :         break;
     245            0 :     case RIALTO_DEBUG_LEVEL_DEBUG:
     246            0 :         SYSTEM_LOG_DEBUG(file, function, line, "%s %s", fbuf, message);
     247            0 :         break;
     248            0 :     case RIALTO_DEBUG_LEVEL_EXTERNAL:
     249            0 :         SYSTEM_LOG_INFO(file, function, line, "%s %s", fbuf, message);
     250            0 :         break;
     251            0 :     default:
     252            0 :         break;
     253              :     }
     254              : }
     255              : 
     256         9677 : void rialtoLog(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, const char *func, int line,
     257              :                const char *fmt, va_list ap, const char *append)
     258              : {
     259              :     /* Must be valid component */
     260         9677 :     if (component >= RIALTO_COMPONENT_LAST)
     261          451 :         return;
     262              : 
     263              :     /* If log levels have not been set, set to Default */
     264         9677 :     if (!g_rialtoLogLevels[component])
     265           15 :         g_rialtoLogLevels[component] = g_envVariableParser.getLevel(component);
     266              : 
     267         9677 :     if (!(level & g_rialtoLogLevels[component]) && !g_ignoreLogLevels[component])
     268          451 :         return;
     269              :     char mbuf[512];
     270              :     int len;
     271         9226 :     len = vsnprintf(mbuf, sizeof(mbuf), fmt, ap);
     272         9226 :     if (len < 1)
     273            0 :         return;
     274         9226 :     if (len > static_cast<int>(sizeof(mbuf) - 1))
     275            0 :         len = sizeof(mbuf) - 1;
     276         9226 :     if (mbuf[len - 1] == '\n')
     277            5 :         len--;
     278         9226 :     mbuf[len] = '\0';
     279         9226 :     if (append && (len < static_cast<int>(sizeof(mbuf) - 1)))
     280              :     {
     281           49 :         size_t extra = std::min<size_t>(strlen(append), (sizeof(mbuf) - len - 1));
     282           49 :         memcpy(mbuf + len, append, extra);
     283           49 :         len += static_cast<int>(extra);
     284           49 :         mbuf[len] = '\0';
     285              :     }
     286         9226 :     const char *kFname = nullptr;
     287         9226 :     if (file)
     288              :     {
     289         9226 :         if ((kFname = strrchr(file, '/')) == nullptr)
     290            0 :             kFname = file;
     291              :         else
     292         9226 :             kFname++;
     293              :     }
     294              : 
     295         9226 :     const auto &kLogFileHandle = firebolt::rialto::logging::LogFileHandle::instance();
     296              :     /* If log handler had not been set, use default */
     297         9226 :     firebolt::rialto::logging::LogHandler logHandler = g_logHandler[component]; // local copy for thread safety
     298         9226 :     if (logHandler)
     299              :     {
     300           59 :         logHandler(level, kFname, line, func, mbuf, len);
     301              :     }
     302         9167 :     else if (g_envVariableParser.isFileLoggingEnabled() && kLogFileHandle.isOpen())
     303              :     {
     304            0 :         fdLogHandler(kLogFileHandle.fd(), component, level, kFname, line, func, mbuf, len);
     305              :     }
     306         9167 :     else if (g_envVariableParser.isConsoleLoggingEnabled())
     307              :     {
     308         9167 :         fdLogHandler(STDERR_FILENO, component, level, kFname, line, func, mbuf, len);
     309              :     }
     310              :     else
     311              :     {
     312            0 :         journaldLogHandler(component, level, kFname, line, func, mbuf, len);
     313              :     }
     314         9226 : }
     315              : 
     316              : } // namespace
     317              : 
     318            0 : void rialtoLogVPrintf(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, const char *func,
     319              :                       int line, const char *fmt, va_list ap)
     320              : {
     321            0 :     rialtoLog(component, level, file, func, line, fmt, ap, nullptr);
     322              : }
     323              : 
     324         9590 : void rialtoLogPrintf(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, const char *func, int line,
     325              :                      const char *fmt, ...)
     326              : {
     327              :     va_list ap;
     328         9590 :     va_start(ap, fmt);
     329         9590 :     rialtoLog(component, level, file, func, line, fmt, ap, nullptr);
     330         9590 :     va_end(ap);
     331              : }
     332              : 
     333           87 : void rialtoLogSysPrintf(RIALTO_COMPONENT component, int err, RIALTO_DEBUG_LEVEL level, const char *file,
     334              :                         const char *func, int line, const char *fmt, ...)
     335              : {
     336              :     va_list ap;
     337           87 :     const char *kErrmsg{nullptr};
     338              :     char appendbuf[96];
     339           87 :     const char *kAppend = nullptr;
     340              : #if defined(__linux__)
     341              :     char errbuf[64];
     342           87 :     kErrmsg = strerror_r(err, errbuf, sizeof(errbuf));
     343              : #elif defined(__APPLE__)
     344              :     char errbuf[64];
     345              :     if (strerror_r(err, errbuf, sizeof(errbuf)) != 0)
     346              :         kErrmsg = "Unknown error";
     347              :     else
     348              :         kErrmsg = errbuf;
     349              : #endif
     350           87 :     if (kErrmsg)
     351              :     {
     352           87 :         snprintf(appendbuf, sizeof(appendbuf), " (%d - %s)", err, kErrmsg);
     353           87 :         appendbuf[sizeof(appendbuf) - 1] = '\0';
     354           87 :         kAppend = appendbuf;
     355              :     }
     356           87 :     va_start(ap, fmt);
     357           87 :     rialtoLog(component, level, file, func, line, fmt, ap, kAppend);
     358           87 :     va_end(ap);
     359              : }
     360              : 
     361              : namespace firebolt::rialto::logging
     362              : {
     363           46 : RialtoLoggingStatus setLogLevels(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL logLevels)
     364              : {
     365           46 :     RialtoLoggingStatus status = RIALTO_LOGGING_STATUS_ERROR;
     366           46 :     if (component < RIALTO_COMPONENT_LAST && !g_ignoreLogLevels[component])
     367              :     {
     368           45 :         g_rialtoLogLevels[component] = logLevels;
     369           45 :         status = RIALTO_LOGGING_STATUS_OK;
     370              :     }
     371              : 
     372           46 :     return status;
     373              : }
     374              : 
     375           26 : RIALTO_DEBUG_LEVEL getLogLevels(RIALTO_COMPONENT component)
     376              : {
     377           26 :     if (component < RIALTO_COMPONENT_LAST)
     378              :     {
     379           26 :         if (g_ignoreLogLevels[component])
     380            1 :             return RIALTO_DEBUG_LEVEL_EXTERNAL;
     381              : 
     382           25 :         if (!g_rialtoLogLevels[component])
     383            0 :             g_rialtoLogLevels[component] = g_envVariableParser.getLevel(component);
     384           25 :         return g_rialtoLogLevels[component];
     385              :     }
     386            0 :     return RIALTO_DEBUG_LEVEL_DEFAULT;
     387              : }
     388              : 
     389           63 : RialtoLoggingStatus setLogHandler(RIALTO_COMPONENT component, LogHandler handler, bool ignoreLogLevels)
     390              : {
     391           63 :     RialtoLoggingStatus status = RIALTO_LOGGING_STATUS_ERROR;
     392           63 :     if (component < RIALTO_COMPONENT_LAST)
     393              :     {
     394           62 :         std::unique_lock<std::mutex> lock{g_logHandlerMutex};
     395              : 
     396           62 :         g_logHandler[component] = std::move(handler);
     397              : 
     398              :         // Ignoring log levels is only an option if we're registering
     399              :         // a non-null log handler
     400           62 :         g_ignoreLogLevels[component] = (g_logHandler[component]) ? ignoreLogLevels : false;
     401              : 
     402           62 :         status = RIALTO_LOGGING_STATUS_OK;
     403              :     }
     404              : 
     405           63 :     return status;
     406           42 : }
     407              : 
     408            3 : bool isConsoleLoggingEnabled()
     409              : {
     410            3 :     return g_envVariableParser.isConsoleLoggingEnabled();
     411              : }
     412              : 
     413              : } // namespace firebolt::rialto::logging
        

Generated by: LCOV version 2.0-1