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-03-21 11:02:39 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 <syslog.h>
      29              : #include <unistd.h>
      30              : 
      31              : #include "EnvVariableParser.h"
      32              : #include "LogFileHandle.h"
      33              : #include "RialtoLogging.h"
      34              : 
      35              : namespace
      36              : {
      37              : /**
      38              :  * Log levels for each component. By default will print all fatals, errors, warnings & milestones.
      39              :  */
      40              : std::atomic<RIALTO_DEBUG_LEVEL> g_rialtoLogLevels[RIALTO_COMPONENT_LAST] = {};
      41              : 
      42              : /**
      43              :  * Default Log levels defined by RIALTO_DEBUG environment variable
      44              :  */
      45              : const firebolt::rialto::logging::EnvVariableParser g_envVariableParser;
      46              : 
      47              : /**
      48              :  * Log handler for each component. By default will use journaldLogHandler.
      49              :  */
      50              : void fdLogHandler(int fd, RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
      51              :                   const char *function, const char *message, size_t messageLen);
      52              : void journaldLogHandler(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
      53              :                         const char *function, const char *message, size_t messageLen);
      54              : 
      55              : firebolt::rialto::logging::LogHandler g_logHandler[RIALTO_COMPONENT_LAST] = {};
      56              : bool g_ignoreLogLevels[RIALTO_COMPONENT_LAST] = {};
      57              : std::mutex g_logHandlerMutex;
      58              : 
      59              : std::string componentToString(RIALTO_COMPONENT component);
      60              : std::string levelToString(RIALTO_DEBUG_LEVEL level);
      61              : 
      62         8953 : std::string componentToString(RIALTO_COMPONENT component)
      63              : {
      64         8953 :     switch (component)
      65              :     {
      66            7 :     case RIALTO_COMPONENT_DEFAULT:
      67           14 :         return "DEF";
      68              :         break;
      69         2882 :     case RIALTO_COMPONENT_CLIENT:
      70         5764 :         return "CLI";
      71              :         break;
      72         5455 :     case RIALTO_COMPONENT_SERVER:
      73        10910 :         return "SRV";
      74              :         break;
      75          153 :     case RIALTO_COMPONENT_IPC:
      76          306 :         return "IPC";
      77              :         break;
      78          387 :     case RIALTO_COMPONENT_SERVER_MANAGER:
      79          774 :         return "SMG";
      80              :         break;
      81           69 :     case RIALTO_COMPONENT_COMMON:
      82          138 :         return "COM";
      83              :         break;
      84            0 :     case RIALTO_COMPONENT_EXTERNAL:
      85            0 :         return "EXT";
      86              :         break;
      87            0 :     default:
      88            0 :         return "UNK";
      89              :         break;
      90              :     }
      91              : }
      92              : 
      93         8953 : std::string levelToString(RIALTO_DEBUG_LEVEL level)
      94              : {
      95         8953 :     switch (level)
      96              :     {
      97            2 :     case RIALTO_DEBUG_LEVEL_FATAL:
      98            4 :         return "FTL";
      99              :         break;
     100          946 :     case RIALTO_DEBUG_LEVEL_ERROR:
     101         1892 :         return "ERR";
     102              :         break;
     103          324 :     case RIALTO_DEBUG_LEVEL_WARNING:
     104          648 :         return "WRN";
     105              :         break;
     106          286 :     case RIALTO_DEBUG_LEVEL_MILESTONE:
     107          572 :         return "MIL";
     108              :         break;
     109         1281 :     case RIALTO_DEBUG_LEVEL_INFO:
     110         2562 :         return "NFO";
     111              :         break;
     112         6114 :     case RIALTO_DEBUG_LEVEL_DEBUG:
     113        12228 :         return "DBG";
     114              :         break;
     115            0 :     case RIALTO_DEBUG_LEVEL_EXTERNAL:
     116            0 :         return "EXT";
     117              :         break;
     118            0 :     default:
     119            0 :         return ":";
     120              :         break;
     121              :     }
     122              : }
     123              : 
     124              : /**
     125              :  * File descriptor logging function for the library.
     126              :  */
     127         8953 : void fdLogHandler(int fd, RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
     128              :                   const char *function, const char *message, size_t messageLen)
     129              : {
     130         8953 :     timespec ts = {0, 0};
     131         8953 :     clock_gettime(CLOCK_MONOTONIC, &ts);
     132              :     struct iovec iov[6];
     133              :     char tbuf[32];
     134              : 
     135         8953 :     iov[0].iov_base = tbuf;
     136         8953 :     iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "%.010lu.%.06lu ", ts.tv_sec, ts.tv_nsec / 1000);
     137         8953 :     iov[0].iov_len = std::min(iov[0].iov_len, sizeof(tbuf));
     138              : 
     139              :     char lbuf[8];
     140         8953 :     iov[1].iov_base = reinterpret_cast<void *>(lbuf);
     141         8953 :     iov[1].iov_len =
     142         8953 :         std::min(static_cast<size_t>(snprintf(lbuf, sizeof(lbuf), "%s: ", levelToString(level).c_str())), sizeof(lbuf));
     143              : 
     144              :     char cbuf[8];
     145         8953 :     iov[2].iov_base = reinterpret_cast<void *>(cbuf);
     146         8953 :     iov[2].iov_len =
     147         8953 :         std::min(static_cast<size_t>(snprintf(cbuf, sizeof(cbuf), "%s: ", componentToString(component).c_str())),
     148         8953 :                  sizeof(cbuf));
     149              : 
     150              :     static thread_local pid_t threadId = 0;
     151         8953 :     if (threadId <= 0)
     152           81 :         threadId = syscall(SYS_gettid);
     153              :     char fbuf[180];
     154         8953 :     iov[3].iov_base = reinterpret_cast<void *>(fbuf);
     155              : 
     156         8953 :     if (RIALTO_DEBUG_LEVEL_EXTERNAL == level)
     157              :     {
     158            0 :         iov[3].iov_len = snprintf(fbuf, sizeof(fbuf), "< T:%d >", threadId);
     159              :     }
     160         8953 :     else if (!file || !function || (line <= 0))
     161              :     {
     162            0 :         iov[3].iov_len = snprintf(fbuf, sizeof(fbuf), "< T:%d M:? F:? L:? > ", threadId);
     163              :     }
     164              :     else
     165              :     {
     166         8953 :         iov[3].iov_len =
     167         8953 :             snprintf(fbuf, sizeof(fbuf), "< T:%d M:%.*s F:%.*s L:%d > ", threadId, 64, file, 64, function, line);
     168              :     }
     169         8953 :     iov[3].iov_len = std::min(iov[3].iov_len, sizeof(fbuf));
     170         8953 :     iov[4].iov_base = const_cast<void *>(reinterpret_cast<const void *>(message));
     171         8953 :     iov[4].iov_len = messageLen;
     172         8953 :     iov[5].iov_base = const_cast<void *>(reinterpret_cast<const void *>("\n"));
     173         8953 :     iov[5].iov_len = 1;
     174              :     // TODO(RIALTO-38): consider using standard write(2) and handle EINTR properly.
     175         8953 :     std::ignore = writev(fd, iov, 6);
     176              : }
     177              : /**
     178              :  * Journald logging function for the library.
     179              :  */
     180            0 : void journaldLogHandler(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, int line,
     181              :                         const char *function, const char *message, size_t messageLen)
     182              : {
     183              :     static thread_local pid_t threadId = 0;
     184            0 :     if (threadId <= 0)
     185            0 :         threadId = syscall(SYS_gettid);
     186              :     char fbuf[180];
     187            0 :     if (RIALTO_DEBUG_LEVEL_EXTERNAL == level)
     188              :     {
     189            0 :         snprintf(fbuf, sizeof(fbuf), "%s: %s: < T:%d >", levelToString(level).c_str(),
     190            0 :                  componentToString(component).c_str(), threadId);
     191              :     }
     192            0 :     else if (!file || !function || (line <= 0))
     193              :     {
     194            0 :         snprintf(fbuf, sizeof(fbuf), "%s: %s: < T:%d M:? F:? L:? >", levelToString(level).c_str(),
     195            0 :                  componentToString(component).c_str(), threadId);
     196              :     }
     197              :     else
     198              :     {
     199            0 :         snprintf(fbuf, sizeof(fbuf), "%s: %s: < T:%d M:%.*s F:%.*s L:%d >", levelToString(level).c_str(),
     200            0 :                  componentToString(component).c_str(), threadId, 64, file, 64, function, line);
     201              :     }
     202              : 
     203            0 :     switch (level)
     204              :     {
     205            0 :     case RIALTO_DEBUG_LEVEL_FATAL:
     206            0 :         syslog(LOG_CRIT, "%s %s", fbuf, message);
     207            0 :         break;
     208            0 :     case RIALTO_DEBUG_LEVEL_ERROR:
     209            0 :         syslog(LOG_ERR, "%s %s", fbuf, message);
     210            0 :         break;
     211            0 :     case RIALTO_DEBUG_LEVEL_WARNING:
     212            0 :         syslog(LOG_WARNING, "%s %s", fbuf, message);
     213            0 :         break;
     214            0 :     case RIALTO_DEBUG_LEVEL_MILESTONE:
     215            0 :         syslog(LOG_NOTICE, "%s %s", fbuf, message);
     216            0 :         break;
     217            0 :     case RIALTO_DEBUG_LEVEL_INFO:
     218            0 :         syslog(LOG_INFO, "%s %s", fbuf, message);
     219            0 :         break;
     220            0 :     case RIALTO_DEBUG_LEVEL_DEBUG:
     221            0 :         syslog(LOG_DEBUG, "%s %s", fbuf, message);
     222            0 :         break;
     223            0 :     case RIALTO_DEBUG_LEVEL_EXTERNAL:
     224            0 :         syslog(LOG_INFO, "%s %s", fbuf, message);
     225            0 :         break;
     226            0 :     default:
     227            0 :         break;
     228              :     }
     229              : }
     230              : 
     231         9463 : void rialtoLog(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, const char *func, int line,
     232              :                const char *fmt, va_list ap, const char *append)
     233              : {
     234              :     /* Must be valid component */
     235         9463 :     if (component >= RIALTO_COMPONENT_LAST)
     236          451 :         return;
     237              : 
     238              :     /* If log levels have not been set, set to Default */
     239         9463 :     if (!g_rialtoLogLevels[component])
     240           15 :         g_rialtoLogLevels[component] = g_envVariableParser.getLevel(component);
     241              : 
     242         9463 :     if (!(level & g_rialtoLogLevels[component]) && !g_ignoreLogLevels[component])
     243          451 :         return;
     244              :     char mbuf[512];
     245              :     int len;
     246         9012 :     len = vsnprintf(mbuf, sizeof(mbuf), fmt, ap);
     247         9012 :     if (len < 1)
     248            0 :         return;
     249         9012 :     if (len > static_cast<int>(sizeof(mbuf) - 1))
     250            0 :         len = sizeof(mbuf) - 1;
     251         9012 :     if (mbuf[len - 1] == '\n')
     252            5 :         len--;
     253         9012 :     mbuf[len] = '\0';
     254         9012 :     if (append && (len < static_cast<int>(sizeof(mbuf) - 1)))
     255              :     {
     256           49 :         size_t extra = std::min<size_t>(strlen(append), (sizeof(mbuf) - len - 1));
     257           49 :         memcpy(mbuf + len, append, extra);
     258           49 :         len += static_cast<int>(extra);
     259           49 :         mbuf[len] = '\0';
     260              :     }
     261         9012 :     const char *kFname = nullptr;
     262         9012 :     if (file)
     263              :     {
     264         9012 :         if ((kFname = strrchr(file, '/')) == nullptr)
     265            0 :             kFname = file;
     266              :         else
     267         9012 :             kFname++;
     268              :     }
     269              : 
     270         9012 :     const auto &kLogFileHandle = firebolt::rialto::logging::LogFileHandle::instance();
     271              :     /* If log handler had not been set, use default */
     272         9012 :     firebolt::rialto::logging::LogHandler logHandler = g_logHandler[component]; // local copy for thread safety
     273         9012 :     if (logHandler)
     274              :     {
     275           59 :         logHandler(level, kFname, line, func, mbuf, len);
     276              :     }
     277         8953 :     else if (g_envVariableParser.isFileLoggingEnabled() && kLogFileHandle.isOpen())
     278              :     {
     279            0 :         fdLogHandler(kLogFileHandle.fd(), component, level, kFname, line, func, mbuf, len);
     280              :     }
     281         8953 :     else if (g_envVariableParser.isConsoleLoggingEnabled())
     282              :     {
     283         8953 :         fdLogHandler(STDERR_FILENO, component, level, kFname, line, func, mbuf, len);
     284              :     }
     285              :     else
     286              :     {
     287            0 :         journaldLogHandler(component, level, kFname, line, func, mbuf, len);
     288              :     }
     289         9012 : }
     290              : 
     291              : } // namespace
     292              : 
     293            0 : void rialtoLogVPrintf(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, const char *func,
     294              :                       int line, const char *fmt, va_list ap)
     295              : {
     296            0 :     rialtoLog(component, level, file, func, line, fmt, ap, nullptr);
     297              : }
     298              : 
     299         9376 : void rialtoLogPrintf(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL level, const char *file, const char *func, int line,
     300              :                      const char *fmt, ...)
     301              : {
     302              :     va_list ap;
     303         9376 :     va_start(ap, fmt);
     304         9376 :     rialtoLog(component, level, file, func, line, fmt, ap, nullptr);
     305         9376 :     va_end(ap);
     306              : }
     307              : 
     308           87 : void rialtoLogSysPrintf(RIALTO_COMPONENT component, int err, RIALTO_DEBUG_LEVEL level, const char *file,
     309              :                         const char *func, int line, const char *fmt, ...)
     310              : {
     311              :     va_list ap;
     312           87 :     const char *kErrmsg{nullptr};
     313              :     char appendbuf[96];
     314           87 :     const char *kAppend = nullptr;
     315              : #if defined(__linux__)
     316              :     char errbuf[64];
     317           87 :     kErrmsg = strerror_r(err, errbuf, sizeof(errbuf));
     318              : #elif defined(__APPLE__)
     319              :     char errbuf[64];
     320              :     if (strerror_r(err, errbuf, sizeof(errbuf)) != 0)
     321              :         kErrmsg = "Unknown error";
     322              :     else
     323              :         kErrmsg = errbuf;
     324              : #endif
     325           87 :     if (kErrmsg)
     326              :     {
     327           87 :         snprintf(appendbuf, sizeof(appendbuf), " (%d - %s)", err, kErrmsg);
     328           87 :         appendbuf[sizeof(appendbuf) - 1] = '\0';
     329           87 :         kAppend = appendbuf;
     330              :     }
     331           87 :     va_start(ap, fmt);
     332           87 :     rialtoLog(component, level, file, func, line, fmt, ap, kAppend);
     333           87 :     va_end(ap);
     334              : }
     335              : 
     336              : namespace firebolt::rialto::logging
     337              : {
     338           46 : RialtoLoggingStatus setLogLevels(RIALTO_COMPONENT component, RIALTO_DEBUG_LEVEL logLevels)
     339              : {
     340           46 :     RialtoLoggingStatus status = RIALTO_LOGGING_STATUS_ERROR;
     341           46 :     if (component < RIALTO_COMPONENT_LAST && !g_ignoreLogLevels[component])
     342              :     {
     343           45 :         g_rialtoLogLevels[component] = logLevels;
     344           45 :         status = RIALTO_LOGGING_STATUS_OK;
     345              :     }
     346              : 
     347           46 :     return status;
     348              : }
     349              : 
     350           26 : RIALTO_DEBUG_LEVEL getLogLevels(RIALTO_COMPONENT component)
     351              : {
     352           26 :     if (component < RIALTO_COMPONENT_LAST)
     353              :     {
     354           26 :         if (g_ignoreLogLevels[component])
     355            1 :             return RIALTO_DEBUG_LEVEL_EXTERNAL;
     356              : 
     357           25 :         if (!g_rialtoLogLevels[component])
     358            0 :             g_rialtoLogLevels[component] = g_envVariableParser.getLevel(component);
     359           25 :         return g_rialtoLogLevels[component];
     360              :     }
     361            0 :     return RIALTO_DEBUG_LEVEL_DEFAULT;
     362              : }
     363              : 
     364           63 : RialtoLoggingStatus setLogHandler(RIALTO_COMPONENT component, LogHandler handler, bool ignoreLogLevels)
     365              : {
     366           63 :     RialtoLoggingStatus status = RIALTO_LOGGING_STATUS_ERROR;
     367           63 :     if (component < RIALTO_COMPONENT_LAST)
     368              :     {
     369           62 :         std::unique_lock<std::mutex> lock{g_logHandlerMutex};
     370              : 
     371           62 :         g_logHandler[component] = std::move(handler);
     372              : 
     373              :         // Ignoring log levels is only an option if we're registering
     374              :         // a non-null log handler
     375           62 :         g_ignoreLogLevels[component] = (g_logHandler[component]) ? ignoreLogLevels : false;
     376              : 
     377           62 :         status = RIALTO_LOGGING_STATUS_OK;
     378              :     }
     379              : 
     380           63 :     return status;
     381           42 : }
     382              : 
     383            3 : bool isConsoleLoggingEnabled()
     384              : {
     385            3 :     return g_envVariableParser.isConsoleLoggingEnabled();
     386              : }
     387              : 
     388              : } // namespace firebolt::rialto::logging
        

Generated by: LCOV version 2.0-1