LCOV - code coverage report
Current view: top level - src/base - logger.cc (source / functions) Hit Total Coverage
Test: vlink Lines: 544 596 91.3 %
Date: 2026-09-30 18:30:16 Functions: 54 56 96.4 %
Branches: 313 442 70.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2026 by Thun Lu. All rights reserved.
       3                 :            :  * Author: Thun Lu <thun.lu@zohomail.cn>
       4                 :            :  * Repo:   https://github.com/thun-res/vlink
       5                 :            :  *  _    __   __      _           __
       6                 :            :  * | |  / /  / /     (_) ____    / /__
       7                 :            :  * | | / /  / /     / / / __ \  / //_/
       8                 :            :  * | |/ /  / /___  / / / / / / / ,<
       9                 :            :  * |___/  /_____/ /_/ /_/ /_/ /_/|_|
      10                 :            :  *
      11                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
      12                 :            :  * you may not use this file except in compliance with the License.
      13                 :            :  * You may obtain a copy of the License at
      14                 :            :  *
      15                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
      16                 :            :  *
      17                 :            :  * Unless required by applicable law or agreed to in writing, software
      18                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      19                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      20                 :            :  * See the License for the specific language governing permissions and
      21                 :            :  * limitations under the License.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "./base/logger.h"
      25                 :            : 
      26                 :            : #include <atomic>
      27                 :            : #include <charconv>
      28                 :            : #include <chrono>
      29                 :            : #include <cstdio>
      30                 :            : #include <filesystem>
      31                 :            : #include <fstream>
      32                 :            : #include <iostream>
      33                 :            : #include <limits>
      34                 :            : #include <memory>
      35                 :            : #include <mutex>
      36                 :            : #include <optional>
      37                 :            : #include <shared_mutex>
      38                 :            : #include <string>
      39                 :            : #include <utility>
      40                 :            : #include <vector>
      41                 :            : 
      42                 :            : #include "./base/cached_timestamp.h"
      43                 :            : #include "./base/logger_plugin_interface.h"
      44                 :            : #include "./base/memory_pool.h"
      45                 :            : #include "./base/utils.h"
      46                 :            : #include "./vlink/version.h"
      47                 :            : 
      48                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
      49                 :            : #include "./base/logger_backend.h"
      50                 :            : #elif defined(__ANDROID__)
      51                 :            : #include <android/log.h>
      52                 :            : #elif defined(__QNX__)
      53                 :            : #include <process.h>
      54                 :            : #include <sys/slog2.h>
      55                 :            : #elif defined(__linux__)
      56                 :            : #include <linux/kernel.h>
      57                 :            : #define VLINK_KMSG_DEV_PATH "/dev/kmsg"
      58                 :            : #endif
      59                 :            : 
      60                 :            : namespace vlink {
      61                 :            : 
      62                 :            : [[maybe_unused]] static constexpr size_t kDefaultWriteDepth = 1024L * 8;
      63                 :            : [[maybe_unused]] static constexpr size_t kDefaultLogMaxSize = 1024L * 1024L * 10U;
      64                 :            : [[maybe_unused]] static constexpr size_t kDefaultLogMaxCount = 10U;
      65                 :            : [[maybe_unused]] static constexpr int kDefaultLogFlushDelay = 500;
      66                 :            : 
      67                 :        106 : [[maybe_unused]] static std::string get_current_date(bool use_utc = false) {
      68                 :        106 :   auto now = std::chrono::system_clock::now();
      69                 :        106 :   std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
      70                 :        106 :   std::tm now_tm{};
      71                 :            : 
      72                 :            : #if defined(_WIN32)
      73                 :            : 
      74                 :            :   if (use_utc) {
      75                 :            :     gmtime_s(&now_tm, &now_time_t);
      76                 :            :   } else {
      77                 :            :     localtime_s(&now_tm, &now_time_t);
      78                 :            :   }
      79                 :            : #else
      80                 :            : 
      81         [ +  + ]:        106 :   if (use_utc) {
      82                 :          1 :     gmtime_r(&now_time_t, &now_tm);
      83                 :            :   } else {
      84                 :        105 :     localtime_r(&now_time_t, &now_tm);
      85                 :            :   }
      86                 :            : #endif
      87                 :            : 
      88                 :            :   char buffer[32];
      89                 :        106 :   std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &now_tm);
      90         [ +  - ]:        106 :   return std::string(buffer);
      91                 :            : }
      92                 :            : 
      93                 :         84 : [[maybe_unused]] static constexpr std::string_view get_log_level_str(Logger::Level level) {
      94   [ +  +  +  +  :         84 :   switch (level) {
             +  +  -  - ]
      95                 :          1 :     case Logger::kTrace:
      96                 :          1 :       return "TRACE";
      97                 :          4 :     case Logger::kDebug:
      98                 :          4 :       return "DEBUG";
      99                 :         69 :     case Logger::kInfo:
     100                 :         69 :       return "INFO ";
     101                 :          4 :     case Logger::kWarn:
     102                 :          4 :       return "WARN ";
     103                 :          4 :     case Logger::kError:
     104                 :          4 :       return "ERROR";
     105                 :          2 :     case Logger::kFatal:
     106                 :          2 :       return "FATAL";
     107                 :            :     // LCOV_EXCL_START GCOVR_EXCL_START
     108                 :            :     case Logger::kOff:
     109                 :            :       return "EMPTY";
     110                 :            :     default:
     111                 :            :       return "EMPTY";
     112                 :            :       // LCOV_EXCL_STOP GCOVR_EXCL_STOP
     113                 :            :   }
     114                 :            : }
     115                 :            : 
     116                 :        350 : [[maybe_unused]] static int get_log_level(const std::string& key) {
     117         [ +  - ]:        700 :   std::string str_value = Utils::get_env(key);
     118                 :            : 
     119         [ +  + ]:        350 :   if (str_value.empty()) {
     120                 :        316 :     return -1;
     121                 :            :   }
     122                 :            : 
     123   [ +  +  +  -  :         34 :   if (str_value == "Trace" || str_value == "TRACE" || str_value == "trace") {
             -  +  +  + ]
     124                 :          6 :     return Logger::kTrace;
     125   [ +  -  +  +  :         28 :   } else if (str_value == "Debug" || str_value == "DEBUG" || str_value == "debug") {
             -  +  +  + ]
     126                 :          1 :     return Logger::kDebug;
     127   [ +  +  +  -  :         27 :   } else if (str_value == "Info" || str_value == "INFO" || str_value == "info") {
             +  +  +  + ]
     128                 :          5 :     return Logger::kInfo;
     129   [ +  +  +  -  :         22 :   } else if (str_value == "Warn" || str_value == "WARN" || str_value == "warn") {
             -  +  +  + ]
     130                 :          1 :     return Logger::kWarn;
     131   [ +  -  +  +  :         21 :   } else if (str_value == "Error" || str_value == "ERROR" || str_value == "error") {
             -  +  +  + ]
     132                 :          1 :     return Logger::kError;
     133   [ +  -  +  -  :         20 :   } else if (str_value == "Fatal" || str_value == "FATAL" || str_value == "fatal") {
             +  +  +  + ]
     134                 :          1 :     return Logger::kFatal;
     135   [ +  +  +  -  :         19 :   } else if (str_value == "Off" || str_value == "OFF" || str_value == "off") {
             -  +  +  + ]
     136                 :         16 :     return Logger::kOff;
     137                 :            :   }
     138                 :            : 
     139                 :          3 :   int value = -1;
     140                 :            : 
     141         [ +  - ]:          3 :   auto [p, error] = std::from_chars(str_value.data(), str_value.data() + str_value.size(), value);
     142                 :            : 
     143         [ +  + ]:          3 :   if VUNLIKELY (error != std::errc()) {
     144                 :          1 :     return -1;
     145                 :            :   }
     146                 :            : 
     147   [ +  -  +  +  :          2 :   if VUNLIKELY (value < 0 || value > Logger::kOff) {
                   +  + ]
     148                 :          1 :     return Logger::kOff;
     149                 :            :   }
     150                 :            : 
     151                 :          1 :   return value;
     152                 :        350 : }
     153                 :            : 
     154                 :         84 : [[maybe_unused]] static std::string_view get_thread_id_str() {
     155                 :            :   thread_local char buffer[32];
     156                 :            :   thread_local bool initialized = false;
     157                 :            : 
     158         [ +  + ]:         84 :   if VUNLIKELY (!initialized) {
     159         [ +  - ]:          2 :     auto [p, ec] = std::to_chars(buffer, buffer + sizeof(buffer) - 1, Utils::get_native_thread_id());
     160                 :            : 
     161         [ +  - ]:          2 :     if (ec == std::errc()) {
     162                 :          2 :       *p = '\0';
     163                 :            :     } else {
     164                 :            :       std::snprintf(  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     165                 :            :           buffer, sizeof(buffer), "%llu",
     166                 :          0 :           static_cast<unsigned long long>(Utils::get_native_thread_id()));  // NOLINT(runtime/int, google-runtime-int)
     167                 :            :                                                                             // // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     168                 :            :     }
     169                 :            : 
     170                 :          2 :     initialized = true;
     171                 :            :   }
     172                 :            : 
     173                 :         84 :   return buffer;
     174                 :            : }
     175                 :            : 
     176                 :     229071 : static bool& is_logging_on_current_thread() noexcept {
     177                 :            :   static thread_local bool is_logging{false};
     178                 :     229071 :   return is_logging;
     179                 :            : }
     180                 :            : 
     181                 :        115 : static bool& is_in_handler_on_current_thread() noexcept {
     182                 :            :   static thread_local bool is_in_handler{false};
     183                 :        115 :   return is_in_handler;
     184                 :            : }
     185                 :            : 
     186                 :            : static thread_local bool logger_stream_retired = false;
     187                 :            : 
     188                 :            : struct LoggerStreamState final {
     189                 :            :   CachedTimestamp timestamp;
     190                 :            :   std::string console_buffer;
     191                 :            :   FastStream stream;
     192                 :            :   std::vector<std::unique_ptr<FastStream>> nested_streams;
     193                 :            :   size_t depth{0};
     194                 :            : };
     195                 :            : 
     196                 :        142 : static void retire_logger_stream_state(LoggerStreamState* state) noexcept {
     197         [ +  - ]:        142 :   delete state;
     198                 :        142 :   logger_stream_retired = true;
     199                 :        142 : }
     200                 :            : 
     201                 :       9896 : static LoggerStreamState& get_logger_stream_state() noexcept {
     202                 :            :   // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
     203                 :        144 :   thread_local std::unique_ptr<LoggerStreamState, void (*)(LoggerStreamState*)> state(new LoggerStreamState,
     204         [ +  + ]:      10040 :                                                                                       retire_logger_stream_state);
     205                 :       9896 :   return *state;
     206                 :            : }
     207                 :            : 
     208                 :          0 : static bool& is_plugin_logging_on_current_thread() noexcept {
     209                 :            :   static thread_local bool is_plugin_logging{false};
     210                 :          0 :   return is_plugin_logging;
     211                 :            : }
     212                 :            : 
     213                 :       1006 : [[maybe_unused]] static std::mutex& get_print_mtx() {
     214                 :            :   static std::mutex print_mtx;
     215                 :       1006 :   return print_mtx;
     216                 :            : }
     217                 :            : 
     218                 :            : template <uint8_t PrefixSizeT, uint8_t SuffixSizeT>
     219                 :        740 : [[maybe_unused]] static void print_with_color(const char (&prefix)[PrefixSizeT], std::string_view log,
     220                 :            :                                               const char (&suffix)[SuffixSizeT], FILE* file, bool in_order,
     221                 :            :                                               bool force_flush) {
     222                 :        740 :   std::unique_lock lock(get_print_mtx(), std::defer_lock);
     223                 :            : 
     224         [ +  + ]:        740 :   if (in_order) {
     225         [ +  - ]:        669 :     lock.lock();
     226                 :            :   }
     227                 :            : 
     228                 :            :   if constexpr (PrefixSizeT > 1) {
     229         [ +  - ]:        734 :     std::fwrite(prefix, sizeof(char), PrefixSizeT - 1, file);
     230                 :            :   }
     231                 :            : 
     232         [ +  - ]:        740 :   if VLIKELY (!log.empty()) {
     233         [ +  - ]:        740 :     std::fwrite(log.data(), sizeof(char), log.size(), file);
     234                 :            :   }
     235                 :            : 
     236                 :            :   if constexpr (SuffixSizeT > 1) {
     237         [ +  - ]:        740 :     std::fwrite(suffix, sizeof(char), SuffixSizeT - 1, file);
     238                 :            :   }
     239                 :            : 
     240   [ +  +  +  - ]:        740 :   if (in_order && force_flush) {
     241         [ +  - ]:        669 :     std::fflush(file);
     242                 :            :   }
     243                 :        740 : }
     244                 :            : 
     245                 :            : // LoggerGlobal
     246                 :            : struct LoggerGlobal final {  // NOLINT(clang-analyzer-optin.performance.Padding)
     247                 :            :   std::atomic_bool is_busy{false};
     248                 :            :   std::atomic_bool is_initialized{false};
     249                 :            :   std::atomic_bool is_initializing{false};
     250                 :            :   std::atomic_bool is_stopping{false};
     251                 :            : 
     252                 :            :   std::string app_name;
     253                 :            :   std::string log_path;
     254                 :            :   std::string version_log;
     255                 :            :   std::atomic<int> console_level{Logger::kDebug};
     256                 :            :   std::atomic<int> file_level{Logger::kDebug};
     257                 :            :   std::atomic_bool console_in_order{true};
     258                 :            :   std::atomic_bool console_level_by_user{false};
     259                 :            :   std::atomic_bool file_level_by_user{false};
     260                 :            :   std::atomic_bool console_format_enable{false};
     261                 :            :   std::atomic_bool utc_enable{false};
     262                 :            :   std::mutex level_mtx;
     263                 :            :   std::atomic_bool has_console_callback{false};
     264                 :            :   std::atomic_bool has_file_callback{false};
     265                 :            :   Logger::Callback console_callback;
     266                 :            :   Logger::Callback file_callback;
     267                 :            :   mutable std::shared_mutex callback_mtx;
     268                 :            :   std::atomic_bool has_pending_console_callback{false};
     269                 :            :   std::atomic_bool has_pending_file_callback{false};
     270                 :            :   Logger::Callback pending_console_callback;
     271                 :            :   Logger::Callback pending_file_callback;
     272                 :            :   std::mutex pending_mtx;
     273                 :            :   std::atomic<std::ios_base::fmtflags> stream_flags{std::ios_base::dec | std::ios_base::skipws};
     274                 :            :   std::atomic<int> stream_precision{6};
     275                 :            :   std::atomic<int> stream_width{0};
     276                 :            : 
     277                 :     230097 :   static LoggerGlobal& get() {
     278   [ +  +  +  -  :     230097 :     static LoggerGlobal instance;
             +  -  -  - ]
     279                 :     230097 :     return instance;
     280                 :            :   }
     281                 :            : 
     282                 :            :  private:
     283                 :        118 :   LoggerGlobal() {
     284         [ +  - ]:        118 :     MemoryPool::global_instance();
     285                 :        118 :     get_print_mtx();
     286                 :        118 :   }
     287                 :            : };
     288                 :            : 
     289                 :         40 : static void install_console_handler(Logger::Callback&& callback) noexcept {
     290                 :         40 :   auto& global_instance = LoggerGlobal::get();
     291                 :         40 :   Logger::Callback retired;
     292                 :         40 :   Logger::Callback retired_pending;
     293                 :            : 
     294                 :            :   {
     295                 :         40 :     std::unique_lock lock(global_instance.callback_mtx);
     296                 :            : 
     297                 :            :     {
     298                 :         40 :       std::lock_guard pending_lock(global_instance.pending_mtx);
     299                 :            : 
     300         [ -  + ]:         40 :       if (global_instance.has_pending_console_callback.exchange(false, std::memory_order_acq_rel)) {
     301                 :          0 :         retired_pending = std::move(global_instance.pending_console_callback);
     302                 :            :       }
     303                 :         40 :     }
     304                 :            : 
     305                 :         40 :     retired = std::move(global_instance.console_callback);
     306                 :         40 :     global_instance.console_callback = std::move(callback);
     307                 :         40 :     global_instance.has_console_callback.store(static_cast<bool>(global_instance.console_callback),
     308                 :            :                                                std::memory_order_release);
     309                 :         40 :   }
     310                 :         40 : }
     311                 :            : 
     312                 :          9 : static void install_file_handler(Logger::Callback&& callback) noexcept {
     313                 :          9 :   auto& global_instance = LoggerGlobal::get();
     314                 :          9 :   Logger::Callback retired;
     315                 :          9 :   Logger::Callback retired_pending;
     316                 :            : 
     317                 :            :   {
     318                 :          9 :     std::unique_lock lock(global_instance.callback_mtx);
     319                 :            : 
     320                 :            :     {
     321                 :          9 :       std::lock_guard pending_lock(global_instance.pending_mtx);
     322                 :            : 
     323         [ -  + ]:          9 :       if (global_instance.has_pending_file_callback.exchange(false, std::memory_order_acq_rel)) {
     324                 :          0 :         retired_pending = std::move(global_instance.pending_file_callback);
     325                 :            :       }
     326                 :          9 :     }
     327                 :            : 
     328                 :          9 :     retired = std::move(global_instance.file_callback);
     329                 :          9 :     global_instance.file_callback = std::move(callback);
     330                 :          9 :     global_instance.has_file_callback.store(static_cast<bool>(global_instance.file_callback),
     331                 :            :                                             std::memory_order_release);
     332                 :          9 :   }
     333                 :          9 : }
     334                 :            : 
     335                 :         55 : static void install_pending_handlers() noexcept {
     336                 :         55 :   auto& global_instance = LoggerGlobal::get();
     337                 :            : 
     338   [ +  +  +  -  :         55 :   if VLIKELY (!global_instance.has_pending_console_callback.load(std::memory_order_acquire) &&
                   +  + ]
     339                 :            :               !global_instance.has_pending_file_callback.load(std::memory_order_acquire)) {
     340                 :         51 :     return;
     341                 :            :   }
     342                 :            : 
     343         [ -  + ]:          4 :   if VUNLIKELY (is_in_handler_on_current_thread()) {
     344                 :          0 :     return;
     345                 :            :   }
     346                 :            : 
     347                 :          4 :   Logger::Callback retired_console;
     348                 :          4 :   Logger::Callback retired_file;
     349                 :            : 
     350                 :            :   {
     351                 :          4 :     std::unique_lock callback_lock(global_instance.callback_mtx);
     352                 :          4 :     std::lock_guard pending_lock(global_instance.pending_mtx);
     353                 :            : 
     354         [ +  - ]:          4 :     if (global_instance.has_pending_console_callback.exchange(false, std::memory_order_acq_rel)) {
     355                 :          4 :       retired_console = std::move(global_instance.console_callback);
     356                 :          4 :       global_instance.console_callback = std::move(global_instance.pending_console_callback);
     357                 :          4 :       global_instance.has_console_callback.store(static_cast<bool>(global_instance.console_callback),
     358                 :            :                                                  std::memory_order_release);
     359                 :            :     }
     360                 :            : 
     361         [ +  + ]:          4 :     if (global_instance.has_pending_file_callback.exchange(false, std::memory_order_acq_rel)) {
     362                 :          3 :       retired_file = std::move(global_instance.file_callback);
     363                 :          3 :       global_instance.file_callback = std::move(global_instance.pending_file_callback);
     364                 :          3 :       global_instance.has_file_callback.store(static_cast<bool>(global_instance.file_callback),
     365                 :            :                                               std::memory_order_release);
     366                 :            :     }
     367                 :          4 :   }
     368                 :          4 : }
     369                 :            : 
     370                 :            : // Logger::Impl
     371                 :            : struct Logger::Impl final {  // NOLINT(clang-analyzer-optin.performance.Padding)
     372                 :            :   enum class PluginInitState : uint8_t {
     373                 :            :     kPending,
     374                 :            :     kInitializing,
     375                 :            :     kComplete,
     376                 :            :   };
     377                 :            : 
     378                 :            :   struct PluginFinalizer final {
     379                 :            :     Logger& instance;
     380                 :            : 
     381                 :          0 :     ~PluginFinalizer() {
     382                 :          0 :       auto& global_instance = LoggerGlobal::get();
     383                 :            : 
     384                 :          0 :       global_instance.is_stopping.store(true, std::memory_order_release);
     385                 :            : 
     386                 :            : #if defined(_WIN32)
     387                 :            :       if (Utils::is_terminating()) {
     388                 :            :         return;
     389                 :            :       }
     390                 :            : #endif
     391                 :            : 
     392                 :          0 :       instance.impl_->is_enable_file_channel.store(false, std::memory_order_release);
     393                 :          0 :       instance.impl_->interface->flush();
     394                 :          0 :       instance.impl_->interface.reset();
     395                 :          0 :       instance.impl_->plugin.clear();
     396                 :          0 :     }
     397                 :            :   };
     398                 :            : 
     399                 :            :   std::atomic_bool disk_emergency{false};
     400                 :            :   std::atomic_bool is_enable_file_channel{false};
     401                 :            :   std::once_flag file_init;
     402                 :            :   std::atomic_bool file_ready{false};
     403                 :            : 
     404                 :            :   std::atomic<PluginInitState> plugin_init_state{PluginInitState::kPending};
     405                 :            :   std::string plugin_name;
     406                 :            :   Plugin plugin;
     407                 :            :   std::shared_ptr<LoggerPluginInterface> interface;
     408                 :            : 
     409                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
     410                 :            :   std::unique_ptr<LoggerBackend> backend;
     411                 :            : #elif defined(__ANDROID__)
     412                 :            : #elif defined(__QNX__)
     413                 :            :   slog2_buffer_t slog2_buffer{nullptr};
     414                 :            : #elif defined(__linux__)
     415                 :            :   std::ofstream kmsg_dev;
     416                 :            :   std::mutex file_mtx;
     417                 :            : #endif
     418                 :            : };
     419                 :            : 
     420                 :            : // Logger
     421                 :         57 : void Logger::init(const std::string& app_name, const std::string& log_path) noexcept {
     422   [ +  +  +  - ]:         57 :   static auto& global_instance = LoggerGlobal::get();
     423                 :            : 
     424         [ +  - ]:         57 :   if (!app_name.empty()) {
     425                 :         57 :     global_instance.app_name = app_name;
     426                 :            : 
     427         [ +  + ]:         57 :     if (!log_path.empty()) {
     428                 :          7 :       global_instance.log_path = log_path;
     429                 :            :     }
     430                 :            :   }
     431                 :            : 
     432                 :         57 :   Logger::get();
     433                 :         57 : }
     434                 :            : 
     435                 :       6548 : Logger& Logger::get() noexcept {
     436   [ +  +  +  - ]:       6548 :   static Logger instance;
     437                 :            : 
     438   [ +  +  +  -  :       6668 :   if VUNLIKELY (!instance.impl_->file_ready.load(std::memory_order_acquire) && !is_logging_on_current_thread() &&
          +  +  +  -  +  
             +  +  +  +  
                      + ]
     439                 :            :                 !LoggerGlobal::get().is_busy.load(std::memory_order_acquire) &&
     440                 :            :                 LoggerGlobal::get().file_level.load(std::memory_order_acquire) < kOff) {
     441                 :        106 :     std::call_once(instance.impl_->file_init, [&] {
     442                 :        106 :       auto& global_instance = LoggerGlobal::get();
     443                 :        106 :       auto& logging = is_logging_on_current_thread();
     444                 :        106 :       const bool previous = logging;
     445                 :            : 
     446                 :        106 :       global_instance.is_busy.store(true, std::memory_order_release);
     447                 :        106 :       logging = true;
     448                 :        106 :       instance.initialize_file_channel();
     449                 :            : 
     450   [ +  +  +  + ]:        211 :       if (instance.impl_->is_enable_file_channel.load(std::memory_order_acquire) &&
     451         [ +  - ]:        210 :           kInfo >= global_instance.file_level.load(std::memory_order_acquire)) {
     452                 :        105 :         instance.write_to_file(kInfo, global_instance.version_log);
     453                 :            :       }
     454                 :            : 
     455                 :        106 :       logging = previous;
     456                 :        106 :       global_instance.is_busy.store(false, std::memory_order_release);
     457                 :        106 :     });
     458                 :            : 
     459                 :        106 :     instance.initialize_plugin();
     460                 :            : 
     461         [ +  - ]:        106 :     if (instance.impl_->plugin_init_state.load(std::memory_order_acquire) != Impl::PluginInitState::kInitializing) {
     462                 :        106 :       instance.impl_->file_ready.store(true, std::memory_order_release);
     463                 :            :     }
     464                 :            :   }
     465                 :            : 
     466                 :       6547 :   return instance;
     467                 :            : }
     468                 :            : 
     469                 :        150 : void Logger::flush() noexcept {
     470                 :        150 :   auto& global_instance = LoggerGlobal::get();
     471                 :            : 
     472   [ +  +  -  +  :        150 :   if VUNLIKELY (is_logging_on_current_thread() || global_instance.is_initializing.load(std::memory_order_acquire) ||
          +  +  -  +  +  
                      + ]
     473                 :            :                 global_instance.is_stopping.load(std::memory_order_acquire)) {
     474                 :          2 :     return;
     475                 :            :   }
     476                 :            : 
     477                 :        148 :   Logger& instance = Logger::get();
     478                 :            : 
     479                 :            :   {
     480                 :        148 :     std::lock_guard lock(get_print_mtx());
     481                 :        148 :     std::fflush(stdout);
     482                 :        148 :     std::fflush(stderr);
     483                 :        148 :   }
     484                 :            : 
     485         [ +  + ]:        148 :   if (!instance.impl_->is_enable_file_channel.load(std::memory_order_acquire)) {
     486                 :          1 :     return;
     487                 :            :   }
     488                 :            : 
     489         [ -  + ]:        147 :   if VUNLIKELY (instance.impl_->interface) {
     490                 :          0 :     auto& is_plugin_logging = is_plugin_logging_on_current_thread();
     491                 :            : 
     492         [ #  # ]:          0 :     if VUNLIKELY (is_plugin_logging) {
     493                 :          0 :       return;
     494                 :            :     }
     495                 :            : 
     496                 :          0 :     is_plugin_logging = true;
     497                 :          0 :     instance.impl_->interface->flush();
     498                 :          0 :     is_plugin_logging = false;
     499                 :            : 
     500                 :          0 :     return;
     501                 :            :   }
     502                 :            : 
     503         [ +  + ]:        147 :   if VUNLIKELY (instance.impl_->disk_emergency.load(std::memory_order_acquire)) {
     504                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     505                 :            :   }
     506                 :            : 
     507                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
     508                 :        146 :   instance.impl_->backend->flush();
     509                 :            : #endif
     510                 :            : }
     511                 :            : 
     512                 :         44 : void Logger::register_console_handler(Callback&& callback) noexcept {
     513                 :         44 :   auto& global_instance = LoggerGlobal::get();
     514                 :            : 
     515         [ +  + ]:         44 :   if VUNLIKELY (is_in_handler_on_current_thread()) {
     516                 :          4 :     std::lock_guard lock(global_instance.pending_mtx);
     517                 :            : 
     518                 :          4 :     global_instance.pending_console_callback = std::move(callback);
     519                 :          4 :     global_instance.has_pending_console_callback.store(true, std::memory_order_release);
     520                 :            : 
     521                 :          4 :     return;
     522                 :          4 :   }
     523                 :            : 
     524                 :         40 :   install_console_handler(std::move(callback));
     525                 :            : }
     526                 :            : 
     527                 :         12 : void Logger::register_file_handler(Callback&& callback) noexcept {
     528                 :         12 :   auto& global_instance = LoggerGlobal::get();
     529                 :            : 
     530         [ +  + ]:         12 :   if VUNLIKELY (is_in_handler_on_current_thread()) {
     531                 :          3 :     std::lock_guard lock(global_instance.pending_mtx);
     532                 :            : 
     533                 :          3 :     global_instance.pending_file_callback = std::move(callback);
     534                 :          3 :     global_instance.has_pending_file_callback.store(true, std::memory_order_release);
     535                 :            : 
     536                 :          3 :     return;
     537                 :          3 :   }
     538                 :            : 
     539                 :          9 :   install_file_handler(std::move(callback));
     540                 :            : }
     541                 :            : 
     542                 :         52 : void Logger::set_console_level(Level level) noexcept {
     543                 :         52 :   auto& global_instance = LoggerGlobal::get();
     544                 :         52 :   std::lock_guard lock(global_instance.level_mtx);
     545                 :            : 
     546                 :         52 :   global_instance.console_level.store(level, std::memory_order_release);
     547                 :         52 :   global_instance.console_level_by_user.store(true, std::memory_order_release);
     548                 :         52 : }
     549                 :            : 
     550                 :         28 : void Logger::set_file_level(Level level) noexcept {
     551                 :         28 :   auto& global_instance = LoggerGlobal::get();
     552                 :         28 :   std::lock_guard lock(global_instance.level_mtx);
     553                 :            : 
     554                 :         28 :   global_instance.file_level.store(level, std::memory_order_release);
     555                 :         28 :   global_instance.file_level_by_user.store(true, std::memory_order_release);
     556                 :         28 : }
     557                 :            : 
     558                 :          2 : void Logger::set_console_fmt_enable(bool enable) noexcept {
     559                 :          2 :   LoggerGlobal::get().console_format_enable.store(enable, std::memory_order_release);
     560                 :          2 : }
     561                 :            : 
     562                 :         17 : Logger::Level Logger::get_console_level() noexcept {
     563                 :         34 :   return static_cast<Logger::Level>(LoggerGlobal::get().console_level.load(std::memory_order_acquire));
     564                 :            : }
     565                 :            : 
     566                 :          8 : Logger::Level Logger::get_file_level() noexcept {
     567                 :         16 :   return static_cast<Logger::Level>(LoggerGlobal::get().file_level.load(std::memory_order_acquire));
     568                 :            : }
     569                 :            : 
     570                 :          3 : bool Logger::get_console_fmt_enable() noexcept {
     571                 :          3 :   return LoggerGlobal::get().console_format_enable.load(std::memory_order_acquire);
     572                 :            : }
     573                 :            : 
     574                 :          6 : void Logger::set_stream_flag(std::ios_base::fmtflags flags) noexcept {
     575                 :          6 :   LoggerGlobal::get().stream_flags.store(flags, std::memory_order_release);
     576                 :          6 : }
     577                 :            : 
     578                 :          2 : void Logger::set_stream_precision(int precision) noexcept {
     579                 :          2 :   LoggerGlobal::get().stream_precision.store(precision, std::memory_order_release);
     580                 :          2 : }
     581                 :            : 
     582                 :          5 : void Logger::set_stream_width(int width) noexcept {
     583                 :          5 :   LoggerGlobal::get().stream_width.store(width, std::memory_order_release);
     584                 :          5 : }
     585                 :            : 
     586                 :          2 : std::ios_base::fmtflags Logger::get_stream_flag() noexcept {
     587                 :          2 :   return LoggerGlobal::get().stream_flags.load(std::memory_order_acquire);
     588                 :            : }
     589                 :            : 
     590                 :          2 : int Logger::get_stream_precision() noexcept {
     591                 :          4 :   return LoggerGlobal::get().stream_precision.load(std::memory_order_acquire);
     592                 :            : }
     593                 :            : 
     594                 :          4 : int Logger::get_stream_width() noexcept { return LoggerGlobal::get().stream_width.load(std::memory_order_acquire); }
     595                 :            : 
     596                 :          3 : void Logger::enable_backtrace(size_t size) noexcept {
     597                 :          3 :   Logger& instance = Logger::get();
     598                 :            : 
     599         [ -  + ]:          3 :   if VUNLIKELY (instance.impl_->disk_emergency.load(std::memory_order_acquire)) {
     600                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     601                 :            :   }
     602                 :            : 
     603         [ -  + ]:          3 :   if VUNLIKELY (!instance.impl_->is_enable_file_channel.load(std::memory_order_acquire)) {
     604                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     605                 :            :   }
     606                 :            : 
     607         [ -  + ]:          3 :   if VUNLIKELY (instance.impl_->interface) {
     608                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     609                 :            :   }
     610                 :            : 
     611                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
     612                 :          3 :   instance.impl_->backend->enable_backtrace(size);
     613                 :            : 
     614                 :            : #else
     615                 :            :   (void)size;
     616                 :            : #endif
     617                 :            : }
     618                 :            : 
     619                 :          3 : void Logger::disable_backtrace() noexcept {
     620                 :          3 :   Logger& instance = Logger::get();
     621                 :            : 
     622         [ -  + ]:          3 :   if VUNLIKELY (!instance.impl_->is_enable_file_channel.load(std::memory_order_acquire)) {
     623                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     624                 :            :   }
     625                 :            : 
     626         [ -  + ]:          3 :   if VUNLIKELY (instance.impl_->interface) {
     627                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     628                 :            :   }
     629                 :            : 
     630                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
     631         [ +  - ]:          3 :   if (instance.impl_->backend) {
     632                 :          3 :     instance.impl_->backend->disable_backtrace();
     633                 :            :   }
     634                 :            : #else
     635                 :            :   (void)instance;
     636                 :            : #endif
     637                 :            : }
     638                 :            : 
     639                 :          2 : void Logger::dump_backtrace() noexcept {
     640                 :          2 :   Logger& instance = Logger::get();
     641                 :            : 
     642         [ -  + ]:          2 :   if VUNLIKELY (!instance.impl_->is_enable_file_channel.load(std::memory_order_acquire)) {
     643                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     644                 :            :   }
     645                 :            : 
     646         [ -  + ]:          2 :   if VUNLIKELY (instance.impl_->interface) {
     647                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     648                 :            :   }
     649                 :            : 
     650                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
     651                 :          4 :   LoggerBackend::ConsoleWriter console_writer = [](Level level, std::string_view log) {
     652         [ +  - ]:          8 :     if (level >= LoggerGlobal::get().console_level.load(std::memory_order_acquire)) {
     653                 :          4 :       write_to_console(level, log, true);
     654                 :            :     }
     655                 :          2 :   };
     656         [ +  - ]:          2 :   if (instance.impl_->backend) {
     657                 :          2 :     instance.impl_->backend->dump_backtrace(console_writer);
     658                 :            :   }
     659                 :            : #else
     660                 :            :   (void)instance;
     661                 :            : #endif
     662                 :          2 : }
     663                 :            : 
     664                 :          1 : bool Logger::is_busy() noexcept { return LoggerGlobal::get().is_busy.load(std::memory_order_acquire); }
     665                 :            : 
     666                 :     219178 : bool Logger::is_writable(Level level) noexcept {
     667         [ -  + ]:     219178 :   if VUNLIKELY (level >= kOff) {
     668                 :          0 :     return false;
     669                 :            :   }
     670                 :            : 
     671         [ +  + ]:     219178 :   if VUNLIKELY (level == kFatal) {
     672                 :        141 :     return true;
     673                 :            :   }
     674                 :            : 
     675                 :     219037 :   return can_log(level);
     676                 :            : }
     677                 :            : 
     678                 :     214145 : bool Logger::try_acquire_periodic_log(Level level, int64_t interval_ms,
     679                 :            :                                       std::atomic<uint64_t>& last_log_time_ns) noexcept {
     680         [ +  + ]:     214145 :   if VUNLIKELY (level >= kFatal) {
     681                 :          1 :     return false;
     682                 :            :   }
     683                 :            : 
     684         [ +  + ]:     214144 :   if (!is_writable(level)) {
     685                 :          1 :     return false;
     686                 :            :   }
     687                 :            : 
     688         [ +  + ]:     214143 :   if VUNLIKELY (interval_ms <= 0) {
     689                 :          3 :     return true;
     690                 :            :   }
     691                 :            : 
     692                 :     214140 :   constexpr uint64_t kNanosecondsPerMillisecond = 1000U * 1000U;
     693                 :     214140 :   const auto unsigned_interval_ms = static_cast<uint64_t>(interval_ms);
     694                 :     214140 :   const auto interval_ns = unsigned_interval_ms > std::numeric_limits<uint64_t>::max() / kNanosecondsPerMillisecond
     695         [ -  + ]:     214140 :                                ? std::numeric_limits<uint64_t>::max()
     696                 :     214140 :                                : unsigned_interval_ms * kNanosecondsPerMillisecond;
     697   [ +  +  +  - ]:     214140 :   static const auto kStartTime = std::chrono::steady_clock::now();
     698                 :            :   const auto now_ns =
     699                 :     214140 :       static_cast<uint64_t>(
     700                 :     214140 :           std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - kStartTime).count()) +
     701                 :     214140 :       1U;
     702                 :     428280 :   auto last_ns = last_log_time_ns.load(std::memory_order_relaxed);
     703                 :            : 
     704                 :            :   for (;;) {
     705         [ +  + ]:     214140 :     if VLIKELY (last_ns != 0U) {
     706         [ +  + ]:     214130 :       if VUNLIKELY (last_ns >= now_ns) {
     707                 :          1 :         return false;
     708                 :            :       }
     709                 :            : 
     710         [ +  + ]:     214129 :       if VLIKELY (now_ns - last_ns < interval_ns) {
     711                 :     214128 :         return false;
     712                 :            :       }
     713                 :            :     }
     714                 :            : 
     715         [ +  - ]:         22 :     if VLIKELY (last_log_time_ns.compare_exchange_weak(last_ns, now_ns, std::memory_order_relaxed,
     716                 :            :                                                        std::memory_order_relaxed)) {
     717                 :         11 :       return true;
     718                 :            :     }
     719                 :            :   }
     720                 :            : }
     721                 :            : 
     722                 :        118 : Logger::Logger() noexcept {
     723   [ +  -  +  - ]:        118 :   static auto& global_instance = LoggerGlobal::get();
     724                 :        118 :   global_instance.is_initializing.store(true, std::memory_order_release);
     725                 :            : 
     726                 :        118 :   auto& is_logging = is_logging_on_current_thread();
     727                 :        118 :   const bool was_logging = is_logging;
     728                 :            : 
     729                 :        118 :   is_logging = true;
     730                 :        118 :   impl_ = std::make_unique<Impl>();
     731                 :        118 :   global_instance.is_busy.store(true, std::memory_order_release);
     732                 :            : 
     733                 :        118 :   int common_level = get_log_level("VLINK_LOG_LEVEL");
     734                 :            : 
     735                 :            :   {
     736                 :        118 :     std::lock_guard lock(global_instance.level_mtx);
     737                 :            : 
     738         [ +  + ]:        118 :     if (!global_instance.console_level_by_user.load(std::memory_order_acquire)) {
     739                 :        116 :       int console_level = get_log_level("VLINK_LOG_CONSOLE_LEVEL");
     740                 :            : 
     741         [ +  + ]:        116 :       if (console_level >= 0) {
     742                 :         16 :         global_instance.console_level.store(console_level, std::memory_order_release);
     743         [ +  + ]:        100 :       } else if (common_level >= 0) {
     744                 :          1 :         global_instance.console_level.store(common_level, std::memory_order_release);
     745                 :            :       }
     746                 :            :     }
     747                 :            : 
     748         [ +  + ]:        118 :     if (!global_instance.file_level_by_user.load(std::memory_order_acquire)) {
     749                 :        116 :       int file_level = get_log_level("VLINK_LOG_FILE_LEVEL");
     750                 :            : 
     751         [ +  + ]:        116 :       if (file_level >= 0) {
     752                 :         13 :         global_instance.file_level.store(file_level, std::memory_order_release);
     753         [ +  + ]:        103 :       } else if (common_level >= 0) {
     754                 :          4 :         global_instance.file_level.store(common_level, std::memory_order_release);
     755                 :            :       }
     756                 :            :     }
     757                 :        118 :   }
     758                 :            : 
     759                 :            :   {
     760                 :        236 :     std::string enable_console_unorder = Utils::get_env("VLINK_LOG_CONSOLE_UNORDER");
     761                 :        118 :     global_instance.console_in_order.store(enable_console_unorder != "1", std::memory_order_release);
     762                 :            : 
     763                 :        236 :     std::string utc_enable_str = Utils::get_env("VLINK_LOG_UTC_ENABLE");
     764                 :        118 :     global_instance.utc_enable.store(utc_enable_str == "1", std::memory_order_release);
     765                 :            : 
     766         [ +  + ]:        118 :     if (global_instance.app_name.empty()) {
     767                 :        111 :       global_instance.app_name = Utils::get_app_name();
     768                 :            : 
     769         [ -  + ]:        111 :       if VUNLIKELY (global_instance.app_name.empty()) {
     770                 :            :         global_instance.app_name = "unknown";                          // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     771                 :            :         std::cerr << "Can not get app name for logger!" << std::endl;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     772                 :            :       }
     773                 :            :     }
     774                 :            : 
     775                 :        236 :     std::string console_format = Utils::get_env("VLINK_LOG_CONSOLE_FMT");
     776                 :        118 :     global_instance.console_format_enable.store(console_format == "1", std::memory_order_release);
     777                 :        118 :   }
     778                 :            : 
     779                 :        118 :   is_logging = was_logging;
     780                 :        118 :   global_instance.is_busy.store(false, std::memory_order_release);
     781                 :        118 :   global_instance.is_initializing.store(false, std::memory_order_release);
     782                 :        118 :   global_instance.is_initialized.store(true, std::memory_order_release);
     783                 :        118 : }
     784                 :            : 
     785                 :        223 : Logger::~Logger() noexcept {
     786                 :        118 :   auto& global_instance = LoggerGlobal::get();
     787                 :        118 :   global_instance.is_stopping.store(true, std::memory_order_release);
     788                 :            : 
     789                 :            : #if defined(_WIN32)
     790                 :            :   if (Utils::is_terminating()) {
     791                 :            :     (void)impl_.release();
     792                 :            :     return;
     793                 :            :   }
     794                 :            : #endif
     795                 :            : 
     796         [ +  + ]:        118 :   if (!impl_->is_enable_file_channel.exchange(false, std::memory_order_acq_rel)) {
     797                 :         13 :     return;
     798                 :            :   }
     799                 :            : 
     800                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
     801                 :        105 :   impl_->backend.reset();
     802                 :            : 
     803                 :            : #elif defined(__ANDROID__)
     804                 :            : #elif defined(__QNX__)
     805                 :            : #elif defined(__linux__)
     806                 :            : 
     807                 :            :   if (impl_->kmsg_dev.is_open()) {
     808                 :            :     impl_->kmsg_dev.close();
     809                 :            :   }
     810                 :            : 
     811                 :            : #endif
     812         [ +  + ]:        118 : }
     813                 :            : 
     814                 :     223774 : bool Logger::can_log(Level level) noexcept {
     815                 :     223774 :   auto& global_instance = LoggerGlobal::get();
     816                 :            : 
     817         [ +  + ]:     223774 :   if VUNLIKELY (!global_instance.is_initialized.load(std::memory_order_acquire)) {
     818   [ +  -  +  -  :         82 :     if (is_logging_on_current_thread() || global_instance.is_initializing.load(std::memory_order_acquire) ||
             -  +  -  + ]
     819                 :         41 :         global_instance.is_stopping.load(std::memory_order_acquire)) {
     820                 :          0 :       return false;
     821                 :            :     }
     822                 :            : 
     823                 :         41 :     Logger::get();
     824                 :            :   }
     825                 :            : 
     826   [ +  #  +  +  :     455897 :   if (level != kFatal && level < global_instance.console_level.load(std::memory_order_acquire) &&
                   +  + ]
     827         [ +  + ]:      16700 :       level < global_instance.file_level.load(std::memory_order_acquire)) {
     828                 :        171 :     return false;
     829                 :            :   }
     830                 :            : 
     831   [ +  +  -  +  :     223602 :   if VUNLIKELY (is_logging_on_current_thread() || global_instance.is_stopping.load(std::memory_order_acquire)) {
                   +  + ]
     832                 :          3 :     return false;
     833                 :            :   }
     834                 :            : 
     835                 :     223600 :   return true;
     836                 :            : }
     837                 :            : 
     838                 :       4878 : void Logger::write(Level level, std::string_view log) noexcept {
     839                 :       4878 :   auto& global_instance = LoggerGlobal::get();
     840                 :            : 
     841   [ +  +  -  +  :       4878 :   if VUNLIKELY (is_logging_on_current_thread() || global_instance.is_initializing.load(std::memory_order_acquire) ||
          +  +  -  +  +  
                      + ]
     842                 :            :                 global_instance.is_stopping.load(std::memory_order_acquire)) {
     843                 :          2 :     return;
     844                 :            :   }
     845                 :            : 
     846                 :       4876 :   Logger& instance = Logger::get();
     847                 :            : 
     848         [ +  + ]:       9752 :   if (level >= global_instance.console_level.load(std::memory_order_acquire)) {
     849                 :        785 :     write_to_console(level, log);
     850                 :            :   }
     851                 :            : 
     852         [ +  + ]:       9752 :   if (level >= global_instance.file_level.load(std::memory_order_acquire)) {
     853                 :       4812 :     instance.write_to_file(level, log);
     854                 :            :   }
     855                 :            : }
     856                 :            : 
     857                 :       4864 : FastStream& Logger::get_local_stream() noexcept {
     858   [ +  +  +  - ]:       4864 :   static auto& global_instance = LoggerGlobal::get();
     859                 :            :   FastStream* selected;
     860                 :            : 
     861         [ -  + ]:       4864 :   if VUNLIKELY (logger_stream_retired) {
     862                 :            :     // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
     863                 :          0 :     selected = new FastStream;
     864                 :            :   } else {
     865                 :       4864 :     auto& state = get_logger_stream_state();
     866                 :            : 
     867         [ +  + ]:       4864 :     if VUNLIKELY (state.depth > state.nested_streams.size()) {
     868                 :          1 :       state.nested_streams.emplace_back(std::make_unique<FastStream>());
     869                 :            :     }
     870                 :            : 
     871         [ +  + ]:       4864 :     selected = state.depth == 0 ? &state.stream : state.nested_streams[state.depth - 1].get();
     872                 :       4864 :     ++state.depth;
     873                 :            :   }
     874                 :            : 
     875                 :       4864 :   auto& stream = *selected;
     876                 :            : 
     877                 :       4864 :   stream.reset();
     878                 :            : 
     879                 :       4864 :   auto flags = global_instance.stream_flags.load(std::memory_order_acquire);
     880                 :            : 
     881         [ +  + ]:       4864 :   if VUNLIKELY (stream.flags() != flags) {
     882                 :          4 :     stream.flags(flags);
     883                 :            :   }
     884                 :            : 
     885                 :       4864 :   auto precision = global_instance.stream_precision.load(std::memory_order_acquire);
     886                 :            : 
     887         [ +  + ]:       4864 :   if VUNLIKELY (stream.precision() != precision) {
     888                 :          3 :     stream.precision(precision);
     889                 :            :   }
     890                 :            : 
     891                 :       4864 :   auto width = global_instance.stream_width.load(std::memory_order_acquire);
     892                 :            : 
     893         [ +  + ]:       4864 :   if VUNLIKELY (stream.width() != width) {
     894                 :          1 :     stream.width(width);
     895                 :            :   }
     896                 :            : 
     897                 :       4864 :   return stream;
     898                 :            : }
     899                 :            : 
     900                 :       4864 : void Logger::release_local_stream(FastStream* stream) noexcept {
     901         [ -  + ]:       4864 :   if VUNLIKELY (logger_stream_retired) {
     902         [ #  # ]:          0 :     delete stream;
     903                 :            :   } else {
     904                 :       4864 :     --get_logger_stream_state().depth;
     905                 :            :   }
     906                 :       4864 : }
     907                 :            : 
     908                 :        106 : void Logger::initialize_file_channel() noexcept {
     909                 :        106 :   auto& global_instance = LoggerGlobal::get();
     910                 :        106 :   global_instance.version_log.reserve(128);
     911                 :            : 
     912                 :        106 :   global_instance.version_log.append("***** ");
     913                 :        106 :   global_instance.version_log.append("[PNAME: ");
     914                 :        106 :   global_instance.version_log.append(global_instance.app_name);
     915                 :        106 :   global_instance.version_log.append("] ");
     916                 :            : 
     917                 :        106 :   global_instance.version_log.append("[PID: ");
     918                 :        106 :   global_instance.version_log.append(Utils::get_pid_str());
     919                 :        106 :   global_instance.version_log.append("] ");
     920                 :            : 
     921         [ +  + ]:        106 :   if (global_instance.utc_enable.load(std::memory_order_acquire)) {
     922                 :          1 :     global_instance.version_log.append("[DATE (UTC): ");
     923                 :          1 :     global_instance.version_log.append(get_current_date(true));
     924                 :          1 :     global_instance.version_log.append("] ");
     925                 :            :   } else {
     926                 :        105 :     global_instance.version_log.append("[DATE: ");
     927                 :        105 :     global_instance.version_log.append(get_current_date(false));
     928                 :        105 :     global_instance.version_log.append("] ");
     929                 :            :   }
     930                 :            : 
     931                 :        106 :   global_instance.version_log.append("[VERSION: ");
     932                 :        106 :   global_instance.version_log.append(VLINK_VERSION);
     933                 :        106 :   global_instance.version_log.append("] ");
     934                 :        106 :   global_instance.version_log.append("*****");
     935                 :            : 
     936                 :        106 :   impl_->plugin_name = Utils::get_env("VLINK_LOG_PLUGIN");
     937                 :            : 
     938         [ +  + ]:        106 :   if (!impl_->plugin_name.empty()) {
     939                 :          1 :     return;
     940                 :            :   }
     941                 :            : 
     942         [ +  + ]:        105 :   if (global_instance.log_path.empty()) {
     943                 :        198 :     std::string log_dir = Utils::get_env("VLINK_LOG_DIR");
     944                 :            : 
     945         [ +  - ]:         99 :     if (log_dir.empty()) {
     946                 :         99 :       log_dir = Utils::get_tmp_dir() + "/" + "vlink-log";
     947         [ #  # ]:          0 :     } else if (log_dir.back() == '/') {
     948                 :          0 :       log_dir.pop_back();
     949                 :            :     }
     950                 :            : 
     951                 :            :     try {
     952   [ +  -  +  -  :         99 :       if (!std::filesystem::exists(log_dir)) {
                   +  + ]
     953   [ +  -  +  - ]:          1 :         std::filesystem::create_directories(log_dir);
     954                 :            :       }
     955                 :            :     } catch (std::exception&) {        // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     956                 :            :       log_dir = Utils::get_tmp_dir();  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     957                 :            :     }  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     958                 :            : 
     959                 :        198 :     std::string log_pid_enable = Utils::get_env("VLINK_LOG_PID_ENABLE");
     960                 :            : 
     961                 :         99 :     global_instance.log_path = log_dir + "/" + global_instance.app_name;
     962                 :            : 
     963         [ -  + ]:         99 :     if (log_pid_enable == "1") {
     964                 :          0 :       global_instance.log_path += "/" + Utils::get_pid_str();
     965                 :            :     }
     966                 :         99 :   }
     967                 :            : 
     968                 :        105 :   size_t log_max_size = kDefaultLogMaxSize;
     969                 :        105 :   size_t log_max_count = kDefaultLogMaxCount;
     970                 :        105 :   int log_flush_delay_ms = kDefaultLogFlushDelay;
     971                 :            : 
     972                 :            :   {
     973                 :        210 :     std::string log_max_size_str = Utils::get_env("VLINK_LOG_MAX_SIZE");
     974                 :        210 :     std::string log_max_count_str = Utils::get_env("VLINK_LOG_MAX_COUNT");
     975                 :        210 :     std::string log_flush_delay_str = Utils::get_env("VLINK_LOG_FLUSH_DELAY");
     976                 :            : 
     977         [ +  + ]:        105 :     if (!log_max_size_str.empty()) {
     978                 :          4 :       std::from_chars(log_max_size_str.data(), log_max_size_str.data() + log_max_size_str.size(), log_max_size);
     979                 :            :     }
     980                 :            : 
     981         [ +  + ]:        105 :     if (!log_max_count_str.empty()) {
     982                 :          4 :       std::from_chars(log_max_count_str.data(), log_max_count_str.data() + log_max_count_str.size(), log_max_count);
     983                 :            :     }
     984                 :            : 
     985         [ +  + ]:        105 :     if (!log_flush_delay_str.empty()) {
     986                 :          4 :       std::from_chars(log_flush_delay_str.data(), log_flush_delay_str.data() + log_flush_delay_str.size(),
     987                 :            :                       log_flush_delay_ms);
     988                 :            :     }
     989                 :        105 :   }
     990                 :            : 
     991                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
     992                 :        210 :   std::string log_strategy = Utils::get_env("VLINK_LOG_STORE_STRATEGY");
     993                 :        210 :   std::string log_append = Utils::get_env("VLINK_LOG_OPEN_APPEND");
     994                 :        210 :   std::string log_block = Utils::get_env("VLINK_LOG_BLOCK_SYNC");
     995                 :        210 :   std::string log_depth = Utils::get_env("VLINK_LOG_WRITE_DEPTH");
     996                 :            : 
     997                 :        105 :   size_t log_write_depth = kDefaultWriteDepth;
     998                 :            : 
     999         [ +  + ]:        105 :   if (!log_depth.empty()) {
    1000                 :          4 :     std::from_chars(log_depth.data(), log_depth.data() + log_depth.size(), log_write_depth);
    1001                 :            :   }
    1002                 :            : 
    1003                 :        105 :   LoggerBackend::Config config;
    1004                 :        105 :   config.app_name = global_instance.app_name;
    1005                 :        105 :   config.log_path = global_instance.log_path;
    1006                 :        105 :   config.max_file_size = log_max_size;
    1007                 :        105 :   config.max_files = log_max_count;
    1008                 :        105 :   config.queue_size = log_write_depth;
    1009                 :        105 :   config.flush_interval_ms = log_flush_delay_ms > 0 ? static_cast<uint32_t>(log_flush_delay_ms) : 0U;
    1010                 :        105 :   config.fixed_filename = log_strategy == "1";
    1011                 :        105 :   config.append = log_append == "1";
    1012                 :        105 :   config.block_when_full = log_block == "1";
    1013                 :        105 :   config.use_utc = global_instance.utc_enable.load(std::memory_order_acquire);
    1014                 :            : 
    1015                 :            :   try {
    1016         [ +  - ]:        210 :     impl_->backend = std::make_unique<LoggerBackend>(std::move(config), [this](std::string_view message) {
    1017                 :          1 :       impl_->disk_emergency.store(true, std::memory_order_release);
    1018                 :          1 :       std::cerr << "VLink logger disk emergency: " << message << std::endl;
    1019                 :        105 :     });
    1020         [ -  - ]:          0 :   } catch (const std::exception& error) {
    1021                 :          0 :     impl_->disk_emergency.store(true, std::memory_order_release);
    1022                 :          0 :     std::cerr << "VLink logger disk emergency: " << error.what() << std::endl;
    1023                 :          0 :   }
    1024                 :            : 
    1025                 :            : #elif defined(__ANDROID__)
    1026                 :            : #elif defined(__QNX__)
    1027                 :            :   slog2_buffer_set_config_t buffer_cfg;
    1028                 :            : 
    1029                 :            :   buffer_cfg.num_buffers = 1;
    1030                 :            :   buffer_cfg.buffer_set_name = "vlink-log";
    1031                 :            :   buffer_cfg.verbosity_level = SLOG2_DEBUG2;
    1032                 :            :   buffer_cfg.buffer_config[0].buffer_name = global_instance.app_name.c_str();
    1033                 :            :   buffer_cfg.buffer_config[0].num_pages = 32;
    1034                 :            :   buffer_cfg.max_retries = 3;
    1035                 :            : 
    1036                 :            :   if VUNLIKELY (slog2_register(&buffer_cfg, &impl_->slog2_buffer, 0) != 0) {
    1037                 :            :     impl_->disk_emergency.store(true, std::memory_order_release);
    1038                 :            :     std::cerr << "Failed to register slog2 buffer" << std::endl;
    1039                 :            :   } else {
    1040                 :            :     slog2_set_default_buffer(impl_->slog2_buffer);
    1041                 :            :   }
    1042                 :            : 
    1043                 :            : #elif defined(__linux__)
    1044                 :            :   impl_->kmsg_dev.open(VLINK_KMSG_DEV_PATH, std::ofstream::out | std::ofstream::app);
    1045                 :            : 
    1046                 :            :   std::error_code ec(errno, std::generic_category());
    1047                 :            : 
    1048                 :            :   if VUNLIKELY (!impl_->kmsg_dev.is_open()) {
    1049                 :            :     impl_->disk_emergency.store(true, std::memory_order_release);
    1050                 :            :     std::cerr << "Failed to open " << VLINK_KMSG_DEV_PATH << ": " << ec.message() << std::endl;
    1051                 :            : 
    1052                 :            :     return;
    1053                 :            :   }
    1054                 :            : 
    1055                 :            : #endif
    1056                 :            : 
    1057                 :        105 :   impl_->is_enable_file_channel.store(true, std::memory_order_release);
    1058                 :        105 : }
    1059                 :            : 
    1060                 :        106 : void Logger::initialize_plugin() noexcept {
    1061   [ +  +  +  -  :        106 :   if VUNLIKELY (!impl_->plugin_name.empty() &&
                   +  + ]
    1062                 :            :                 impl_->plugin_init_state.load(std::memory_order_acquire) != Impl::PluginInitState::kComplete) {
    1063                 :          1 :     auto expected = Impl::PluginInitState::kPending;
    1064                 :            : 
    1065         [ +  - ]:          1 :     if (impl_->plugin_init_state.compare_exchange_strong(expected, Impl::PluginInitState::kInitializing,
    1066                 :            :                                                          std::memory_order_acq_rel, std::memory_order_acquire)) {
    1067                 :          1 :       auto& global_instance = LoggerGlobal::get();
    1068                 :          1 :       bool plugin_inited = false;
    1069                 :            : 
    1070                 :          1 :       global_instance.is_busy.store(true, std::memory_order_release);
    1071                 :          1 :       impl_->plugin.set_log_level(kOff);
    1072                 :          1 :       impl_->interface = impl_->plugin.load<LoggerPluginInterface>(impl_->plugin_name, 1, 0);
    1073                 :            : 
    1074         [ -  + ]:          1 :       if (impl_->interface) {
    1075                 :          0 :         plugin_inited = impl_->interface->init(global_instance.app_name);
    1076                 :            :       }
    1077                 :            : 
    1078         [ -  + ]:          1 :       if (plugin_inited) {
    1079   [ #  #  #  # ]:          0 :         static Logger::Impl::PluginFinalizer plugin_finalizer{*this};
    1080                 :            :         (void)plugin_finalizer;
    1081                 :            : 
    1082                 :          0 :         impl_->is_enable_file_channel.store(true, std::memory_order_release);
    1083                 :          0 :         std::cout << "Successfully loaded plugin for env 'VLINK_LOG_PLUGIN', libname: " << impl_->plugin_name
    1084                 :          0 :                   << std::endl;
    1085                 :            : 
    1086         [ #  # ]:          0 :         if (kInfo >= global_instance.file_level.load(std::memory_order_acquire)) {
    1087                 :          0 :           write_to_file(kInfo, global_instance.version_log);
    1088                 :            :         }
    1089                 :            :       } else {
    1090                 :          1 :         impl_->interface.reset();
    1091                 :          1 :         impl_->plugin.clear();
    1092                 :          1 :         std::cerr << "Failed to load plugin for env 'VLINK_LOG_PLUGIN', libname: " << impl_->plugin_name << std::endl;
    1093                 :            :       }
    1094                 :            : 
    1095                 :          1 :       global_instance.is_busy.store(false, std::memory_order_release);
    1096                 :          1 :       impl_->plugin_init_state.store(Impl::PluginInitState::kComplete, std::memory_order_release);
    1097                 :            :     }
    1098                 :            :   }
    1099                 :        106 : }
    1100                 :            : 
    1101                 :        789 : void Logger::write_to_console(Level level, std::string_view log, bool formatted) noexcept {
    1102   [ +  +  +  - ]:        789 :   static auto& global_instance = LoggerGlobal::get();
    1103                 :            : 
    1104         [ +  + ]:        789 :   if VUNLIKELY (global_instance.has_console_callback.load(std::memory_order_acquire)) {
    1105                 :         49 :     std::shared_lock callback_lock(global_instance.callback_mtx);
    1106                 :            : 
    1107         [ +  - ]:         49 :     if (global_instance.console_callback) {
    1108                 :         49 :       auto& is_logging = is_logging_on_current_thread();
    1109                 :         49 :       auto& is_in_handler = is_in_handler_on_current_thread();
    1110                 :         49 :       const bool was_logging = is_logging;
    1111                 :         49 :       const bool was_in_handler = is_in_handler;
    1112                 :            : 
    1113                 :         49 :       is_logging = true;
    1114                 :         49 :       is_in_handler = true;
    1115                 :            : 
    1116                 :            :       try {
    1117         [ +  + ]:         49 :         global_instance.console_callback(level, log);
    1118         [ +  - ]:          1 :       } catch (const std::exception& error) {
    1119                 :          1 :         std::cerr << "VLink console logger handler failed: " << error.what() << std::endl;
    1120                 :            :       } catch (...) {                                                     // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1121                 :            :         std::cerr << "VLink console logger handler failed" << std::endl;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1122                 :          0 :       }
    1123                 :            : 
    1124                 :         49 :       is_in_handler = was_in_handler;
    1125                 :         49 :       is_logging = was_logging;
    1126                 :            : 
    1127                 :         49 :       callback_lock.unlock();
    1128                 :         49 :       install_pending_handlers();
    1129                 :            : 
    1130                 :         49 :       return;
    1131                 :            :     }
    1132         [ -  + ]:         49 :   }
    1133                 :            : 
    1134   [ +  +  +  +  :        740 :   if VUNLIKELY (!formatted && global_instance.console_format_enable.load(std::memory_order_acquire)) {
                   +  + ]
    1135                 :         84 :     std::string fallback_log;
    1136                 :         84 :     std::optional<CachedTimestamp> fallback_timestamp;
    1137                 :            : 
    1138         [ -  + ]:         84 :     auto& fmt_log = logger_stream_retired ? fallback_log : get_logger_stream_state().console_buffer;
    1139         [ -  + ]:         84 :     auto& timestamp = logger_stream_retired ? fallback_timestamp.emplace() : get_logger_stream_state().timestamp;
    1140                 :            : 
    1141                 :         84 :     fmt_log.clear();
    1142                 :            : 
    1143                 :         84 :     auto tid_str = get_thread_id_str();
    1144                 :            : 
    1145         [ +  + ]:         84 :     if VUNLIKELY (global_instance.utc_enable.load(std::memory_order_acquire)) {
    1146                 :         67 :       fmt_log.append(timestamp.get("%02d-%02d %02d:%02d:%02d.%03d", true));
    1147                 :         67 :       fmt_log.append(" UTC");
    1148                 :            :     } else {
    1149                 :         17 :       fmt_log.append(timestamp.get());
    1150                 :            :     }
    1151                 :            : 
    1152                 :         84 :     fmt_log.append(" @");
    1153                 :         84 :     fmt_log.append(tid_str);
    1154                 :         84 :     fmt_log.append(" - ");
    1155                 :         84 :     fmt_log.append(get_log_level_str(level).data());
    1156                 :         84 :     fmt_log.append(" - ");
    1157                 :            : 
    1158                 :         84 :     fmt_log.append(log);
    1159                 :            : 
    1160                 :         84 :     write_to_console_line(level, fmt_log);
    1161                 :         84 :   } else {
    1162                 :        656 :     write_to_console_line(level, log);
    1163                 :            :   }
    1164                 :            : }
    1165                 :            : 
    1166                 :        740 : void Logger::write_to_console_line(Level level, std::string_view log) noexcept {
    1167   [ +  +  +  - ]:        740 :   static auto& global_instance = LoggerGlobal::get();
    1168                 :        740 :   const bool console_in_order = global_instance.console_in_order.load(std::memory_order_acquire);
    1169                 :            : 
    1170   [ +  +  +  +  :        740 :   switch (level) {
             +  +  -  - ]
    1171                 :          2 :     case kTrace:
    1172                 :          2 :       print_with_color("", log, "\n", stdout, console_in_order, false);
    1173                 :          2 :       return;
    1174                 :          4 :     case kDebug:
    1175                 :          4 :       print_with_color("", log, "\n", stdout, console_in_order, true);
    1176                 :          4 :       return;
    1177                 :        160 :     case kInfo:
    1178                 :        160 :       print_with_color("\033[32m", log, "\033[0m\n", stdout, console_in_order, true);
    1179                 :        160 :       return;
    1180                 :        272 :     case kWarn:
    1181                 :        272 :       print_with_color("\033[33m", log, "\033[0m\n", stderr, console_in_order, true);
    1182                 :        272 :       return;
    1183                 :        168 :     case kError:
    1184                 :        168 :       print_with_color("\033[31m", log, "\033[0m\n", stderr, console_in_order, true);
    1185                 :        168 :       return;
    1186                 :        134 :     case kFatal:
    1187                 :        134 :       print_with_color("\033[41;37;1m", log, "\033[0m\n", stderr, console_in_order, true);
    1188                 :        134 :       return;
    1189                 :            :     // LCOV_EXCL_START GCOVR_EXCL_START
    1190                 :            :     case kOff:
    1191                 :            :       return;
    1192                 :            :     default:
    1193                 :            :       return;
    1194                 :            :       // LCOV_EXCL_STOP GCOVR_EXCL_STOP
    1195                 :            :   }
    1196                 :            : }
    1197                 :            : 
    1198                 :       4917 : void Logger::write_to_file(Level level, std::string_view log) noexcept {
    1199   [ +  +  +  - ]:       4917 :   static auto& global_instance = LoggerGlobal::get();
    1200                 :            : 
    1201         [ +  + ]:       4917 :   if VUNLIKELY (global_instance.has_file_callback.load(std::memory_order_acquire)) {
    1202                 :          6 :     std::shared_lock callback_lock(global_instance.callback_mtx);
    1203                 :            : 
    1204         [ +  - ]:          6 :     if (global_instance.file_callback) {
    1205                 :          6 :       auto& is_logging = is_logging_on_current_thread();
    1206                 :          6 :       auto& is_in_handler = is_in_handler_on_current_thread();
    1207                 :          6 :       const bool was_logging = is_logging;
    1208                 :          6 :       const bool was_in_handler = is_in_handler;
    1209                 :            : 
    1210                 :          6 :       is_logging = true;
    1211                 :          6 :       is_in_handler = true;
    1212                 :            : 
    1213                 :            :       try {
    1214         [ +  - ]:          6 :         global_instance.file_callback(level, log);
    1215         [ -  - ]:          0 :       } catch (const std::exception& error) {
    1216                 :          0 :         std::cerr << "VLink file logger handler failed: " << error.what() << std::endl;
    1217                 :            :       } catch (...) {                                                  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1218                 :            :         std::cerr << "VLink file logger handler failed" << std::endl;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1219                 :          0 :       }
    1220                 :            : 
    1221                 :          6 :       is_in_handler = was_in_handler;
    1222                 :          6 :       is_logging = was_logging;
    1223                 :            : 
    1224                 :          6 :       callback_lock.unlock();
    1225                 :          6 :       install_pending_handlers();
    1226                 :            : 
    1227                 :          6 :       return;
    1228                 :            :     }
    1229         [ -  + ]:          6 :   }
    1230                 :            : 
    1231         [ +  + ]:       4911 :   if VUNLIKELY (!impl_->is_enable_file_channel.load(std::memory_order_acquire)) {
    1232                 :          1 :     return;
    1233                 :            :   }
    1234                 :            : 
    1235         [ -  + ]:       4910 :   if VUNLIKELY (impl_->interface) {
    1236                 :          0 :     auto& is_plugin_logging = is_plugin_logging_on_current_thread();
    1237                 :            : 
    1238         [ #  # ]:          0 :     if VUNLIKELY (is_plugin_logging) {
    1239                 :          0 :       return;
    1240                 :            :     }
    1241                 :            : 
    1242                 :          0 :     is_plugin_logging = true;
    1243                 :          0 :     impl_->interface->log(level, log);
    1244                 :          0 :     is_plugin_logging = false;
    1245                 :            : 
    1246                 :          0 :     return;
    1247                 :            :   }
    1248                 :            : 
    1249         [ +  + ]:       4910 :   if VUNLIKELY (impl_->disk_emergency.load(std::memory_order_acquire)) {
    1250                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1251                 :            :   }
    1252                 :            : 
    1253                 :            : #if defined(VLINK_ENABLE_LOG_BACKEND)
    1254   [ +  -  -  +  :       4908 :   if VUNLIKELY (!impl_->backend || !impl_->backend->log(level, log)) {
                   -  + ]
    1255   [ #  #  #  #  :          0 :     if (impl_->backend && impl_->backend->has_error()) {
                   #  # ]
    1256                 :          0 :       impl_->disk_emergency.store(true, std::memory_order_release);
    1257                 :            :     }
    1258                 :            :   }
    1259                 :            : 
    1260                 :            : #elif defined(__ANDROID__)
    1261                 :            : 
    1262                 :            :   int android_level = ANDROID_LOG_DEBUG;
    1263                 :            :   switch (level) {
    1264                 :            :     case kTrace:
    1265                 :            :       android_level = ANDROID_LOG_VERBOSE;
    1266                 :            :       break;
    1267                 :            :     case kDebug:
    1268                 :            :       android_level = ANDROID_LOG_DEBUG;
    1269                 :            :       break;
    1270                 :            :     case kInfo:
    1271                 :            :       android_level = ANDROID_LOG_INFO;
    1272                 :            :       break;
    1273                 :            :     case kWarn:
    1274                 :            :       android_level = ANDROID_LOG_WARN;
    1275                 :            :       break;
    1276                 :            :     case kError:
    1277                 :            :       android_level = ANDROID_LOG_ERROR;
    1278                 :            :       break;
    1279                 :            :     case kFatal:
    1280                 :            :       android_level = ANDROID_LOG_FATAL;
    1281                 :            :       break;
    1282                 :            :     case kOff:
    1283                 :            :       return;
    1284                 :            :     default:
    1285                 :            :       return;
    1286                 :            :   }
    1287                 :            : 
    1288                 :            :   __android_log_write(android_level, global_instance.app_name.c_str(), log.data());
    1289                 :            : 
    1290                 :            : #elif defined(__QNX__)
    1291                 :            :   int platform_level = SLOG2_DEBUG1;
    1292                 :            :   switch (level) {
    1293                 :            :     case kTrace:
    1294                 :            :       platform_level = SLOG2_DEBUG2;
    1295                 :            :       break;
    1296                 :            :     case kDebug:
    1297                 :            :       platform_level = SLOG2_DEBUG1;
    1298                 :            :       break;
    1299                 :            :     case kInfo:
    1300                 :            :       platform_level = SLOG2_INFO;
    1301                 :            :       break;
    1302                 :            :     case kWarn:
    1303                 :            :       platform_level = SLOG2_WARNING;
    1304                 :            :       break;
    1305                 :            :     case kError:
    1306                 :            :       platform_level = SLOG2_ERROR;
    1307                 :            :       break;
    1308                 :            :     case kFatal:
    1309                 :            :       platform_level = SLOG2_CRITICAL;
    1310                 :            :       break;
    1311                 :            :     case kOff:
    1312                 :            :       return;
    1313                 :            :     default:
    1314                 :            :       return;
    1315                 :            :   }
    1316                 :            : 
    1317                 :            :   slog2c(impl_->slog2_buffer, ::gettid(), platform_level, log.data());
    1318                 :            : 
    1319                 :            : #elif defined(__linux__)
    1320                 :            : 
    1321                 :            :   if (impl_->kmsg_dev.is_open()) {
    1322                 :            :     std::lock_guard lock(impl_->file_mtx);
    1323                 :            : 
    1324                 :            :     switch (level) {
    1325                 :            :       case kTrace:
    1326                 :            :         impl_->kmsg_dev << "<7>";
    1327                 :            :         break;
    1328                 :            :       case kDebug:
    1329                 :            :         impl_->kmsg_dev << "<6>";
    1330                 :            :         break;
    1331                 :            :       case kInfo:
    1332                 :            :         impl_->kmsg_dev << "<5>";
    1333                 :            :         break;
    1334                 :            :       case kWarn:
    1335                 :            :         impl_->kmsg_dev << "<4>";
    1336                 :            :         break;
    1337                 :            :       case kError:
    1338                 :            :         impl_->kmsg_dev << "<3>";
    1339                 :            :         break;
    1340                 :            :       case kFatal:
    1341                 :            :         impl_->kmsg_dev << "<2>";
    1342                 :            :         break;
    1343                 :            :       case kOff:
    1344                 :            :         return;
    1345                 :            :       default:
    1346                 :            :         return;
    1347                 :            :     }
    1348                 :            : 
    1349                 :            :     impl_->kmsg_dev << log << std::endl;
    1350                 :            :   }
    1351                 :            : 
    1352                 :            : #endif
    1353                 :            : }
    1354                 :            : 
    1355                 :            : }  // namespace vlink

Generated by: LCOV version 1.14