LCOV - code coverage report
Current view: top level - src/base - logger.cc (source / functions) Hit Total Coverage
Test: vlink Lines: 411 415 99.0 %
Date: 2026-06-27 19:56:04 Functions: 39 40 97.5 %
Branches: 249 328 75.9 %

           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 <cstdio>
      29                 :            : #include <filesystem>
      30                 :            : #include <fstream>
      31                 :            : #include <iostream>
      32                 :            : #include <memory>
      33                 :            : #include <mutex>
      34                 :            : #include <shared_mutex>
      35                 :            : #include <string>
      36                 :            : #include <utility>
      37                 :            : #include <vector>
      38                 :            : 
      39                 :            : #include "./base/cached_timestamp.h"
      40                 :            : #include "./base/logger_plugin_interface.h"
      41                 :            : #include "./base/utils.h"
      42                 :            : #include "./vlink/version.h"
      43                 :            : 
      44                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
      45                 :            : 
      46                 :            : #define SPDLOG_LEVEL_NAMES                                                                                     \
      47                 :            :   {                                                                                                            \
      48                 :            :       spdlog::string_view_t("TRACE", 5), spdlog::string_view_t("DEBUG", 5), spdlog::string_view_t("INFO ", 5), \
      49                 :            :       spdlog::string_view_t("WARN ", 5), spdlog::string_view_t("ERROR", 5), spdlog::string_view_t("FATAL", 5), \
      50                 :            :       spdlog::string_view_t("EMPTY", 5),                                                                       \
      51                 :            :   }
      52                 :            : 
      53                 :            : #define SPDLOG_SHORT_LEVEL_NAMES {"T", "D", "I", "W", "E", "F", " "}
      54                 :            : 
      55                 :            : #include <spdlog/async.h>
      56                 :            : #include <spdlog/sinks/rotating_file_sink.h>
      57                 :            : #include <spdlog/sinks/stdout_color_sinks.h>
      58                 :            : #include <spdlog/spdlog.h>
      59                 :            : 
      60                 :            : #include "./private/spdlog_time_rolling_file_sink.h"
      61                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
      62                 :            : #include <quill/Backend.h>
      63                 :            : #include <quill/Frontend.h>
      64                 :            : #include <quill/LogMacros.h>
      65                 :            : #include <quill/Logger.h>
      66                 :            : #include <quill/sinks/ConsoleSink.h>
      67                 :            : #include <quill/sinks/RotatingFileSink.h>
      68                 :            : #elif defined(VLINK_ENABLE_LOG_DLT)
      69                 :            : #include <dlt/dlt.h>
      70                 :            : DLT_DECLARE_CONTEXT(dlt_global_ctx_);
      71                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__ANDROID__)
      72                 :            : #include <android/log.h>
      73                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__QNX__)
      74                 :            : #include <process.h>
      75                 :            : #include <sys/slog2.h>
      76                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__linux__)
      77                 :            : #include <linux/kernel.h>
      78                 :            : #define VLINK_KMSG_DEV_PATH "/dev/kmsg"
      79                 :            : #endif
      80                 :            : 
      81                 :            : namespace vlink {
      82                 :            : 
      83                 :            : [[maybe_unused]] static constexpr size_t kDefaultWriteDepth = 1024L * 8;
      84                 :            : [[maybe_unused]] static constexpr size_t kDefaultLogMaxSize = 1024L * 1024L * 10U;
      85                 :            : [[maybe_unused]] static constexpr size_t kDefaultLogMaxCount = 10U;
      86                 :            : [[maybe_unused]] static constexpr int kDefaultLogFlushDelay = 500;
      87                 :            : 
      88                 :         87 : [[maybe_unused]] static std::string get_current_date(bool use_utc = false) {
      89                 :         87 :   auto now = std::chrono::system_clock::now();
      90                 :         87 :   std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
      91                 :         87 :   std::tm now_tm{};
      92                 :            : 
      93                 :            : #if defined(_WIN32)
      94                 :            : 
      95                 :            :   if (use_utc) {
      96                 :            :     gmtime_s(&now_tm, &now_time_t);
      97                 :            :   } else {
      98                 :            :     localtime_s(&now_tm, &now_time_t);
      99                 :            :   }
     100                 :            : #else
     101                 :            : 
     102         [ +  + ]:         87 :   if (use_utc) {
     103                 :          1 :     gmtime_r(&now_time_t, &now_tm);
     104                 :            :   } else {
     105                 :         86 :     localtime_r(&now_time_t, &now_tm);
     106                 :            :   }
     107                 :            : #endif
     108                 :            : 
     109                 :            :   char buffer[32];
     110                 :         87 :   std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &now_tm);
     111         [ +  - ]:         87 :   return std::string(buffer);
     112                 :            : }
     113                 :            : 
     114                 :         29 : [[maybe_unused]] static std::string_view get_current_time(bool use_utc = false) {
     115         [ +  + ]:         29 :   thread_local CachedTimestamp cache;
     116                 :         29 :   return cache.get("%02d-%02d %02d:%02d:%02d.%03d", use_utc);
     117                 :            : }
     118                 :            : 
     119                 :         29 : [[maybe_unused]] static constexpr std::string_view get_log_level_str(Logger::Level level) {
     120   [ +  +  +  +  :         29 :   switch (level) {
             +  +  -  - ]
     121                 :          2 :     case Logger::kTrace:
     122                 :          2 :       return "TRACE";
     123                 :          6 :     case Logger::kDebug:
     124                 :          6 :       return "DEBUG";
     125                 :          6 :     case Logger::kInfo:
     126                 :          6 :       return "INFO ";
     127                 :          6 :     case Logger::kWarn:
     128                 :          6 :       return "WARN ";
     129                 :          6 :     case Logger::kError:
     130                 :          6 :       return "ERROR";
     131                 :          3 :     case Logger::kFatal:
     132                 :          3 :       return "FATAL";
     133                 :            :     // LCOV_EXCL_START GCOVR_EXCL_START
     134                 :            :     case Logger::kOff:
     135                 :            :       return "EMPTY";
     136                 :            :     default:
     137                 :            :       return "EMPTY";
     138                 :            :       // LCOV_EXCL_STOP GCOVR_EXCL_STOP
     139                 :            :   }
     140                 :            : }
     141                 :            : 
     142                 :        291 : [[maybe_unused]] static int get_log_level(const std::string& key) {
     143         [ +  - ]:        582 :   std::string str_value = Utils::get_env(key);
     144                 :            : 
     145         [ +  + ]:        291 :   if (str_value.empty()) {
     146                 :        265 :     return -1;
     147                 :            :   }
     148                 :            : 
     149   [ +  +  +  -  :         26 :   if (str_value == "Trace" || str_value == "TRACE" || str_value == "trace") {
             -  +  +  + ]
     150                 :          4 :     return Logger::kTrace;
     151   [ +  -  +  +  :         22 :   } else if (str_value == "Debug" || str_value == "DEBUG" || str_value == "debug") {
             -  +  +  + ]
     152                 :          1 :     return Logger::kDebug;
     153   [ +  +  +  -  :         21 :   } else if (str_value == "Info" || str_value == "INFO" || str_value == "info") {
             +  +  +  + ]
     154                 :          2 :     return Logger::kInfo;
     155   [ +  +  +  -  :         19 :   } else if (str_value == "Warn" || str_value == "WARN" || str_value == "warn") {
             -  +  +  + ]
     156                 :          1 :     return Logger::kWarn;
     157   [ +  -  +  +  :         18 :   } else if (str_value == "Error" || str_value == "ERROR" || str_value == "error") {
             -  +  +  + ]
     158                 :          1 :     return Logger::kError;
     159   [ +  -  +  -  :         17 :   } else if (str_value == "Fatal" || str_value == "FATAL" || str_value == "fatal") {
             +  +  +  + ]
     160                 :          1 :     return Logger::kFatal;
     161   [ +  +  +  -  :         16 :   } else if (str_value == "Off" || str_value == "OFF" || str_value == "off") {
             -  +  +  + ]
     162                 :         13 :     return Logger::kOff;
     163                 :            :   }
     164                 :            : 
     165                 :          3 :   int value = -1;
     166                 :            : 
     167         [ +  - ]:          3 :   auto [p, error] = std::from_chars(str_value.data(), str_value.data() + str_value.size(), value);
     168                 :            : 
     169         [ +  + ]:          3 :   if VUNLIKELY (error != std::errc()) {
     170                 :          1 :     return -1;
     171                 :            :   }
     172                 :            : 
     173   [ +  -  +  +  :          2 :   if VUNLIKELY (value < 0 || value > Logger::kOff) {
                   +  + ]
     174                 :          1 :     return Logger::kOff;
     175                 :            :   }
     176                 :            : 
     177                 :          1 :   return value;
     178                 :        291 : }
     179                 :            : 
     180                 :         29 : [[maybe_unused]] static std::string_view get_thread_id_str() {
     181                 :            :   thread_local char buffer[32];
     182                 :            :   thread_local bool initialized = false;
     183                 :            : 
     184         [ +  + ]:         29 :   if VUNLIKELY (!initialized) {
     185         [ +  - ]:          2 :     auto [p, ec] = std::to_chars(buffer, buffer + sizeof(buffer) - 1, Utils::get_native_thread_id());
     186                 :            : 
     187         [ +  - ]:          2 :     if (ec == std::errc()) {
     188                 :          2 :       *p = '\0';
     189                 :            :     } else {
     190                 :            :       std::snprintf(  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     191                 :            :           buffer, sizeof(buffer), "%llu",
     192                 :          0 :           static_cast<unsigned long long>(Utils::get_native_thread_id()));  // NOLINT(runtime/int, google-runtime-int)
     193                 :            :                                                                             // // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     194                 :            :     }
     195                 :            : 
     196                 :          2 :     initialized = true;
     197                 :            :   }
     198                 :            : 
     199                 :         29 :   return buffer;
     200                 :            : }
     201                 :            : 
     202                 :        515 : [[maybe_unused]] static std::mutex& get_print_mtx() {
     203                 :            :   static std::mutex print_mtx;
     204                 :        515 :   return print_mtx;
     205                 :            : }
     206                 :            : 
     207                 :            : template <uint8_t PrefixSizeT, uint8_t SuffixSizeT>
     208                 :        515 : [[maybe_unused]] static void print_with_color(const char (&prefix)[PrefixSizeT], std::string_view log,
     209                 :            :                                               const char (&suffix)[SuffixSizeT], FILE* file, bool in_order,
     210                 :            :                                               bool force_flush) {
     211                 :        515 :   std::unique_lock lock(get_print_mtx(), std::defer_lock);
     212                 :            : 
     213         [ +  + ]:        515 :   if (in_order) {
     214         [ +  - ]:        509 :     lock.lock();
     215                 :            :   }
     216                 :            : 
     217                 :            :   if constexpr (PrefixSizeT > 1) {
     218         [ +  - ]:        505 :     std::fwrite(prefix, sizeof(char), PrefixSizeT - 1, file);
     219                 :            :   }
     220                 :            : 
     221         [ +  - ]:        515 :   if VLIKELY (!log.empty()) {
     222         [ +  - ]:        515 :     std::fwrite(log.data(), sizeof(char), log.size(), file);
     223                 :            :   }
     224                 :            : 
     225                 :            :   if constexpr (SuffixSizeT > 1) {
     226         [ +  - ]:        515 :     std::fwrite(suffix, sizeof(char), SuffixSizeT - 1, file);
     227                 :            :   }
     228                 :            : 
     229   [ +  +  +  + ]:        515 :   if (in_order && force_flush) {
     230         [ +  - ]:        507 :     std::fflush(file);
     231                 :            :   }
     232                 :        515 : }
     233                 :            : 
     234                 :            : // LoggerGlobal
     235                 :            : struct LoggerGlobal final {  // NOLINT(clang-analyzer-optin.performance.Padding)
     236                 :            :   std::atomic_bool is_busy{false};
     237                 :            : 
     238                 :            :   std::string app_name;
     239                 :            :   std::string log_path;
     240                 :            :   std::string version_log;
     241                 :            :   std::atomic<int> console_level{Logger::kDebug};
     242                 :            :   std::atomic<int> file_level{Logger::kDebug};
     243                 :            :   std::atomic_bool console_in_order{true};
     244                 :            :   std::atomic_bool console_level_by_user{false};
     245                 :            :   std::atomic_bool file_level_by_user{false};
     246                 :            :   std::atomic_bool console_format_enable{false};
     247                 :            :   std::atomic_bool utc_enable{false};
     248                 :            :   // Protected by callback_mtx (shared on read/invoke, exclusive on register).
     249                 :            :   Logger::Callback console_callback;
     250                 :            :   Logger::Callback file_callback;
     251                 :            :   mutable std::shared_mutex callback_mtx;
     252                 :            :   std::atomic<std::ios_base::fmtflags> stream_flags{std::ios_base::dec | std::ios_base::skipws};
     253                 :            :   std::atomic<int> stream_precision{6};
     254                 :            :   std::atomic<int> stream_width{0};
     255                 :            : 
     256                 :        490 :   static LoggerGlobal& get() {
     257   [ +  +  +  - ]:        490 :     static LoggerGlobal instance;
     258                 :        490 :     return instance;
     259                 :            :   }
     260                 :            : 
     261                 :            :  private:
     262                 :         98 :   LoggerGlobal() = default;
     263                 :            : };
     264                 :            : 
     265                 :            : // Logger::Impl
     266                 :            : struct Logger::Impl final {  // NOLINT(clang-analyzer-optin.performance.Padding)
     267                 :            :   std::atomic_bool disk_emergency{false};
     268                 :            :   std::atomic_bool is_enable_backtrace{false};
     269                 :            : 
     270                 :            :   bool is_enable_file_channel{false};
     271                 :            :   Plugin plugin;
     272                 :            :   std::shared_ptr<LoggerPluginInterface> interface;
     273                 :            : 
     274                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
     275                 :            :   std::shared_ptr<spdlog::logger> spd;
     276                 :            :   std::shared_ptr<spdlog::sinks::sink> spd_console_sink;
     277                 :            :   std::shared_ptr<spdlog::sinks::sink> spd_file_sink;
     278                 :            :   std::shared_ptr<spdlog::details::thread_pool> spd_thread_pool;
     279                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
     280                 :            :   quill::Logger* quill_log{nullptr};
     281                 :            :   std::shared_ptr<quill::StreamSink> quill_console_sink;
     282                 :            :   std::shared_ptr<quill::StreamSink> quill_file_sink;
     283                 :            :   quill::MacroMetadata quill_metadata_trace{
     284                 :            :       "", "", "{}", nullptr, quill::LogLevel::TraceL1, quill::MacroMetadata::Event::Log};
     285                 :            :   quill::MacroMetadata quill_metadata_debug{
     286                 :            :       "", "", "{}", nullptr, quill::LogLevel::Debug, quill::MacroMetadata::Event::Log};
     287                 :            :   quill::MacroMetadata quill_metadata_info{
     288                 :            :       "", "", "{}", nullptr, quill::LogLevel::Info, quill::MacroMetadata::Event::Log};
     289                 :            :   quill::MacroMetadata quill_metadata_warn{
     290                 :            :       "", "", "{}", nullptr, quill::LogLevel::Warning, quill::MacroMetadata::Event::Log};
     291                 :            :   quill::MacroMetadata quill_metadata_error{
     292                 :            :       "", "", "{}", nullptr, quill::LogLevel::Error, quill::MacroMetadata::Event::Log};
     293                 :            :   quill::MacroMetadata quill_metadata_fatal{
     294                 :            :       "", "", "{}", nullptr, quill::LogLevel::Critical, quill::MacroMetadata::Event::Log};
     295                 :            :   quill::MacroMetadata quill_metadata_backtrace{
     296                 :            :       "", "", "{}", nullptr, quill::LogLevel::Backtrace, quill::MacroMetadata::Event::Log};
     297                 :            : #elif defined(VLINK_ENABLE_LOG_DLT)
     298                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__ANDROID__)
     299                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__QNX__)
     300                 :            :   slog2_buffer_t slog2_buffer{nullptr};
     301                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__linux__)
     302                 :            :   std::ofstream kmsg_dev;
     303                 :            :   std::mutex file_mtx;
     304                 :            : #endif
     305                 :            : };
     306                 :            : 
     307                 :            : // Logger
     308                 :         40 : void Logger::init(const std::string& app_name, const std::string& log_path) noexcept {
     309   [ +  +  +  - ]:         40 :   static auto& global_instance = LoggerGlobal::get();
     310                 :            : 
     311         [ +  - ]:         40 :   if (!app_name.empty()) {
     312                 :         40 :     global_instance.app_name = app_name;
     313         [ +  + ]:         40 :     if (!log_path.empty()) {
     314                 :          1 :       global_instance.log_path = log_path;
     315                 :            :     }
     316                 :            :   }
     317                 :            : 
     318                 :         40 :   Logger::get();
     319                 :         40 : }
     320                 :            : 
     321                 :       1840 : Logger& Logger::get() noexcept {
     322   [ +  +  +  - ]:       1840 :   static Logger instance;
     323                 :            : 
     324                 :       1840 :   return instance;
     325                 :            : }
     326                 :            : 
     327                 :        143 : void Logger::flush() noexcept {
     328   [ +  +  +  - ]:        143 :   static Logger& instance = Logger::get();
     329                 :            : 
     330         [ +  + ]:        143 :   if (!instance.impl_->is_enable_file_channel) {
     331                 :          1 :     return;
     332                 :            :   }
     333                 :            : 
     334         [ -  + ]:        142 :   if VUNLIKELY (instance.impl_->disk_emergency.load(std::memory_order_acquire)) {
     335                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     336                 :            :   }
     337                 :            : 
     338                 :            :   try {
     339                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
     340         [ +  - ]:        142 :     instance.impl_->spd->flush();
     341                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
     342                 :            :     quill::Backend::notify();
     343                 :            :     instance.impl_->quill_file_sink->flush_sink();
     344                 :            : #endif
     345                 :            :     // LCOV_EXCL_START GCOVR_EXCL_START
     346                 :            :   } catch (std::exception& e) {
     347                 :            :     instance.impl_->disk_emergency.store(true, std::memory_order_release);
     348                 :            :     std::cerr << "VLink logger disk emergency: " << e.what() << std::endl;
     349                 :            :   }
     350                 :            :   // LCOV_EXCL_STOP GCOVR_EXCL_STOP
     351                 :            : }
     352                 :            : 
     353                 :          9 : void Logger::register_console_handler(Callback&& callback) noexcept {
     354                 :          9 :   auto& global_instance = LoggerGlobal::get();
     355                 :            : 
     356                 :          9 :   std::unique_lock lock(global_instance.callback_mtx);
     357                 :            : 
     358                 :          9 :   global_instance.console_callback = std::move(callback);
     359                 :          9 : }
     360                 :            : 
     361                 :          2 : void Logger::register_file_handler(Callback&& callback) noexcept {
     362                 :          2 :   auto& global_instance = LoggerGlobal::get();
     363                 :            : 
     364                 :          2 :   std::unique_lock lock(global_instance.callback_mtx);
     365                 :            : 
     366                 :          2 :   global_instance.file_callback = std::move(callback);
     367                 :          2 : }
     368                 :            : 
     369                 :         31 : void Logger::set_console_level(Level level) noexcept {
     370                 :         31 :   LoggerGlobal::get().console_level.store(level, std::memory_order_release);
     371                 :         31 :   LoggerGlobal::get().console_level_by_user.store(true, std::memory_order_release);
     372                 :         31 : }
     373                 :            : 
     374                 :          9 : void Logger::set_file_level(Level level) noexcept {
     375                 :          9 :   LoggerGlobal::get().file_level.store(level, std::memory_order_release);
     376                 :          9 :   LoggerGlobal::get().file_level_by_user.store(true, std::memory_order_release);
     377                 :          9 : }
     378                 :            : 
     379                 :          4 : void Logger::set_console_fmt_enable(bool enable) noexcept {
     380                 :          4 :   LoggerGlobal::get().console_format_enable.store(enable, std::memory_order_release);
     381                 :          4 : }
     382                 :            : 
     383                 :         15 : Logger::Level Logger::get_console_level() noexcept {
     384                 :         30 :   return static_cast<Logger::Level>(LoggerGlobal::get().console_level.load(std::memory_order_acquire));
     385                 :            : }
     386                 :            : 
     387                 :          6 : Logger::Level Logger::get_file_level() noexcept {
     388                 :         12 :   return static_cast<Logger::Level>(LoggerGlobal::get().file_level.load(std::memory_order_acquire));
     389                 :            : }
     390                 :            : 
     391                 :          3 : bool Logger::get_console_fmt_enable() noexcept {
     392                 :          3 :   return LoggerGlobal::get().console_format_enable.load(std::memory_order_acquire);
     393                 :            : }
     394                 :            : 
     395                 :          2 : void Logger::set_stream_flag(std::ios_base::fmtflags flags) noexcept {
     396                 :          2 :   LoggerGlobal::get().stream_flags.store(flags, std::memory_order_release);
     397                 :          2 : }
     398                 :            : 
     399                 :          2 : void Logger::set_stream_precision(int precision) noexcept {
     400                 :          2 :   LoggerGlobal::get().stream_precision.store(precision, std::memory_order_release);
     401                 :          2 : }
     402                 :            : 
     403                 :          2 : void Logger::set_stream_width(int width) noexcept {
     404                 :          2 :   LoggerGlobal::get().stream_width.store(width, std::memory_order_release);
     405                 :          2 : }
     406                 :            : 
     407                 :          2 : std::ios_base::fmtflags Logger::get_stream_flag() noexcept {
     408                 :          2 :   return LoggerGlobal::get().stream_flags.load(std::memory_order_acquire);
     409                 :            : }
     410                 :            : 
     411                 :          2 : int Logger::get_stream_precision() noexcept {
     412                 :          4 :   return LoggerGlobal::get().stream_precision.load(std::memory_order_acquire);
     413                 :            : }
     414                 :            : 
     415                 :          4 : int Logger::get_stream_width() noexcept { return LoggerGlobal::get().stream_width.load(std::memory_order_acquire); }
     416                 :            : 
     417                 :          3 : void Logger::enable_backtrace(size_t size) noexcept {
     418   [ +  +  +  - ]:          3 :   static Logger& instance = Logger::get();
     419                 :            : 
     420         [ -  + ]:          3 :   if VUNLIKELY (instance.impl_->disk_emergency.load(std::memory_order_acquire)) {
     421                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     422                 :            :   }
     423                 :            : 
     424         [ -  + ]:          3 :   if VUNLIKELY (!instance.impl_->is_enable_file_channel) {
     425                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     426                 :            :   }
     427                 :            : 
     428         [ -  + ]:          3 :   if VUNLIKELY (instance.impl_->interface) {
     429                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     430                 :            :   }
     431                 :            : 
     432                 :            : #if defined(VLINK_ENABLE_LOG_SPD) || defined(VLINK_ENABLE_LOG_QUI)
     433                 :          3 :   bool expected = false;
     434                 :            : 
     435         [ -  + ]:          3 :   if (!instance.impl_->is_enable_backtrace.compare_exchange_strong(
     436                 :            :           expected, true, std::memory_order_acq_rel,  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     437                 :            :           std::memory_order_relaxed)) {
     438                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     439                 :            :   }
     440                 :            : 
     441                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
     442                 :          3 :   instance.impl_->spd_console_sink->set_level(spdlog::level::trace);
     443                 :          3 :   instance.impl_->spd->set_level(spdlog::level::warn);
     444                 :          3 :   instance.impl_->spd->enable_backtrace(size);
     445                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
     446                 :            :   instance.impl_->quill_log->init_backtrace(size, quill::LogLevel::TraceL3);
     447                 :            : #endif
     448                 :            : #else
     449                 :            :   (void)size;
     450                 :            : #endif
     451                 :            : }
     452                 :            : 
     453                 :          3 : void Logger::disable_backtrace() noexcept {
     454   [ +  +  +  - ]:          3 :   static Logger& instance = Logger::get();
     455                 :            : 
     456         [ -  + ]:          3 :   if VUNLIKELY (instance.impl_->disk_emergency.load(std::memory_order_acquire)) {
     457                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     458                 :            :   }
     459                 :            : 
     460                 :          3 :   bool expected = true;
     461                 :            : 
     462         [ -  + ]:          3 :   if (!instance.impl_->is_enable_backtrace.compare_exchange_strong(
     463                 :            :           expected, false, std::memory_order_acq_rel,  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     464                 :            :           std::memory_order_relaxed)) {
     465                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     466                 :            :   }
     467                 :            : 
     468         [ -  + ]:          3 :   if VUNLIKELY (!instance.impl_->is_enable_file_channel) {
     469                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     470                 :            :   }
     471                 :            : 
     472         [ -  + ]:          3 :   if VUNLIKELY (instance.impl_->interface) {
     473                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     474                 :            :   }
     475                 :            : 
     476                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
     477                 :          3 :   instance.impl_->spd->disable_backtrace();
     478                 :          3 :   instance.impl_->spd_console_sink->set_level(spdlog::level::off);
     479                 :          3 :   instance.impl_->spd->set_level(spdlog::level::trace);
     480                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
     481                 :            :   instance.impl_->quill_log->init_backtrace(0, quill::LogLevel::None);
     482                 :            : #else
     483                 :            :   (void)instance;
     484                 :            : #endif
     485                 :            : }
     486                 :            : 
     487                 :          2 : void Logger::dump_backtrace() noexcept {
     488   [ +  -  +  - ]:          2 :   static Logger& instance = Logger::get();
     489                 :            : 
     490         [ -  + ]:          2 :   if VUNLIKELY (instance.impl_->disk_emergency.load(std::memory_order_acquire)) {
     491                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     492                 :            :   }
     493                 :            : 
     494         [ -  + ]:          2 :   if (!instance.impl_->is_enable_backtrace.load(std::memory_order_acquire)) {
     495                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     496                 :            :   }
     497                 :            : 
     498         [ -  + ]:          2 :   if VUNLIKELY (!instance.impl_->is_enable_file_channel) {
     499                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     500                 :            :   }
     501                 :            : 
     502         [ -  + ]:          2 :   if VUNLIKELY (instance.impl_->interface) {
     503                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     504                 :            :   }
     505                 :            : 
     506                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
     507                 :          2 :   instance.impl_->spd->dump_backtrace();
     508                 :          2 :   instance.impl_->spd_console_sink->flush();
     509                 :          2 :   std::this_thread::sleep_for(std::chrono::milliseconds(100));  // wait for dump to console
     510                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
     511                 :            :   instance.impl_->quill_log->flush_backtrace();
     512                 :            : #else
     513                 :            :   (void)instance;
     514                 :            : #endif
     515                 :            : }
     516                 :            : 
     517                 :          1 : bool Logger::is_busy() noexcept { return LoggerGlobal::get().is_busy.load(std::memory_order_acquire); }
     518                 :            : 
     519                 :        519 : bool Logger::is_writable(Level level) noexcept {
     520   [ +  +  +  - ]:        519 :   static auto& global_instance = LoggerGlobal::get();
     521                 :            : 
     522         [ +  + ]:       1167 :   return level >= global_instance.console_level.load(std::memory_order_acquire) ||
     523         [ +  + ]:        777 :          level >= global_instance.file_level.load(std::memory_order_acquire);
     524                 :            : }
     525                 :            : 
     526                 :         97 : Logger::Logger() noexcept : impl_(std::make_unique<Impl>()) {
     527   [ +  -  +  - ]:         97 :   static auto& global_instance = LoggerGlobal::get();
     528                 :            : 
     529                 :         97 :   global_instance.is_busy.store(true, std::memory_order_release);
     530                 :            : 
     531                 :         97 :   int common_level = get_log_level("VLINK_LOG_LEVEL");
     532                 :            : 
     533         [ +  - ]:         97 :   if (!global_instance.console_level_by_user.load(std::memory_order_acquire)) {
     534                 :         97 :     int console_level = get_log_level("VLINK_LOG_CONSOLE_LEVEL");
     535                 :            : 
     536         [ +  + ]:         97 :     if (console_level >= 0) {
     537                 :         12 :       global_instance.console_level.store(console_level, std::memory_order_release);
     538         [ +  + ]:         85 :     } else if (common_level >= 0) {
     539                 :          1 :       global_instance.console_level.store(common_level, std::memory_order_release);
     540                 :            :     }
     541                 :            :   }
     542                 :            : 
     543         [ +  - ]:         97 :   if (!global_instance.file_level_by_user.load(std::memory_order_acquire)) {
     544                 :         97 :     int file_level = get_log_level("VLINK_LOG_FILE_LEVEL");
     545                 :            : 
     546         [ +  + ]:         97 :     if (file_level >= 0) {
     547                 :         11 :       global_instance.file_level.store(file_level, std::memory_order_release);
     548         [ +  + ]:         86 :     } else if (common_level >= 0) {
     549                 :          2 :       global_instance.file_level.store(common_level, std::memory_order_release);
     550                 :            :     }
     551                 :            :   }
     552                 :            : 
     553   [ +  +  +  + ]:        199 :   if (global_instance.console_level.load(std::memory_order_acquire) < kOff ||
     554         [ +  + ]:         10 :       global_instance.file_level.load(std::memory_order_acquire) < kOff) {
     555                 :        188 :     std::string enable_console_unorder = Utils::get_env("VLINK_LOG_CONSOLE_UNORDER");
     556                 :         94 :     global_instance.console_in_order.store(enable_console_unorder != "1", std::memory_order_release);
     557                 :            : 
     558                 :        188 :     std::string enable_utc_str = Utils::get_env("VLINK_LOG_ENABLE_UTC");
     559                 :         94 :     global_instance.utc_enable.store(enable_utc_str == "1", std::memory_order_release);
     560                 :            : 
     561         [ +  + ]:         94 :     if (global_instance.app_name.empty()) {
     562                 :         93 :       global_instance.app_name = Utils::get_app_name();
     563                 :            : 
     564         [ -  + ]:         93 :       if VUNLIKELY (global_instance.app_name.empty()) {
     565                 :            :         global_instance.app_name = "unknown";                          // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     566                 :            :         std::cerr << "Can not get app name for logger!" << std::endl;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     567                 :            :       }
     568                 :            :     }
     569                 :            : 
     570                 :        188 :     std::string console_format = Utils::get_env("VLINK_LOG_CONSOLE_FMT");
     571                 :         94 :     global_instance.console_format_enable.store(console_format == "1", std::memory_order_release);
     572                 :         94 :   }
     573                 :            : 
     574         [ +  + ]:        194 :   if (global_instance.file_level.load(std::memory_order_acquire) < kOff) {
     575                 :         87 :     global_instance.version_log.reserve(128);
     576                 :            : 
     577                 :         87 :     global_instance.version_log.append("***** ");
     578                 :         87 :     global_instance.version_log.append("[PNAME: ");
     579                 :         87 :     global_instance.version_log.append(global_instance.app_name);
     580                 :         87 :     global_instance.version_log.append("] ");
     581                 :            : 
     582                 :         87 :     global_instance.version_log.append("[PID: ");
     583                 :         87 :     global_instance.version_log.append(Utils::get_pid_str());
     584                 :         87 :     global_instance.version_log.append("] ");
     585                 :            : 
     586         [ +  + ]:         87 :     if (global_instance.utc_enable.load(std::memory_order_acquire)) {
     587                 :          1 :       global_instance.version_log.append("[DATE (UTC): ");
     588                 :          1 :       global_instance.version_log.append(get_current_date(true));
     589                 :          1 :       global_instance.version_log.append("] ");
     590                 :            :     } else {
     591                 :         86 :       global_instance.version_log.append("[DATE: ");
     592                 :         86 :       global_instance.version_log.append(get_current_date(false));
     593                 :         86 :       global_instance.version_log.append("] ");
     594                 :            :     }
     595                 :            : 
     596                 :         87 :     global_instance.version_log.append("[VERSION: ");
     597                 :         87 :     global_instance.version_log.append(VLINK_VERSION);
     598                 :         87 :     global_instance.version_log.append("] ");
     599                 :         87 :     global_instance.version_log.append("*****");
     600                 :            : 
     601                 :         87 :     impl_->is_enable_file_channel = true;
     602                 :            : 
     603                 :        174 :     std::string plugin_name = Utils::get_env("VLINK_LOG_PLUGIN");
     604                 :            : 
     605         [ +  + ]:         87 :     if (!plugin_name.empty()) {
     606                 :            :       // Use plugin
     607                 :          1 :       impl_->plugin.set_log_level(kOff);  // Must set!
     608                 :            : 
     609                 :          1 :       impl_->interface = impl_->plugin.load<LoggerPluginInterface>(plugin_name, 1, 0);
     610                 :            : 
     611         [ -  + ]:          1 :       if (impl_->interface) {
     612                 :            :         // LCOV_EXCL_START GCOVR_EXCL_START
     613                 :            :         bool plugin_inited = false;
     614                 :            : 
     615                 :            :         try {
     616                 :            :           plugin_inited = impl_->interface->init(global_instance.app_name);
     617                 :            :         } catch (const std::exception& e) {
     618                 :            :           std::cerr << "Failed to init plugin for env 'VLINK_LOG_PLUGIN', libname: " << plugin_name << ": " << e.what()
     619                 :            :                     << std::endl;
     620                 :            :         } catch (...) {
     621                 :            :           std::cerr << "Failed to init plugin for env 'VLINK_LOG_PLUGIN', libname: " << plugin_name
     622                 :            :                     << ": non-std exception" << std::endl;
     623                 :            :         }
     624                 :            : 
     625                 :            :         if (plugin_inited) {
     626                 :            :           std::cout << "Successfully loaded plugin for env 'VLINK_LOG_PLUGIN', libname: " << plugin_name << std::endl;
     627                 :            : 
     628                 :            :           write_to_file(kInfo, global_instance.version_log);
     629                 :            :         } else {
     630                 :            :           impl_->interface.reset();
     631                 :            :           impl_->plugin.clear();
     632                 :            :           impl_->is_enable_file_channel = false;
     633                 :            :           std::cerr << "Failed to load plugin for env 'VLINK_LOG_PLUGIN', libname: " << plugin_name << std::endl;
     634                 :            :         }
     635                 :            :         // LCOV_EXCL_STOP GCOVR_EXCL_STOP
     636                 :            :       } else {
     637                 :          1 :         impl_->is_enable_file_channel = false;
     638                 :          1 :         std::cerr << "Failed to load plugin for env 'VLINK_LOG_PLUGIN', libname: " << plugin_name << std::endl;
     639                 :            :       }
     640                 :            : 
     641                 :          1 :       global_instance.is_busy.store(false, std::memory_order_release);
     642                 :            : 
     643                 :          1 :       return;
     644                 :            :     }
     645                 :            : 
     646         [ +  - ]:         86 :     if (global_instance.log_path.empty()) {
     647                 :        172 :       std::string log_dir = Utils::get_env("VLINK_LOG_DIR");
     648                 :            : 
     649         [ +  + ]:         86 :       if (log_dir.empty()) {
     650                 :         84 :         log_dir = Utils::get_tmp_dir() + "/" + "vlink-log";
     651         [ +  + ]:          2 :       } else if (log_dir.back() == '/') {
     652                 :          1 :         log_dir.pop_back();
     653                 :            :       }
     654                 :            : 
     655                 :            :       try {
     656   [ +  -  +  -  :         86 :         if (!std::filesystem::exists(log_dir)) {
                   +  + ]
     657   [ +  -  +  - ]:          1 :           std::filesystem::create_directories(log_dir);
     658                 :            :         }
     659                 :            :       } catch (std::exception&) {        // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     660                 :            :         log_dir = Utils::get_tmp_dir();  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     661                 :            :       }  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     662                 :            : 
     663                 :         86 :       global_instance.log_path = log_dir + "/" + global_instance.app_name;
     664                 :         86 :     }
     665                 :            : 
     666                 :         86 :     size_t log_max_size = kDefaultLogMaxSize;
     667                 :         86 :     size_t log_max_count = kDefaultLogMaxCount;
     668                 :         86 :     int log_flush_delay_ms = kDefaultLogFlushDelay;
     669                 :            : 
     670                 :            :     {
     671                 :        172 :       std::string log_max_size_str = Utils::get_env("VLINK_LOG_MAX_SIZE");
     672                 :        172 :       std::string log_max_count_str = Utils::get_env("VLINK_LOG_MAX_COUNT");
     673                 :        172 :       std::string log_flush_delay_str = Utils::get_env("VLINK_LOG_FLUSH_DELAY");
     674                 :            : 
     675         [ +  + ]:         86 :       if (!log_max_size_str.empty()) {
     676                 :          2 :         std::from_chars(log_max_size_str.data(), log_max_size_str.data() + log_max_size_str.size(), log_max_size);
     677                 :            :       }
     678                 :            : 
     679         [ +  + ]:         86 :       if (!log_max_count_str.empty()) {
     680                 :          2 :         std::from_chars(log_max_count_str.data(), log_max_count_str.data() + log_max_count_str.size(), log_max_count);
     681                 :            :       }
     682                 :            : 
     683         [ +  + ]:         86 :       if (!log_flush_delay_str.empty()) {
     684                 :          2 :         std::from_chars(log_flush_delay_str.data(), log_flush_delay_str.data() + log_flush_delay_str.size(),
     685                 :            :                         log_flush_delay_ms);
     686                 :            :       }
     687                 :         86 :     }
     688                 :            : 
     689                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
     690                 :        172 :     std::string log_strategy = Utils::get_env("VLINK_LOG_STORE_STRATEGY");
     691                 :        172 :     std::string log_append = Utils::get_env("VLINK_LOG_OPEN_APPEND");
     692                 :        172 :     std::string log_block = Utils::get_env("VLINK_LOG_BLOCK_SYNC");
     693                 :        172 :     std::string log_depth = Utils::get_env("VLINK_LOG_WRITE_DEPTH");
     694                 :            : 
     695                 :         86 :     bool use_log_strategy = (log_strategy == "1");
     696                 :         86 :     bool use_log_append = (log_append == "1");
     697                 :         86 :     bool use_log_block = (log_block == "1");
     698                 :         86 :     int log_write_depth = kDefaultWriteDepth;
     699                 :            : 
     700         [ +  + ]:         86 :     if (!log_depth.empty()) {
     701                 :          2 :       std::from_chars(log_depth.data(), log_depth.data() + log_depth.size(), log_write_depth);
     702                 :            :     }
     703                 :            : 
     704                 :         86 :     impl_->spd_thread_pool = std::make_shared<spdlog::details::thread_pool>(log_write_depth, 1);
     705                 :            : 
     706                 :         86 :     impl_->spd_console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
     707                 :         86 :     impl_->spd_console_sink->set_level(spdlog::level::off);
     708                 :            : 
     709         [ +  + ]:         86 :     if (use_log_strategy) {
     710                 :          2 :       std::string log_path = global_instance.log_path + "/" + global_instance.app_name + ".log";
     711                 :            : 
     712                 :            :       try {
     713                 :          2 :         impl_->spd_file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_path, log_max_size,
     714         [ +  - ]:          3 :                                                                                       log_max_count, !use_log_append);
     715                 :            :       } catch (std::exception& e) {                                    // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     716                 :            :         impl_->disk_emergency.store(true, std::memory_order_release);  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     717                 :            : 
     718                 :            :         std::cerr << "VLink logger disk emergency: " << e.what() << std::endl;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     719                 :          0 :         impl_->spd_file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
     720                 :            :             log_path, log_max_size,           // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     721                 :            :             log_max_count, !use_log_append);  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     722                 :            :       }  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     723                 :            : 
     724                 :          1 :     } else {
     725                 :         85 :       spdlog_custom_sink::TimeZone timezone = global_instance.utc_enable.load(std::memory_order_acquire)
     726         [ +  + ]:         85 :                                                   ? spdlog_custom_sink::TimeZone::kTimezoneUtc
     727                 :         85 :                                                   : spdlog_custom_sink::TimeZone::kTimezoneLocal;
     728                 :            : 
     729                 :            :       try {
     730                 :        170 :         impl_->spd_file_sink = std::make_shared<spdlog_custom_sink::TimeRollingFile_mt>(
     731         [ +  - ]:        255 :             global_instance.log_path, log_max_size, log_max_count, timezone, !use_log_append);
     732                 :            :       } catch (std::exception& e) {                                    // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     733                 :            :         impl_->disk_emergency.store(true, std::memory_order_release);  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     734                 :            : 
     735                 :            :         std::cerr << "VLink logger disk emergency: " << e.what() << std::endl;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     736                 :          0 :         impl_->spd_file_sink =
     737                 :            :             std::make_shared<spdlog_custom_sink::TimeRollingFile_mt>(  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     738                 :          0 :                 global_instance.log_path, log_max_size, log_max_count, timezone,
     739                 :            :                 !use_log_append);  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     740                 :            :       }  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     741                 :            :     }
     742                 :            : 
     743                 :         86 :     std::vector<spdlog::sink_ptr> spd_sinks;
     744                 :         86 :     spd_sinks.emplace_back(impl_->spd_console_sink);
     745                 :         86 :     spd_sinks.emplace_back(impl_->spd_file_sink);
     746                 :            : 
     747                 :        172 :     impl_->spd = std::make_shared<spdlog::async_logger>(
     748                 :         86 :         global_instance.app_name, spd_sinks.begin(), spd_sinks.end(), impl_->spd_thread_pool,
     749         [ +  + ]:        172 :         use_log_block ? spdlog::async_overflow_policy::block : spdlog::async_overflow_policy::overrun_oldest);
     750                 :            : 
     751                 :         86 :     spdlog::register_logger(impl_->spd);
     752                 :            : 
     753                 :         86 :     impl_->spd->set_error_handler([this](const std::string& msg) {
     754                 :            :       impl_->disk_emergency.store(true, std::memory_order_release);      // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     755                 :            :       std::cerr << "VLink logger disk emergency: " << msg << std::endl;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     756                 :            :     });                                                                  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     757                 :            : 
     758                 :         86 :     spdlog::set_default_logger(impl_->spd);
     759                 :            : 
     760         [ +  + ]:         86 :     if (global_instance.utc_enable.load(std::memory_order_acquire)) {
     761                 :          1 :       impl_->spd->set_pattern("%m-%d %H:%M:%S.%e UTC @%t - %l - %v", spdlog::pattern_time_type::utc);
     762                 :            :     } else {
     763                 :         85 :       impl_->spd->set_pattern("%m-%d %H:%M:%S.%e @%t - %l - %v", spdlog::pattern_time_type::local);
     764                 :            :     }
     765                 :            : 
     766                 :         86 :     impl_->spd->set_level(spdlog::level::level_enum::trace);
     767                 :            : 
     768         [ +  + ]:         86 :     if (log_flush_delay_ms > 0) {
     769                 :         85 :       impl_->spd->flush_on(spdlog::level::level_enum::err);
     770                 :         85 :       spdlog::flush_every(std::chrono::milliseconds(log_flush_delay_ms));
     771                 :            : 
     772                 :            :     } else {
     773                 :          1 :       impl_->spd->flush_on(spdlog::level::level_enum::trace);
     774                 :            :     }
     775                 :            : 
     776                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
     777                 :            :     std::string log_append = Utils::get_env("VLINK_LOG_OPEN_APPEND");
     778                 :            :     std::string log_depth = Utils::get_env("VLINK_LOG_WRITE_DEPTH");
     779                 :            : 
     780                 :            :     bool use_log_append = (log_append == "1");
     781                 :            :     int log_write_depth = kDefaultWriteDepth;
     782                 :            : 
     783                 :            :     if (!log_depth.empty()) {
     784                 :            :       std::from_chars(log_depth.data(), log_depth.data() + log_depth.size(), log_write_depth);
     785                 :            :     }
     786                 :            : 
     787                 :            :     std::string log_path = global_instance.log_path + "/" + global_instance.app_name + ".log";
     788                 :            : 
     789                 :            :     quill::BackendOptions backend_options;
     790                 :            : 
     791                 :            :     // backend_options.cpu_affinity=0;
     792                 :            :     backend_options.sleep_duration =
     793                 :            :         log_flush_delay_ms > 0 ? std::chrono::milliseconds(log_flush_delay_ms) : std::chrono::milliseconds(10);
     794                 :            :     backend_options.transit_event_buffer_initial_capacity = 1024U;
     795                 :            :     backend_options.transit_events_soft_limit = 8192U;
     796                 :            :     backend_options.wait_for_queues_to_empty_before_exit = true;
     797                 :            :     backend_options.log_level_descriptions = {"TRACE", "TRACE", "TRACE", "DEBUG",     "INFO", "NOTICE",
     798                 :            :                                               "WARN",  "ERROR", "FATAL", "BACKTRACE", "EMPTY"};
     799                 :            :     backend_options.log_level_short_codes = {"T", "T", "T", "D", "I", "N", "W", "E", "F", "BT", " "};
     800                 :            : 
     801                 :            :     backend_options.error_notifier = [this](std::string const& msg) {
     802                 :            :       impl_->disk_emergency.store(true, std::memory_order_release);
     803                 :            : 
     804                 :            :       std::cerr << "VLink logger disk emergency: " << msg << std::endl;
     805                 :            :     };
     806                 :            : 
     807                 :            :     quill::Backend::start(backend_options);
     808                 :            : 
     809                 :            :     quill::RotatingFileSinkConfig sink_config;
     810                 :            : 
     811                 :            :     sink_config.set_open_mode('a');
     812                 :            :     sink_config.set_write_buffer_size(log_write_depth);
     813                 :            :     sink_config.set_rotation_max_file_size(log_max_size);
     814                 :            :     sink_config.set_max_backup_files(log_max_count);
     815                 :            :     sink_config.set_overwrite_rolled_files(true);
     816                 :            :     sink_config.set_remove_old_files(true);
     817                 :            :     sink_config.set_fsync_enabled(true);
     818                 :            :     sink_config.set_minimum_fsync_interval(std::chrono::milliseconds(log_flush_delay_ms));
     819                 :            :     sink_config.set_rotation_on_creation(!use_log_append);
     820                 :            :     sink_config.set_filename_append_option(quill::FilenameAppendOption::None);
     821                 :            :     sink_config.set_rotation_naming_transport(quill::RotatingFileSinkConfig::RotationNamingScheme::Index);
     822                 :            : 
     823                 :            :     quill::PatternFormatterOptions format_options;
     824                 :            : 
     825                 :            :     if (global_instance.utc_enable.load(std::memory_order_acquire)) {
     826                 :            :       sink_config.set_timezone(quill::Timezone::GmtTime);
     827                 :            :       format_options = quill::PatternFormatterOptions("%(time) UTC @%(thread_id) - %(log_level:<5) - %(message)",
     828                 :            :                                                       "%m-%d %H:%M:%S.%Qms", quill::Timezone::GmtTime);
     829                 :            :     } else {
     830                 :            :       sink_config.set_timezone(quill::Timezone::LocalTime);
     831                 :            :       format_options = quill::PatternFormatterOptions("%(time) @%(thread_id) - %(log_level:<5) - %(message)",
     832                 :            :                                                       "%m-%d %H:%M:%S.%Qms", quill::Timezone::LocalTime);
     833                 :            :     }
     834                 :            : 
     835                 :            :     impl_->quill_console_sink = std::make_shared<quill::ConsoleSink>();
     836                 :            :     impl_->quill_console_sink->set_log_level_filter(quill::LogLevel::Backtrace);
     837                 :            :     impl_->quill_file_sink = std::make_shared<quill::RotatingFileSink>(log_path, sink_config);
     838                 :            : 
     839                 :            :     std::vector<std::shared_ptr<quill::Sink> > quill_sinks;
     840                 :            :     quill_sinks.emplace_back(impl_->quill_file_sink);
     841                 :            :     quill_sinks.emplace_back(impl_->quill_console_sink);
     842                 :            : 
     843                 :            :     impl_->quill_log = quill::Frontend::create_or_get_logger(global_instance.app_name, quill_sinks, format_options);
     844                 :            :     impl_->quill_log->set_log_level(quill::LogLevel::None);
     845                 :            : 
     846                 :            : #elif defined(VLINK_ENABLE_LOG_DLT)
     847                 :            :     DLT_REGISTER_APP(global_instance.app_name.c_str(), "Application for Logging");
     848                 :            :     DLT_REGISTER_CONTEXT(dlt_global_ctx_, "Context", "Context for Logging");
     849                 :            : 
     850                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__ANDROID__)
     851                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__QNX__)
     852                 :            :     slog2_buffer_set_config_t buffer_cfg;
     853                 :            : 
     854                 :            :     buffer_cfg.num_buffers = 1;
     855                 :            :     buffer_cfg.buffer_set_name = "vlink-log";
     856                 :            :     buffer_cfg.verbosity_level = SLOG2_DEBUG2;
     857                 :            :     buffer_cfg.buffer_config[0].buffer_name = global_instance.app_name.c_str();
     858                 :            :     buffer_cfg.buffer_config[0].num_pages = 32;
     859                 :            :     buffer_cfg.max_retries = 3;
     860                 :            : 
     861                 :            :     if (slog2_register(&buffer_cfg, &impl_->slog2_buffer, 0) == 0) {
     862                 :            :       slog2_set_default_buffer(impl_->slog2_buffer);
     863                 :            :     }
     864                 :            : 
     865                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__linux__)
     866                 :            :     impl_->kmsg_dev.open(VLINK_KMSG_DEV_PATH, std::ofstream::out | std::ofstream::app);
     867                 :            : 
     868                 :            :     std::error_code ec(errno, std::generic_category());
     869                 :            : 
     870                 :            :     if VUNLIKELY (!impl_->kmsg_dev.is_open()) {
     871                 :            :       std::cerr << "Failed to open " << VLINK_KMSG_DEV_PATH << ": " << ec.message() << std::endl;
     872                 :            : 
     873                 :            :       global_instance.is_busy.store(false, std::memory_order_release);
     874                 :            : 
     875                 :            :       return;
     876                 :            :     }
     877                 :            : 
     878                 :            : #endif
     879                 :            : 
     880                 :         86 :     write_to_file(kInfo, global_instance.version_log);
     881         [ +  + ]:         87 :   }
     882                 :            : 
     883                 :         96 :   global_instance.is_busy.store(false, std::memory_order_release);
     884                 :            : }
     885                 :            : 
     886                 :        183 : Logger::~Logger() noexcept {
     887         [ +  + ]:         97 :   if (!impl_->is_enable_file_channel) {
     888                 :         11 :     return;
     889                 :            :   }
     890                 :            : 
     891         [ -  + ]:         86 :   if (impl_->interface) {
     892                 :            :     impl_->interface.reset();  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     893                 :            :     impl_->plugin.clear();     // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     894                 :            :     return;                    // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     895                 :            :   }
     896                 :            : 
     897                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
     898                 :            :   try {
     899         [ +  - ]:         86 :     impl_->spd->flush();
     900                 :         86 :     impl_->spd.reset();
     901         [ +  - ]:         86 :     spdlog::shutdown();
     902                 :         86 :     impl_->spd_console_sink.reset();
     903                 :         86 :     impl_->spd_file_sink.reset();
     904                 :         86 :     impl_->spd_thread_pool.reset();
     905                 :            :   } catch (std::exception&) {  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     906                 :            :   }  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     907                 :            : 
     908                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
     909                 :            :   try {
     910                 :            :     quill::Backend::notify();
     911                 :            :     impl_->quill_file_sink->flush_sink();
     912                 :            :     quill::Backend::stop();
     913                 :            :     impl_->quill_console_sink.reset();
     914                 :            :     impl_->quill_file_sink.reset();
     915                 :            :     quill::Frontend::remove_logger(impl_->quill_log);
     916                 :            :     impl_->quill_log = nullptr;
     917                 :            :   } catch (std::exception&) {
     918                 :            :   }
     919                 :            : 
     920                 :            : #elif defined(VLINK_ENABLE_LOG_DLT)
     921                 :            :   DLT_UNREGISTER_CONTEXT(dlt_global_ctx_);
     922                 :            :   DLT_UNREGISTER_APP();
     923                 :            : 
     924                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__ANDROID__)
     925                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__QNX__)
     926                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__linux__)
     927                 :            : 
     928                 :            :   if (impl_->kmsg_dev.is_open()) {
     929                 :            :     impl_->kmsg_dev.close();
     930                 :            :   }
     931                 :            : 
     932                 :            : #endif
     933         [ +  + ]:         97 : }
     934                 :            : 
     935                 :        171 : char* Logger::get_local_buffer() noexcept {
     936                 :            :   thread_local char buffer[kLocalBufferSize];
     937                 :            : 
     938                 :        171 :   return buffer;
     939                 :            : }
     940                 :            : 
     941                 :        523 : FastStream& Logger::get_local_stream() noexcept {
     942   [ +  +  +  - ]:        523 :   static auto& global_instance = LoggerGlobal::get();
     943                 :            : 
     944         [ +  + ]:        523 :   thread_local FastStream stream;
     945                 :            : 
     946                 :        523 :   stream.reset();
     947                 :        523 :   stream.flags(global_instance.stream_flags.load(std::memory_order_acquire));
     948                 :       1046 :   stream.precision(global_instance.stream_precision.load(std::memory_order_acquire));
     949                 :       1046 :   stream.width(global_instance.stream_width.load(std::memory_order_acquire));
     950                 :            : 
     951                 :        523 :   return stream;
     952                 :            : }
     953                 :            : 
     954                 :        532 : void Logger::write_to_console(Level level, std::string_view log) noexcept {
     955   [ +  +  +  - ]:        532 :   static auto& global_instance = LoggerGlobal::get();
     956                 :            : 
     957         [ +  + ]:       1064 :   if (level < global_instance.console_level.load(std::memory_order_acquire)) {
     958                 :          8 :     return;
     959                 :            :   }
     960                 :            : 
     961                 :            :   {
     962                 :        524 :     std::shared_lock callback_lock(global_instance.callback_mtx);
     963                 :            : 
     964         [ +  + ]:        524 :     if VUNLIKELY (global_instance.console_callback) {
     965                 :          8 :       global_instance.console_callback(level, log);
     966                 :          8 :       return;
     967                 :            :     }
     968         [ +  + ]:        524 :   }
     969                 :            : 
     970         [ +  + ]:        516 :   if VUNLIKELY (impl_->is_enable_backtrace.load(std::memory_order_acquire)) {
     971                 :          1 :     return;
     972                 :            :   }
     973                 :            : 
     974                 :        515 :   const bool console_in_order = global_instance.console_in_order.load(std::memory_order_acquire);
     975                 :            : 
     976         [ +  + ]:        515 :   if (global_instance.console_format_enable.load(std::memory_order_acquire)) {
     977         [ +  + ]:         29 :     thread_local std::string fmt_log;
     978                 :            : 
     979                 :         29 :     fmt_log.clear();
     980                 :            : 
     981                 :         29 :     auto tid_str = get_thread_id_str();
     982                 :            : 
     983         [ +  + ]:         29 :     if (global_instance.utc_enable.load(std::memory_order_acquire)) {
     984                 :          6 :       fmt_log.append(get_current_time(true));
     985                 :          6 :       fmt_log.append(" UTC");
     986                 :            :     } else {
     987                 :         23 :       fmt_log.append(get_current_time(false));
     988                 :            :     }
     989                 :            : 
     990                 :         29 :     fmt_log.append(" @");
     991                 :         29 :     fmt_log.append(tid_str);
     992                 :         29 :     fmt_log.append(" - ");
     993                 :         29 :     fmt_log.append(get_log_level_str(level).data());
     994                 :         29 :     fmt_log.append(" - ");
     995                 :            : 
     996                 :         29 :     fmt_log.append(log);
     997                 :            : 
     998   [ +  +  +  +  :         29 :     switch (level) {
             +  +  -  - ]
     999                 :          2 :       case kTrace:
    1000                 :          2 :         print_with_color("", fmt_log, "\n", stdout, console_in_order, false);
    1001                 :          2 :         return;
    1002                 :          6 :       case kDebug:
    1003                 :          6 :         print_with_color("", fmt_log, "\n", stdout, console_in_order, true);
    1004                 :          6 :         return;
    1005                 :          6 :       case kInfo:
    1006                 :          6 :         print_with_color("\033[32m", fmt_log, "\033[0m\n", stdout, console_in_order, true);
    1007                 :          6 :         return;
    1008                 :          6 :       case kWarn:
    1009                 :          6 :         print_with_color("\033[33m", fmt_log, "\033[0m\n", stderr, console_in_order, true);
    1010                 :          6 :         return;
    1011                 :          6 :       case kError:
    1012                 :          6 :         print_with_color("\033[31m", fmt_log, "\033[0m\n", stderr, console_in_order, true);
    1013                 :          6 :         return;
    1014                 :          3 :       case kFatal:
    1015                 :          3 :         print_with_color("\033[41;37;1m", fmt_log, "\033[0m\n", stderr, console_in_order, true);
    1016                 :          3 :         return;
    1017                 :            :       // LCOV_EXCL_START GCOVR_EXCL_START
    1018                 :            :       case kOff:
    1019                 :            :         return;
    1020                 :            :       default:
    1021                 :            :         return;
    1022                 :            :         // LCOV_EXCL_STOP GCOVR_EXCL_STOP
    1023                 :            :     }
    1024                 :            :   } else {
    1025   [ +  +  +  +  :        486 :     switch (level) {
             +  +  -  - ]
    1026                 :          1 :       case kTrace:
    1027                 :          1 :         print_with_color("", log, "\n", stdout, console_in_order, false);
    1028                 :          1 :         return;
    1029                 :          1 :       case kDebug:
    1030                 :          1 :         print_with_color("", log, "\n", stdout, console_in_order, true);
    1031                 :          1 :         return;
    1032                 :         14 :       case kInfo:
    1033                 :         14 :         print_with_color("\033[32m", log, "\033[0m\n", stdout, console_in_order, true);
    1034                 :         14 :         return;
    1035                 :        201 :       case kWarn:
    1036                 :        201 :         print_with_color("\033[33m", log, "\033[0m\n", stderr, console_in_order, true);
    1037                 :        201 :         return;
    1038                 :        138 :       case kError:
    1039                 :        138 :         print_with_color("\033[31m", log, "\033[0m\n", stderr, console_in_order, true);
    1040                 :        138 :         return;
    1041                 :        131 :       case kFatal:
    1042                 :        131 :         print_with_color("\033[41;37;1m", log, "\033[0m\n", stderr, console_in_order, true);
    1043                 :        131 :         return;
    1044                 :            :       // LCOV_EXCL_START GCOVR_EXCL_START
    1045                 :            :       case kOff:
    1046                 :            :         return;
    1047                 :            :       default:
    1048                 :            :         return;
    1049                 :            :         // LCOV_EXCL_STOP GCOVR_EXCL_STOP
    1050                 :            :     }
    1051                 :            :   }
    1052                 :            : }
    1053                 :            : 
    1054                 :        618 : void Logger::write_to_file(Level level, std::string_view log) noexcept {
    1055   [ +  +  +  - ]:        618 :   static auto& global_instance = LoggerGlobal::get();
    1056                 :            : 
    1057         [ +  + ]:       1236 :   if (level < global_instance.file_level.load(std::memory_order_acquire)) {
    1058                 :         37 :     return;
    1059                 :            :   }
    1060                 :            : 
    1061         [ +  + ]:        581 :   if VUNLIKELY (!impl_->is_enable_file_channel) {
    1062                 :          1 :     return;
    1063                 :            :   }
    1064                 :            : 
    1065                 :            :   {
    1066                 :        580 :     std::shared_lock callback_lock(global_instance.callback_mtx);
    1067                 :            : 
    1068         [ +  + ]:        580 :     if VUNLIKELY (global_instance.file_callback) {
    1069                 :          1 :       global_instance.file_callback(level, log);
    1070                 :          1 :       return;
    1071                 :            :     }
    1072         [ +  + ]:        580 :   }
    1073                 :            : 
    1074         [ -  + ]:        579 :   if (impl_->interface) {
    1075                 :            :     impl_->interface->log(level, log);  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1076                 :            :     return;                             // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1077                 :            :   }
    1078                 :            : 
    1079         [ -  + ]:        579 :   if VUNLIKELY (impl_->disk_emergency.load(std::memory_order_acquire)) {
    1080                 :            :     return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
    1081                 :            :   }
    1082                 :            : 
    1083                 :            : #if defined(VLINK_ENABLE_LOG_SPD)
    1084                 :        579 :   spdlog::level::level_enum spd_level = spdlog::level::debug;
    1085                 :            : 
    1086   [ +  +  +  +  :        579 :   switch (level) {
             +  +  -  - ]
    1087                 :          2 :     case kTrace:
    1088                 :          2 :       spd_level = spdlog::level::trace;
    1089                 :          2 :       break;
    1090                 :          2 :     case kDebug:
    1091                 :          2 :       spd_level = spdlog::level::debug;
    1092                 :          2 :       break;
    1093                 :        102 :     case kInfo:
    1094                 :        102 :       spd_level = spdlog::level::info;
    1095                 :        102 :       break;
    1096                 :        202 :     case kWarn:
    1097                 :        202 :       spd_level = spdlog::level::warn;
    1098                 :        202 :       break;
    1099                 :        139 :     case kError:
    1100                 :        139 :       spd_level = spdlog::level::err;
    1101                 :        139 :       break;
    1102                 :        132 :     case kFatal:
    1103                 :        132 :       spd_level = spdlog::level::critical;
    1104                 :        132 :       break;
    1105                 :            :     // LCOV_EXCL_START GCOVR_EXCL_START
    1106                 :            :     case kOff:
    1107                 :            :       return;
    1108                 :            :     default:
    1109                 :            :       return;
    1110                 :            :       // LCOV_EXCL_STOP GCOVR_EXCL_STOP
    1111                 :            :   }
    1112                 :            : 
    1113                 :            :   try {
    1114         [ +  - ]:        579 :     impl_->spd->log(spd_level, log);
    1115                 :            :     // LCOV_EXCL_START GCOVR_EXCL_START
    1116                 :            :   } catch (const std::exception& e) {
    1117                 :            :     impl_->disk_emergency.store(true, std::memory_order_release);
    1118                 :            :     std::cerr << "VLink logger disk emergency: " << e.what() << std::endl;
    1119                 :            :   }
    1120                 :            :   // LCOV_EXCL_STOP GCOVR_EXCL_STOP
    1121                 :            : 
    1122                 :            : #elif defined(VLINK_ENABLE_LOG_QUI)
    1123                 :            :   try {
    1124                 :            :     if (impl_->is_enable_backtrace.load(std::memory_order_acquire)) {
    1125                 :            :       impl_->quill_log->log_statement<true>(&impl_->quill_metadata_backtrace, log);
    1126                 :            : 
    1127                 :            :       if (level < kWarn) {
    1128                 :            :         return;
    1129                 :            :       }
    1130                 :            :     }
    1131                 :            : 
    1132                 :            :     switch (level) {
    1133                 :            :       case kTrace:
    1134                 :            :         impl_->quill_log->log_statement<false>(&impl_->quill_metadata_trace, log);
    1135                 :            :         break;
    1136                 :            :       case kDebug:
    1137                 :            :         impl_->quill_log->log_statement<false>(&impl_->quill_metadata_debug, log);
    1138                 :            :         break;
    1139                 :            :       case kInfo:
    1140                 :            :         impl_->quill_log->log_statement<false>(&impl_->quill_metadata_info, log);
    1141                 :            :         break;
    1142                 :            :       case kWarn:
    1143                 :            :         impl_->quill_log->log_statement<false>(&impl_->quill_metadata_warn, log);
    1144                 :            :         break;
    1145                 :            :       case kError:
    1146                 :            :         impl_->quill_log->log_statement<true>(&impl_->quill_metadata_error, log);
    1147                 :            :         quill::Backend::notify();
    1148                 :            :         break;
    1149                 :            :       case kFatal:
    1150                 :            :         impl_->quill_log->log_statement<true>(&impl_->quill_metadata_fatal, log);
    1151                 :            :         quill::Backend::notify();
    1152                 :            :         break;
    1153                 :            :       case kOff:
    1154                 :            :         return;
    1155                 :            :       default:
    1156                 :            :         return;
    1157                 :            :     }
    1158                 :            :   } catch (const std::exception& e) {
    1159                 :            :     impl_->disk_emergency.store(true, std::memory_order_release);
    1160                 :            :     std::cerr << "VLink logger disk emergency: " << e.what() << std::endl;
    1161                 :            :   }
    1162                 :            : 
    1163                 :            : #elif defined(VLINK_ENABLE_LOG_DLT)
    1164                 :            : 
    1165                 :            :   DltLogLevelType dlt_level = DLT_LOG_DEFAULT;
    1166                 :            :   switch (level) {
    1167                 :            :     case kTrace:
    1168                 :            :       dlt_level = DLT_LOG_VERBOSE;
    1169                 :            :       break;
    1170                 :            :     case kDebug:
    1171                 :            :       dlt_level = DLT_LOG_DEBUG;
    1172                 :            :       break;
    1173                 :            :     case kInfo:
    1174                 :            :       dlt_level = DLT_LOG_INFO;
    1175                 :            :       break;
    1176                 :            :     case kWarn:
    1177                 :            :       dlt_level = DLT_LOG_WARN;
    1178                 :            :       break;
    1179                 :            :     case kError:
    1180                 :            :       dlt_level = DLT_LOG_ERROR;
    1181                 :            :       break;
    1182                 :            :     case kFatal:
    1183                 :            :       dlt_level = DLT_LOG_FATAL;
    1184                 :            :       break;
    1185                 :            :     case kOff:
    1186                 :            :       return;
    1187                 :            :     default:
    1188                 :            :       return;
    1189                 :            :   }
    1190                 :            : 
    1191                 :            : #ifdef DLT_SIZED_STRING
    1192                 :            :   DLT_LOG(dlt_global_ctx_, dlt_level, DLT_SIZED_STRING(log.data(), log.size()));
    1193                 :            : #else
    1194                 :            :   DLT_LOG(dlt_global_ctx_, dlt_level, DLT_STRING(log.data()));
    1195                 :            : #endif
    1196                 :            : 
    1197                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__ANDROID__)
    1198                 :            : 
    1199                 :            :   int android_level = ANDROID_LOG_DEBUG;
    1200                 :            :   switch (level) {
    1201                 :            :     case kTrace:
    1202                 :            :       android_level = ANDROID_LOG_VERBOSE;
    1203                 :            :       break;
    1204                 :            :     case kDebug:
    1205                 :            :       android_level = ANDROID_LOG_DEBUG;
    1206                 :            :       break;
    1207                 :            :     case kInfo:
    1208                 :            :       android_level = ANDROID_LOG_INFO;
    1209                 :            :       break;
    1210                 :            :     case kWarn:
    1211                 :            :       android_level = ANDROID_LOG_WARN;
    1212                 :            :       break;
    1213                 :            :     case kError:
    1214                 :            :       android_level = ANDROID_LOG_ERROR;
    1215                 :            :       break;
    1216                 :            :     case kFatal:
    1217                 :            :       android_level = ANDROID_LOG_FATAL;
    1218                 :            :       break;
    1219                 :            :     case kOff:
    1220                 :            :       return;
    1221                 :            :     default:
    1222                 :            :       return;
    1223                 :            :   }
    1224                 :            : 
    1225                 :            :   __android_log_write(android_level, global_instance.app_name.c_str(), log.data());
    1226                 :            : 
    1227                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__QNX__)
    1228                 :            :   int nat_level = SLOG2_DEBUG1;
    1229                 :            :   switch (level) {
    1230                 :            :     case kTrace:
    1231                 :            :       nat_level = SLOG2_DEBUG2;
    1232                 :            :       break;
    1233                 :            :     case kDebug:
    1234                 :            :       nat_level = SLOG2_DEBUG1;
    1235                 :            :       break;
    1236                 :            :     case kInfo:
    1237                 :            :       nat_level = SLOG2_INFO;
    1238                 :            :       break;
    1239                 :            :     case kWarn:
    1240                 :            :       nat_level = SLOG2_WARNING;
    1241                 :            :       break;
    1242                 :            :     case kError:
    1243                 :            :       nat_level = SLOG2_ERROR;
    1244                 :            :       break;
    1245                 :            :     case kFatal:
    1246                 :            :       nat_level = SLOG2_CRITICAL;
    1247                 :            :       break;
    1248                 :            :     case kOff:
    1249                 :            :       return;
    1250                 :            :     default:
    1251                 :            :       return;
    1252                 :            :   }
    1253                 :            : 
    1254                 :            :   slog2c(impl_->slog2_buffer, ::gettid(), nat_level, log.data());
    1255                 :            : 
    1256                 :            : #elif defined(VLINK_ENABLE_LOG_NAT) && defined(__linux__)
    1257                 :            : 
    1258                 :            :   if (impl_->kmsg_dev.is_open()) {
    1259                 :            :     std::lock_guard lock(impl_->file_mtx);
    1260                 :            : 
    1261                 :            :     switch (level) {
    1262                 :            :       case kTrace:
    1263                 :            :         impl_->kmsg_dev << "<7>";
    1264                 :            :         break;
    1265                 :            :       case kDebug:
    1266                 :            :         impl_->kmsg_dev << "<6>";
    1267                 :            :         break;
    1268                 :            :       case kInfo:
    1269                 :            :         impl_->kmsg_dev << "<5>";
    1270                 :            :         break;
    1271                 :            :       case kWarn:
    1272                 :            :         impl_->kmsg_dev << "<4>";
    1273                 :            :         break;
    1274                 :            :       case kError:
    1275                 :            :         impl_->kmsg_dev << "<3>";
    1276                 :            :         break;
    1277                 :            :       case kFatal:
    1278                 :            :         impl_->kmsg_dev << "<2>";
    1279                 :            :         break;
    1280                 :            :       case kOff:
    1281                 :            :         return;
    1282                 :            :       default:
    1283                 :            :         return;
    1284                 :            :     }
    1285                 :            : 
    1286                 :            :     impl_->kmsg_dev << log << std::endl;
    1287                 :            :   }
    1288                 :            : 
    1289                 :            : #endif
    1290                 :            : }
    1291                 :            : 
    1292                 :            : }  // namespace vlink

Generated by: LCOV version 1.14