LCOV - code coverage report
Current view: top level - include/client - logging.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 136 83.8 %
Date: 2024-04-23 00:09:24 Functions: 126 209 60.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
       3             :   Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany
       4             : 
       5             :   This software was partially supported by the
       6             :   EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
       7             : 
       8             :   This software was partially supported by the
       9             :   ADA-FS project under the SPPEXA project funded by the DFG.
      10             : 
      11             :   This file is part of GekkoFS' POSIX interface.
      12             : 
      13             :   GekkoFS' POSIX interface is free software: you can redistribute it and/or
      14             :   modify it under the terms of the GNU Lesser General Public License as
      15             :   published by the Free Software Foundation, either version 3 of the License,
      16             :   or (at your option) any later version.
      17             : 
      18             :   GekkoFS' POSIX interface is distributed in the hope that it will be useful,
      19             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      20             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21             :   GNU Lesser General Public License for more details.
      22             : 
      23             :   You should have received a copy of the GNU Lesser General Public License
      24             :   along with GekkoFS' POSIX interface.  If not, see
      25             :   <https://www.gnu.org/licenses/>.
      26             : 
      27             :   SPDX-License-Identifier: LGPL-3.0-or-later
      28             : */
      29             : 
      30             : #ifndef LIBGKFS_LOGGING_HPP
      31             : #define LIBGKFS_LOGGING_HPP
      32             : 
      33             : #ifndef BYPASS_SYSCALL
      34             : #include <libsyscall_intercept_hook_point.h>
      35             : #else
      36             : #include <client/void_syscall_intercept.hpp>
      37             : #endif
      38             : 
      39             : #include <type_traits>
      40             : #include <client/make_array.hpp>
      41             : #include <client/syscalls.hpp>
      42             : #include <optional>
      43             : #include <fmt/format.h>
      44             : #include <fmt/ostream.h>
      45             : #include <hermes.hpp>
      46             : 
      47             : #ifdef GKFS_DEBUG_BUILD
      48             : #include <bitset>
      49             : #endif
      50             : 
      51             : namespace gkfs::log {
      52             : 
      53             : enum class log_level : unsigned int {
      54             :     print_syscalls = 1 << 0,
      55             :     print_syscalls_entry = 1 << 1,
      56             :     print_info = 1 << 2,
      57             :     print_critical = 1 << 3,
      58             :     print_errors = 1 << 4,
      59             :     print_warnings = 1 << 5,
      60             :     print_hermes = 1 << 6,
      61             :     print_mercury = 1 << 7,
      62             :     print_debug = 1 << 8,
      63             :     print_trace_reads = 1 << 9,
      64             : 
      65             :     // for internal use
      66             :     print_none = 0,
      67             :     print_all = print_syscalls | print_syscalls_entry | print_info |
      68             :                 print_critical | print_errors | print_warnings | print_hermes |
      69             :                 print_mercury | print_debug,
      70             :     print_most = print_all & ~print_syscalls_entry,
      71             :     print_help = 1 << 10
      72             : };
      73             : 
      74             : inline constexpr log_level
      75    30044199 : operator&(log_level l1, log_level l2) {
      76    30044199 :     return log_level(static_cast<short>(l1) & static_cast<short>(l2));
      77             : }
      78             : 
      79             : inline constexpr log_level
      80         269 : operator|(log_level l1, log_level l2) {
      81         269 :     return log_level(static_cast<short>(l1) | static_cast<short>(l2));
      82             : }
      83             : 
      84             : inline constexpr log_level
      85             : operator^(log_level l1, log_level l2) {
      86             :     return log_level(static_cast<short>(l1) ^ static_cast<short>(l2));
      87             : }
      88             : 
      89             : inline constexpr log_level
      90             : operator~(log_level l1) {
      91             :     return log_level(~static_cast<short>(l1));
      92             : }
      93             : 
      94             : inline constexpr bool
      95    30044199 : operator!(log_level dm) {
      96    30005311 :     return static_cast<short>(dm) == 0;
      97             : }
      98             : 
      99             : inline const log_level&
     100         269 : operator|=(log_level& l1, log_level l2) {
     101         269 :     return l1 = l1 | l2;
     102             : }
     103             : 
     104             : inline const log_level&
     105             : operator&=(log_level& l1, log_level l2) {
     106             :     return l1 = l1 & l2;
     107             : }
     108             : 
     109             : inline const log_level&
     110             : operator^=(log_level& l1, log_level l2) {
     111             :     return l1 = l1 ^ l2;
     112             : }
     113             : 
     114             : 
     115             : static const auto constexpr syscall = log_level::print_syscalls;
     116             : static const auto constexpr syscall_at_entry = log_level::print_syscalls_entry;
     117             : static const auto constexpr info = log_level::print_info;
     118             : static const auto constexpr critical = log_level::print_critical;
     119             : static const auto constexpr error = log_level::print_errors;
     120             : static const auto constexpr warning = log_level::print_warnings;
     121             : static const auto constexpr hermes = log_level::print_hermes;
     122             : static const auto constexpr mercury = log_level::print_mercury;
     123             : static const auto constexpr debug = log_level::print_debug;
     124             : static const auto constexpr trace_reads = log_level::print_trace_reads;
     125             : static const auto constexpr none = log_level::print_none;
     126             : static const auto constexpr most = log_level::print_most;
     127             : static const auto constexpr all = log_level::print_all;
     128             : static const auto constexpr help = log_level::print_help;
     129             : 
     130             : static const auto constexpr level_names = utils::make_array(
     131             :         "syscall",
     132             :         "syscall", // sycall_entry uses the same name as syscall
     133             :         "info", "critical", "error", "warning", "hermes", "mercury", "debug",
     134             :         "trace_reads");
     135             : 
     136             : inline constexpr auto
     137      480058 : lookup_level_name(log_level l) {
     138             : 
     139      480058 :     assert(l != log::none && l != log::help);
     140             : 
     141             :     // since all log levels are powers of 2, we can find a name
     142             :     // very efficiently by counting the number of trailing 0-bits in l
     143      480058 :     const auto i = __builtin_ctz(static_cast<short>(l));
     144      480058 :     assert(i >= 0 && static_cast<std::size_t>(i) < level_names.size());
     145             : 
     146      480058 :     return level_names.at(i);
     147             : }
     148             : 
     149             : 
     150             : // forward declaration
     151             : struct logger;
     152             : 
     153             : namespace detail {
     154             : 
     155             : template <typename Buffer>
     156             : static inline void
     157             : log_buffer(std::FILE* fp, Buffer&& buffer) {
     158             :     log_buffer(::fileno(fp), std::forward<Buffer>(buffer));
     159             : }
     160             : 
     161             : template <typename Buffer>
     162             : static inline void
     163      480058 : log_buffer(int fd, Buffer&& buffer) {
     164             : 
     165      480058 :     if(fd < 0) {
     166           0 :         throw std::runtime_error("Invalid file descriptor");
     167             :     }
     168             : 
     169      480058 :     ::syscall_no_intercept(SYS_write, fd, buffer.data(), buffer.size());
     170      480059 : }
     171             : 
     172             : static inline void
     173             : log_buffer(int fd, const void* buffer, std::size_t length) {
     174             :     if(fd < 0) {
     175             :         throw std::runtime_error("Invalid file descriptor");
     176             :     }
     177             : 
     178             :     ::syscall_no_intercept(SYS_write, fd, buffer, length);
     179             : }
     180             : 
     181             : /**
     182             :  * @brief convert a time_t to a tm
     183             :  * It is not POSIX compliant, but it dows not uses any syscall or timezone
     184             :  * Converts a Unix timestamp (number of seconds since the beginning of 1970
     185             :  * CE) to a Gregorian civil date-time tuple in GMT (UTC) time zone.
     186             :  *
     187             :  * This conforms to C89 (and C99...) and POSIX.
     188             :  *
     189             :  * This implementation works, and doesn't overflow for any sizeof(time_t).
     190             :  * It doesn't check for overflow/underflow in tm->tm_year output. Other than
     191             :  * that, it never overflows or underflows. It assumes that that time_t is
     192             :  * signed.
     193             :  *
     194             :  * This implements the inverse of the POSIX formula
     195             :  * (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15)
     196             :  * for all time_t values, no matter the size, as long as tm->tm_year doesn't
     197             :  * overflow or underflow. The formula is: tm_sec + tm_min*60 + tm_hour*3600
     198             :  * + tm_yday*86400 + (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
     199             :  * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400.
     200             :  *
     201             :  * License : GNU General Public License v2.0 from
     202             :  * https://github.com/pts/minilibc686/
     203             :  * @param time_t
     204             :  * @return tm
     205             :  */
     206             : 
     207             : static inline struct tm*
     208     1751132 : mini_gmtime_r(const time_t* timep, struct tm* tm) {
     209     1751132 :     const time_t ts = *timep;
     210     1751132 :     time_t t = ts / 86400;
     211     1751132 :     unsigned hms =
     212     1751132 :             ts %
     213             :             86400; /* -86399 <= hms <= 86399. This needs sizeof(int) >= 4. */
     214     1751132 :     time_t c, f;
     215     1751132 :     unsigned yday; /* 0 <= yday <= 426. Also fits to an `unsigned short', but
     216             :                       `int' is faster. */
     217     1751132 :     unsigned a; /* 0 <= a <= 2133. Also fits to an `unsigned short', but `int'
     218             :                    is faster. */
     219     1751132 :     if((int) hms < 0) {
     220           0 :         --t;
     221           0 :         hms += 86400;
     222             :     } /* Fix quotient and negative remainder if ts was negative (i.e. before
     223             :          year 1970 CE). */
     224             :     /* Now: -24856 <= t <= 24855. */
     225     1751132 :     tm->tm_sec = hms % 60;
     226     1751132 :     hms /= 60;
     227     1751132 :     tm->tm_min = hms % 60;
     228     1751132 :     tm->tm_hour = hms / 60;
     229     1751132 :     if(sizeof(time_t) >
     230             :        4) { /* Optimization. For int32_t, this would keep t intact, so we won't
     231             :                have to do it. This produces unreachable code. */
     232     1751132 :         f = (t + 4) % 7;
     233     1751132 :         if(f < 0)
     234           0 :             f += 7; /* Fix negative remainder if (t + 4) was negative. */
     235             :         /* Now 0 <= f <= 6. */
     236     1751132 :         tm->tm_wday = f;
     237     1751132 :         c = (t << 2) + 102032;
     238     1751132 :         f = c / 146097;
     239     1751132 :         if(c % 146097 < 0)
     240           0 :             --f; /* Fix negative remainder if c was negative. */
     241     1751132 :         --f;
     242     1751132 :         t += f;
     243     1751132 :         f >>= 2;
     244     1751132 :         t -= f;
     245     1751132 :         f = (t << 2) + 102035;
     246     1751132 :         c = f / 1461;
     247     1751132 :         if(f % 1461 < 0)
     248           0 :             --c; /* Fix negative remainder if f was negative. */
     249             :     } else {
     250             :         tm->tm_wday = (t + 24861) % 7; /* t + 24861 >= 0. */
     251             :         /* Now: -24856 <= t <= 24855. */
     252             :         c = ((t << 2) + 102035) / 1461;
     253             :     }
     254     1751132 :     yday = t - 365 * c - (c >> 2) + 25568;
     255             :     /* Now: 0 <= yday <= 425. */
     256     1751132 :     a = yday * 5 + 8;
     257             :     /* Now: 8 <= a <= 2133. */
     258     1751132 :     tm->tm_mon = a / 153;
     259     1751132 :     a %= 153; /* No need to fix if a < 0, because a cannot be negative here. */
     260             :     /* Now: 2 <= tm->tm_mon <= 13. */
     261             :     /* Now: 0 <= a <= 152. */
     262     1751132 :     tm->tm_mday = 1 + a / 5; /* No need to fix if a < 0, because a cannot be
     263             :                                 negative here. */
     264             :     /* Now: 1 <= tm->tm_mday <= 31. */
     265     1751132 :     if(tm->tm_mon >= 12) {
     266           0 :         tm->tm_mon -= 12;
     267             :         /* Now: 0 <= tm->tm_mon <= 1. */
     268           0 :         ++c;
     269           0 :         yday -= 366;
     270             :     } else { /* Check for leap year (in c). */
     271             :         /* Now: 2 <= tm->tm_mon <= 11. */
     272             :         /* 1903: not leap; 1904: leap, 1900: not leap; 2000: leap */
     273             :         /* With sizeof(time_t) == 4, we have 1901 <= year <= 2038; of these
     274             :          * years only 2000 is divisble by 100, and that's a leap year, no we
     275             :          * optimize the check to `(c & 3) == 0' only.
     276             :          */
     277     1751132 :         if(!((c & 3) == 0 &&
     278     1751132 :              (sizeof(time_t) <= 4 || c % 100 != 0 || (c + 300) % 400 == 0)))
     279           0 :             --yday; /* These `== 0' comparisons work even if c < 0. */
     280             :     }
     281     1751132 :     tm->tm_year =
     282             :             c; /* This assignment may overflow or underflow, we don't check it.
     283             :                   Example: time_t is a huge int64_t, tm->tm_year is int32_t. */
     284             :     /* Now: 0 <= tm->tm_mon <= 11. */
     285             :     /* Now: 0 <= yday <= 365. */
     286     1751132 :     tm->tm_yday = yday;
     287     1751132 :     tm->tm_isdst = 0;
     288     1751132 :     return tm;
     289             : }
     290             : 
     291             : static inline struct tm*
     292     1751211 : mini_gmtime(const time_t* timep) {
     293     1751211 :     static struct tm tm;
     294     1751211 :     return mini_gmtime_r(timep, &tm);
     295             : }
     296             : 
     297             : static inline ssize_t
     298     1751211 : format_timeval(struct timeval* tv, char* buf, size_t sz) {
     299     1751211 :     ssize_t written = -1;
     300     1751211 :     struct tm* gm = mini_gmtime(&tv->tv_sec);
     301             : 
     302             : 
     303     1751057 :     written = (ssize_t) strftime(buf, sz, "%Y-%m-%d %H:%M:%S", gm);
     304     1751057 :     if((written > 0) && ((size_t) written < sz)) {
     305     1751230 :         int w = snprintf(buf + written, sz - (size_t) written, ".%06ld",
     306             :                          tv->tv_usec);
     307     1751230 :         written = (w > 0) ? written + w : -1;
     308             :     }
     309             : 
     310     1751057 :     return written;
     311             : }
     312             : 
     313             : /**
     314             :  * format_timestamp_to - safely format a timestamp for logging messages
     315             :  *
     316             :  * This function produes a timestamp that can be used to prefix logging
     317             :  * messages. Since we are actively intercepting system calls, the formatting
     318             :  * MUST NOT rely on internal system calls, otherwise we risk recursively
     319             :  * calling ourselves for each syscall generated. Also, we cannot rely on
     320             :  * the C formatting functions asctime, ctime, gmtime, localtime, mktime,
     321             :  * asctime_r, ctime_r, gmtime_r, localtime_r, since they acquire a
     322             :  * non-reentrant lock to determine the caller's timezone (yes, the assumedly
     323             :  * reentrant *_r versions of the functions exhibit this problem as well,
     324             :  * see https://sourceware.org/bugzilla/show_bug.cgi?id=16145). To solve this
     325             :  * issue and still get readable timestamps, we determine and cache the
     326             :  * timezone when the logger is created so that the lock is only held once, by
     327             :  * one thread exactly, and we pass it as an argument whenever we need to
     328             :  * format a timestamp. If no timezone is provided, we just format the epoch.
     329             :  *
     330             :  */
     331             : template <typename Buffer>
     332             : static inline void
     333     1751080 : format_timestamp_to(Buffer&& buffer) {
     334             : 
     335             :     struct ::timeval tv;
     336             : 
     337     1751080 :     int rv = ::syscall_no_intercept(SYS_gettimeofday, &tv, NULL);
     338             : 
     339     1751241 :     if(::syscall_error_code(rv) != 0) {
     340           0 :         return;
     341             :     }
     342             : 
     343             :     char buf[28];
     344             : 
     345     1751241 :     if(format_timeval(&tv, buf, sizeof(buf)) > 0) {
     346     1751231 :         fmt::format_to(std::back_inserter(buffer), "[{}] ", buf);
     347             :     }
     348             : }
     349             : 
     350             : template <typename Buffer>
     351             : static inline void
     352     1271135 : format_syscall_info_to(Buffer&& buffer, gkfs::syscall::info info) {
     353             : 
     354     1271135 :     const auto ttid = syscall_no_intercept(SYS_gettid);
     355     1271220 :     fmt::format_to(std::back_inserter(buffer), "[{}] [syscall] ", ttid);
     356             : 
     357             :     char o;
     358             :     char t;
     359             : 
     360     1271160 :     switch(gkfs::syscall::origin(info)) {
     361             :         case gkfs::syscall::from_internal_code:
     362             :             o = 'i';
     363             :             break;
     364      898062 :         case gkfs::syscall::from_external_code:
     365      898062 :             o = 'a';
     366      898062 :             break;
     367        1097 :         default:
     368        1097 :             o = '?';
     369        1097 :             break;
     370             :     }
     371             : 
     372     1271160 :     switch(gkfs::syscall::target(info)) {
     373             :         case gkfs::syscall::to_hook:
     374             :             t = 'h';
     375             :             break;
     376      205295 :         case gkfs::syscall::to_kernel:
     377      205295 :             t = 'k';
     378      205295 :             break;
     379        1097 :         default:
     380        1097 :             t = '?';
     381        1097 :             break;
     382             :     }
     383             : 
     384     1271160 :     const std::array<char, 5> tmp = {'[', o, t, ']', ' '};
     385     1271160 :     fmt::format_to(std::back_inserter(buffer),
     386     1271160 :                    fmt::string_view(tmp.data(), tmp.size()));
     387     1271133 : }
     388             : 
     389             : } // namespace detail
     390             : 
     391             : enum { max_buffer_size = LIBGKFS_LOG_MESSAGE_SIZE };
     392             : 
     393             : using static_buffer = fmt::basic_memory_buffer<char, max_buffer_size>;
     394             : 
     395             : struct logger {
     396             : 
     397             :     logger(const std::string& opts, const std::string& path,
     398             :            bool log_per_process, bool trunc
     399             : #ifdef GKFS_DEBUG_BUILD
     400             :            ,
     401             :            const std::string& filter, int verbosity
     402             : #endif
     403             :     );
     404             : 
     405             :     ~logger();
     406             : 
     407             :     template <typename... Args>
     408             :     inline void
     409      480091 :     log(log_level level, const char* const func, const int lineno,
     410             :         Args&&... args) {
     411             : 
     412      480091 :         if(!(level & log_mask_)) {
     413          32 :             return;
     414             :         }
     415             : 
     416      960118 :         static_buffer buffer;
     417      480059 :         detail::format_timestamp_to(buffer);
     418      480058 :         fmt::format_to(std::back_inserter(buffer), "[{}] [{}] ",
     419      480058 :                        log_process_id_, lookup_level_name(level));
     420             : 
     421      480058 :         if(!!(level & log::debug)) {
     422      457546 :             fmt::format_to(std::back_inserter(buffer), "<{}():{}> ", func,
     423             :                            lineno);
     424             :         }
     425             : 
     426      480602 :         fmt::format_to(std::back_inserter(buffer), std::forward<Args>(args)...);
     427      480058 :         fmt::format_to(std::back_inserter(buffer), "\n");
     428      480058 :         detail::log_buffer(log_fd_, buffer);
     429             :     }
     430             : 
     431             :     inline int
     432             :     log(log_level level, const char* fmt, va_list ap) {
     433             : 
     434             :         if(!(level & log_mask_)) {
     435             :             return 0;
     436             :         }
     437             : 
     438             :         // we use buffer views to compose the logging messages to
     439             :         // avoid copying buffers as much as possible
     440             :         struct buffer_view {
     441             :             const void* addr;
     442             :             std::size_t size;
     443             :         };
     444             : 
     445             :         // helper lambda to print an iterable of buffer_views
     446             :         const auto log_buffer_views = [this](const auto& buffers) {
     447             :             std::size_t n = 0;
     448             : 
     449             :             for(const auto& bv : buffers) {
     450             :                 if(bv.addr != nullptr) {
     451             :                     detail::log_buffer(log_fd_, bv.addr, bv.size);
     452             :                     n += bv.size;
     453             :                 }
     454             :             }
     455             : 
     456             :             return n;
     457             :         };
     458             : 
     459             : 
     460             :         static_buffer prefix;
     461             :         detail::format_timestamp_to(prefix);
     462             :         fmt::format_to(std::back_inserter(prefix), "[{}] [{}] ",
     463             :                        log_process_id_, lookup_level_name(level));
     464             : 
     465             :         char buffer[max_buffer_size];
     466             :         const int n = vsnprintf(buffer, sizeof(buffer), fmt, ap);
     467             : 
     468             :         std::array<buffer_view, 3> buffers{};
     469             : 
     470             :         int i = 0;
     471             :         int m = 0;
     472             :         const char* addr = buffer;
     473             :         const char* p = nullptr;
     474             :         while((p = std::strstr(addr, "\n")) != nullptr) {
     475             :             buffers[0] = buffer_view{prefix.data(), prefix.size()};
     476             :             buffers[1] =
     477             :                     buffer_view{addr, static_cast<std::size_t>(p - addr) + 1};
     478             : 
     479             :             m += log_buffer_views(buffers);
     480             :             addr = p + 1;
     481             :             ++i;
     482             :         }
     483             : 
     484             :         // original line might not end with (or include) '\n'
     485             :         if(buffer[n - 1] != '\n') {
     486             :             buffers[0] = buffer_view{prefix.data(), prefix.size()};
     487             :             buffers[1] = buffer_view{
     488             :                     addr, static_cast<std::size_t>(&buffer[n] - addr)};
     489             :             buffers[2] = buffer_view{"\n", 1};
     490             : 
     491             :             m += log_buffer_views(buffers);
     492             :         }
     493             : 
     494             :         return m;
     495             :     }
     496             : 
     497             :     template <typename... Args>
     498             :     static inline void
     499           0 :     log_message(std::FILE* fp, Args&&... args) {
     500           0 :         log_message(::fileno(fp), std::forward<Args>(args)...);
     501           0 :     }
     502             : 
     503             :     template <typename... Args>
     504             :     static inline void
     505           0 :     log_message(int fd, Args&&... args) {
     506             : 
     507           0 :         if(fd < 0) {
     508           0 :             throw std::runtime_error("Invalid file descriptor");
     509             :         }
     510             : 
     511           0 :         static_buffer buffer;
     512           0 :         fmt::format_to(std::back_inserter(buffer), std::forward<Args>(args)...);
     513           0 :         fmt::format_to(std::back_inserter(buffer), "\n");
     514           0 :         detail::log_buffer(fd, buffer);
     515           0 :     }
     516             : 
     517             :     void
     518             :     log_syscall(syscall::info info, const long syscall_number,
     519             :                 const long args[6], std::optional<long> result = {});
     520             : 
     521             :     static std::shared_ptr<logger>&
     522    59097371 :     global_logger() {
     523    59097371 :         static std::shared_ptr<logger> s_global_logger;
     524    59097371 :         return s_global_logger;
     525             :     }
     526             : 
     527             :     int log_fd_;
     528             :     int log_process_id_;
     529             :     log_level log_mask_;
     530             : 
     531             : #ifdef GKFS_DEBUG_BUILD
     532             :     std::bitset<512> filtered_syscalls_;
     533             :     int debug_verbosity_;
     534             : #endif
     535             : };
     536             : 
     537             : // the following static functions can be used to interact
     538             : // with a globally registered logger instance
     539             : 
     540             : template <typename... Args>
     541             : static inline void
     542         269 : create_global_logger(Args&&... args) {
     543             : 
     544         269 :     auto foo = std::make_shared<logger>(std::forward<Args>(args)...);
     545         269 :     logger::global_logger() = foo;
     546         269 : }
     547             : 
     548             : static inline void
     549             : register_global_logger(logger&& lg) {
     550             :     logger::global_logger() = std::make_shared<logger>(std::move(lg));
     551             : }
     552             : 
     553             : static inline std::shared_ptr<logger>&
     554    59115651 : get_global_logger() {
     555    59115651 :     return logger::global_logger();
     556             : }
     557             : 
     558             : static inline void
     559             : destroy_global_logger() {
     560             :     logger::global_logger().reset();
     561             : }
     562             : 
     563             : } // namespace gkfs::log
     564             : 
     565             : #define LOG(XXX, ...) LOG_##XXX(__VA_ARGS__)
     566             : 
     567             : #ifndef GKFS_ENABLE_LOGGING
     568             : 
     569             : #define LOG_INFO(...)                                                          \
     570             :     do {                                                                       \
     571             :     } while(0);
     572             : #define LOG_WARNING(...)                                                       \
     573             :     do {                                                                       \
     574             :     } while(0);
     575             : #define LOG_ERROR(...)                                                         \
     576             :     do {                                                                       \
     577             :     } while(0);
     578             : #define LOG_CRITICAL(...)                                                      \
     579             :     do {                                                                       \
     580             :     } while(0);
     581             : #define LOG_HERMES(...)                                                        \
     582             :     do {                                                                       \
     583             :     } while(0);
     584             : #define LOG_MERCURY(...)                                                       \
     585             :     do {                                                                       \
     586             :     } while(0);
     587             : #define LOG_SYSCALL(...)                                                       \
     588             :     do {                                                                       \
     589             :     } while(0);
     590             : #define LOG_DEBUG(...)                                                         \
     591             :     do {                                                                       \
     592             :     } while(0);
     593             : #define LOG_TRACE_READS(...)                                                   \
     594             :     do {                                                                       \
     595             :     } while(0);
     596             : 
     597             : #else // !GKFS_ENABLE_LOGGING
     598             : 
     599             : #define LOG_INFO(...)                                                          \
     600             :     do {                                                                       \
     601             :         if(gkfs::log::get_global_logger()) {                                   \
     602             :             gkfs::log::get_global_logger()->log(gkfs::log::info, __func__,     \
     603             :                                                 __LINE__, __VA_ARGS__);        \
     604             :         }                                                                      \
     605             :     } while(0);
     606             : 
     607             : #define LOG_WARNING(...)                                                       \
     608             :     do {                                                                       \
     609             :         if(gkfs::log::get_global_logger()) {                                   \
     610             :             gkfs::log::get_global_logger()->log(gkfs::log::warning, __func__,  \
     611             :                                                 __LINE__, __VA_ARGS__);        \
     612             :         }                                                                      \
     613             :     } while(0);
     614             : 
     615             : #define LOG_ERROR(...)                                                         \
     616             :     do {                                                                       \
     617             :         if(gkfs::log::get_global_logger()) {                                   \
     618             :             gkfs::log::get_global_logger()->log(gkfs::log::error, __func__,    \
     619             :                                                 __LINE__, __VA_ARGS__);        \
     620             :         }                                                                      \
     621             :     } while(0);
     622             : 
     623             : #define LOG_CRITICAL(...)                                                      \
     624             :     do {                                                                       \
     625             :         if(gkfs::log::get_global_logger()) {                                   \
     626             :             gkfs::log::get_global_logger()->log(gkfs::log::critical, __func__, \
     627             :                                                 __LINE__, __VA_ARGS__);        \
     628             :         }                                                                      \
     629             :     } while(0);
     630             : 
     631             : #define LOG_HERMES(...)                                                        \
     632             :     do {                                                                       \
     633             :         if(gkfs::log::get_global_logger()) {                                   \
     634             :             gkfs::log::get_global_logger()->log(gkfs::log::hermes, __func__,   \
     635             :                                                 __LINE__, __VA_ARGS__);        \
     636             :         }                                                                      \
     637             :     } while(0);
     638             : 
     639             : #define LOG_MERCURY(...)                                                       \
     640             :     do {                                                                       \
     641             :         if(gkfs::log::get_global_logger()) {                                   \
     642             :             gkfs::log::get_global_logger()->log(gkfs::log::mercury, __func__,  \
     643             :                                                 __LINE__, __VA_ARGS__);        \
     644             :         }                                                                      \
     645             :     } while(0);
     646             : 
     647             : #define LOG_TRACE_READS(...)                                                   \
     648             :     do {                                                                       \
     649             :         if(gkfs::log::get_global_logger()) {                                   \
     650             :             gkfs::log::get_global_logger()->log(                               \
     651             :                     gkfs::log::trace_reads, __func__, __LINE__, __VA_ARGS__);  \
     652             :         }                                                                      \
     653             :     } while(0);
     654             : 
     655             : #ifdef GKFS_DEBUG_BUILD
     656             : 
     657             : #define LOG_SYSCALL(...)                                                       \
     658             :     do {                                                                       \
     659             :         if(gkfs::log::get_global_logger()) {                                   \
     660             :             gkfs::log::get_global_logger()->log_syscall(__VA_ARGS__);          \
     661             :         }                                                                      \
     662             :     } while(0);
     663             : 
     664             : #define LOG_DEBUG(...)                                                         \
     665             :     do {                                                                       \
     666             :         if(gkfs::log::get_global_logger()) {                                   \
     667             :             gkfs::log::get_global_logger()->log(gkfs::log::debug, __func__,    \
     668             :                                                 __LINE__, __VA_ARGS__);        \
     669             :         }                                                                      \
     670             :     } while(0);
     671             : 
     672             : #else // ! GKFS_DEBUG_BUILD
     673             : 
     674             : #define LOG_SYSCALL(...)                                                       \
     675             :     do {                                                                       \
     676             :     } while(0);
     677             : #define LOG_DEBUG(...)                                                         \
     678             :     do {                                                                       \
     679             :     } while(0);
     680             : 
     681             : #endif // ! GKFS_DEBUG_BUILD
     682             : #endif // !GKFS_ENABLE_LOGGING
     683             : 
     684             : #endif // LIBGKFS_LOGGING_HPP

Generated by: LCOV version 1.16