1 | // LAF Base Library |
2 | // Copyright (C) 2019-2022 Igara Studio S.A. |
3 | // Copyright (C) 2001-2017 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "base/log.h" |
13 | |
14 | #include "base/debug.h" |
15 | #include "base/fstream_path.h" |
16 | |
17 | #include <atomic> |
18 | #include <cstdarg> |
19 | #include <cstdio> |
20 | #include <cstring> |
21 | #include <fstream> |
22 | #include <iostream> |
23 | #include <mutex> |
24 | #include <string> |
25 | #include <vector> |
26 | |
27 | namespace { |
28 | |
29 | // Default log level is error, which means that we'll log regular |
30 | // errors and fatal errors. |
31 | std::atomic<LogLevel> log_level(LogLevel::ERROR); |
32 | std::mutex log_mutex; |
33 | std::ofstream log_stream; |
34 | std::ostream* log_ostream = &std::cerr; |
35 | std::string log_filename; |
36 | |
37 | } // anonymous namespace |
38 | |
39 | void base::set_log_filename(const char* filename) |
40 | { |
41 | if (log_stream.is_open()) { |
42 | log_stream.close(); |
43 | log_ostream = &std::cerr; |
44 | } |
45 | |
46 | if (filename) { |
47 | log_filename = filename; |
48 | log_stream.open(FSTREAM_PATH(log_filename)); |
49 | log_ostream = &log_stream; |
50 | } |
51 | else { |
52 | log_filename = std::string(); |
53 | } |
54 | } |
55 | |
56 | void base::set_log_level(const LogLevel level) |
57 | { |
58 | log_level = level; |
59 | } |
60 | |
61 | LogLevel base::get_log_level() |
62 | { |
63 | return log_level; |
64 | } |
65 | |
66 | static void LOGva(const char* format, va_list ap) |
67 | { |
68 | va_list apTmp; |
69 | va_copy(apTmp, ap); |
70 | int size = std::vsnprintf(nullptr, 0, format, apTmp); |
71 | va_end(apTmp); |
72 | if (size < 1) |
73 | return; // Nothing to log |
74 | |
75 | std::vector<char> buf(size+1); |
76 | std::vsnprintf(&buf[0], buf.size(), format, ap); |
77 | |
78 | { |
79 | std::lock_guard lock(log_mutex); |
80 | ASSERT(log_ostream); |
81 | log_ostream->write(&buf[0], size); |
82 | log_ostream->flush(); |
83 | } |
84 | |
85 | #ifdef _DEBUG |
86 | fputs(&buf[0], stderr); |
87 | fflush(stderr); |
88 | #endif |
89 | } |
90 | |
91 | void LOG(const char* format, ...) |
92 | { |
93 | ASSERT(format); |
94 | if (!format || log_level < INFO) |
95 | return; |
96 | |
97 | va_list ap; |
98 | va_start(ap, format); |
99 | LOGva(format, ap); |
100 | va_end(ap); |
101 | } |
102 | |
103 | void LOG(const LogLevel level, const char* format, ...) |
104 | { |
105 | ASSERT(format); |
106 | if (!format || log_level < level) |
107 | return; |
108 | |
109 | va_list ap; |
110 | va_start(ap, format); |
111 | LOGva(format, ap); |
112 | va_end(ap); |
113 | } |
114 | |