• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "Logger.h"
17 
18 #include <cstdarg>
19 #include <set>
20 #include <string>
21 
22 namespace lume {
23 namespace {
24 constexpr int LOG_BUFFER_SIZE = 1024;
25 
26 // Note: these must match the LogLevel enum.
27 constexpr int LOG_LEVEL_COUNT = 7;
28 
29 constexpr const char* LOG_LEVEL_NAMES[LOG_LEVEL_COUNT] = {
30     "Verbose",
31     "Debug",
32     "Info",
33     "Warning",
34     "Error",
35     "Fatal",
36     "None",
37 };
38 
39 constexpr const char* LOG_LEVEL_NAMES_SHORT[LOG_LEVEL_COUNT] = {
40     "V",
41     "D",
42     "I",
43     "W",
44     "E",
45     "F",
46     "N",
47 };
48 } // namespace
49 
GetLogLevelName(LogLevel logLevel,bool shortName)50 const char* Logger::GetLogLevelName(LogLevel logLevel, bool shortName)
51 {
52     const int logLevelIndex = static_cast<int>(logLevel);
53     LUME_ASSERT(logLevelIndex >= 0 && logLevelIndex < LOG_LEVEL_COUNT);
54 
55     return shortName ? LOG_LEVEL_NAMES_SHORT[logLevelIndex] : LOG_LEVEL_NAMES[logLevelIndex];
56 }
57 
Logger(bool defaultOutputs)58 Logger::Logger(bool defaultOutputs)
59 {
60     if (defaultOutputs) {
61         AddOutput(CreateLoggerConsoleOutput());
62         AddOutput(CreateLoggerDebugOutput());
63 
64         // Not writing to a file by default.
65         // This can be enabled with: addOutput(createLoggerFileOutput("./logfile.txt"))
66     }
67 }
68 
69 Logger::~Logger() = default;
70 
Vlog(LogLevel logLevel,const char * filename,int linenumber,const char * format,va_list args)71 void Logger::Vlog(LogLevel logLevel, const char* filename, int linenumber, const char* format, va_list args)
72 {
73     LUME_ASSERT_MSG(logLevel != LogLevel::NONE, "'NONE' is not a valid log level for writing to the log.");
74 
75     if (mLogLevel > logLevel) {
76         return;
77     }
78 
79     char buffer[LOG_BUFFER_SIZE];
80 #if defined(__STDC_LIB_EXT1__) || defined(__STDC_WANT_SECURE_LIB__)
81     auto ret = vsnprintf_s(buffer, sizeof(buffer), format, args);
82     if (ret < 0) {
83         return;
84     }
85 #else
86     auto ret = vsnprintf(buffer, sizeof(buffer), format, args);
87     if (ret < 0) {
88         return;
89     }
90 #endif
91 
92     for (auto& output : mOutputs) {
93         output->Write(logLevel, filename, linenumber, buffer);
94     }
95 }
96 
Write(LogLevel logLevel,const char * filename,int linenumber,const char * buffer)97 void Logger::Write(LogLevel logLevel, const char* filename, int linenumber, const char* buffer)
98 {
99     for (auto& output : mOutputs) {
100         output->Write(logLevel, filename, linenumber, buffer);
101     }
102 }
103 
104 FORMAT_FUNC(5, 6)
Log(LogLevel logLevel,const char * filename,int linenumber,FORMAT_ATTRIBUTE const char * format,...)105 void Logger::Log(LogLevel logLevel, const char* filename, int linenumber, FORMAT_ATTRIBUTE const char* format, ...)
106 {
107     va_list vl;
108     va_start(vl, format);
109     Vlog(logLevel, filename, linenumber, format, vl);
110     va_end(vl);
111 }
112 
113 FORMAT_FUNC(6, 7)
LogAssert(const char * filename,int linenumber,bool expression,const char * expressionString,FORMAT_ATTRIBUTE const char * format,...)114 bool Logger::LogAssert(const char* filename, int linenumber, bool expression, const char* expressionString,
115     FORMAT_ATTRIBUTE const char* format, ...)
116 {
117     if (expression) {
118         return true;
119     }
120 
121     va_list vl;
122     va_start(vl, format);
123 
124     char buffer[LOG_BUFFER_SIZE];
125 #if defined(__STDC_LIB_EXT1__) || defined(__STDC_WANT_SECURE_LIB__)
126     vsnprintf_s(buffer, sizeof(buffer), format, vl);
127 #else
128     vsnprintf(buffer, sizeof(buffer), format, vl);
129 #endif
130 
131     va_end(vl);
132 
133     Log(LogLevel::FATAL, filename, linenumber, "Assert failed (%s). %s", expressionString, buffer);
134     return false;
135 }
136 
GetLogLevel() const137 ILogger::LogLevel Logger::GetLogLevel() const
138 {
139     return mLogLevel;
140 }
141 
SetLogLevel(LogLevel logLevel)142 void Logger::SetLogLevel(LogLevel logLevel)
143 {
144     mLogLevel = logLevel;
145 }
146 
AddOutput(std::unique_ptr<IOutput> output)147 void Logger::AddOutput(std::unique_ptr<IOutput> output)
148 {
149     if (output) {
150         std::lock_guard<std::mutex> guard(mLoggerMutex);
151         mOutputs.push_back(std::move(output));
152     }
153 }
154 
155 namespace {
156 Logger g_loggerInstance(true); // Global logger instance.
157 
158 std::set<std::string> g_registeredOnce; // Global set of ids used by the LUME_ONCE macro.
159 std::mutex g_onceMutex;
160 } // namespace
161 
GetLogger()162 ILogger& GetLogger()
163 {
164     return g_loggerInstance;
165 }
166 
CheckOnce(const char * aId)167 bool CheckOnce(const char* aId)
168 {
169     std::lock_guard<std::mutex> guard(g_onceMutex);
170 
171     size_t size = g_registeredOnce.size();
172     g_registeredOnce.insert(std::string(aId));
173 
174     // Something was inserted if the size changed.
175     return size != g_registeredOnce.size();
176 }
177 
CheckOnceReset()178 void CheckOnceReset()
179 {
180     std::lock_guard<std::mutex> guard(g_onceMutex);
181     g_registeredOnce.clear();
182 }
183 } // namespace lume
184