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
|