1 /*
2 * Copyright (C) 2023 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 <string>
19 #include <cstdarg>
20
21 #include <set>
22
23 namespace lume
24 {
25 constexpr int LOG_BUFFER_SIZE = 1024;
getLogLevelName(LogLevel aLogLevel,bool aShortName)26 const char* Logger::getLogLevelName(LogLevel aLogLevel, bool aShortName)
27 {
28 // Note: these must match the LogLevel enum.
29 constexpr int LOG_LEVEL_COUNT = 7;
30 constexpr const char* LOG_LEVEL_NAMES[LOG_LEVEL_COUNT] =
31 {
32 "Verbose", "Debug", "Info", "Warning", "Error", "Fatal", "None",
33 };
34
35 constexpr const char* LOG_LEVEL_NAMES_SHORT[LOG_LEVEL_COUNT] =
36 {
37 "V", "D", "I", "W", "E", "F", "N",
38 };
39
40 const int logLevel = static_cast<int>(aLogLevel);
41 LUME_ASSERT(logLevel >= 0 && logLevel < LOG_LEVEL_COUNT);
42
43 return aShortName ? LOG_LEVEL_NAMES_SHORT[logLevel] : LOG_LEVEL_NAMES[logLevel];
44 }
45
46
Logger(bool aDefaultOutputs)47 Logger::Logger(bool aDefaultOutputs)
48 {
49 if (aDefaultOutputs)
50 {
51 addOutput(createLoggerConsoleOutput());
52 addOutput(createLoggerDebugOutput());
53
54 // Not writing to a file by default.
55 //addOutput(createLoggerFileOutput("./logfile.txt"));
56 }
57 }
58
59 Logger::~Logger() = default;
60
VLog(LogLevel aLogLevel,const char * aFilename,int aLinenumber,const char * aFormat,va_list aArgs)61 void Logger::VLog(LogLevel aLogLevel, const char *aFilename, int aLinenumber, const char *aFormat, va_list aArgs)
62 {
63 LUME_ASSERT_MSG(aLogLevel != LogLevel::None, "'None' is not a valid log level for writing to the log.");
64
65 if (mLogLevel > aLogLevel) {
66 return;
67 }
68 char buffer[LOG_BUFFER_SIZE];
69 #if defined(__STDC_LIB_EXT1__) || defined(__STDC_WANT_SECURE_LIB__)
70 int ret = vsnprintf_s(buffer, sizeof(buffer), aFormat, aArgs);
71 va_end(aArgs);
72 if (ret < 0) {
73 return;
74 }
75 #else
76 vsnprintf(buffer, sizeof(buffer), aFormat, aArgs);
77 #endif
78 for (auto &output : mOutputs) {
79 output->write(aLogLevel, aFilename, aLinenumber, buffer);
80 }
81 }
82
log(LogLevel aLogLevel,const char * aFilename,int aLinenumber,FORMAT_ATTRIBUTE const char * aFormat,...)83 FORMAT_FUNC(5, 6) void Logger::log(LogLevel aLogLevel, const char *aFilename, int aLinenumber, FORMAT_ATTRIBUTE const char *aFormat, ...)
84 {
85 va_list vl;
86 va_start(vl, aFormat);
87 VLog(aLogLevel, aFilename, aLinenumber, aFormat, vl);
88 va_end(vl);
89 }
90
logAssert(const char * aFilename,int aLinenumber,bool expression,const char * expressionString,FORMAT_ATTRIBUTE const char * aFormat,...)91 FORMAT_FUNC(6, 7) bool Logger::logAssert(const char *aFilename, int aLinenumber, bool expression, const char *expressionString, FORMAT_ATTRIBUTE const char *aFormat, ...)
92 {
93 if (expression)
94 {
95 return true;
96 }
97
98 va_list vl;
99 va_start(vl, aFormat);
100
101 char buffer[LOG_BUFFER_SIZE];
102 #if defined(__STDC_LIB_EXT1__) || defined(__STDC_WANT_SECURE_LIB__)
103 const int numWritten = vsnprintf_s(buffer, sizeof(buffer), aFormat, vl);
104 if (numWritten < 0) {
105 buffer[0] = '\0';
106 }
107 #else
108 vsnprintf(buffer, sizeof(buffer), aFormat, vl);
109 #endif
110
111 va_end(vl);
112
113 log(LogLevel::Fatal, aFilename, aLinenumber, "Assert failed (%s). %s", expressionString, buffer);
114 return false;
115 }
116
117
getLogLevel() const118 ILogger::LogLevel Logger::getLogLevel() const
119 {
120 return mLogLevel;
121 }
122
setLogLevel(LogLevel aLogLevel)123 void Logger::setLogLevel(LogLevel aLogLevel)
124 {
125 mLogLevel = aLogLevel;
126 }
127
addOutput(std::unique_ptr<IOutput> aOutput)128 void Logger::addOutput(std::unique_ptr<IOutput> aOutput)
129 {
130 if (aOutput)
131 {
132 std::lock_guard<std::mutex> guard(mLoggerMutex);
133 mOutputs.push_back(std::move(aOutput));
134 }
135 }
136
137
138 namespace
139 {
140 Logger g_sLoggerInstance(true); // Global logger instance.
141
142 std::set<std::string> sRegisteredOnce; // Global set of ids used by the LUME_ONCE macro.
143 std::mutex g_sOnceMutex;
144 } // empty namespace
145
getLogger()146 ILogger &getLogger()
147 {
148 return g_sLoggerInstance;
149 }
150
151
CheckOnce(const char * aId)152 bool CheckOnce(const char *aId)
153 {
154 std::lock_guard<std::mutex> guard(g_sOnceMutex);
155
156 size_t size = sRegisteredOnce.size();
157 sRegisteredOnce.insert(std::string(aId));
158
159 // Something was inserted if the size changed.
160 return size != sRegisteredOnce.size();
161 }
162
CheckOnceReset()163 void CheckOnceReset()
164 {
165 std::lock_guard<std::mutex> guard(g_sOnceMutex);
166 sRegisteredOnce.clear();
167 }
168
169
170 } // lume
171