1 /*
2 * Copyright (c) 2021 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 "log_print.h"
17
18 #include <atomic>
19 #include <cstdarg>
20 #include <cstdio>
21 #include <mutex>
22
23 #include "securec.h"
24 #include "platform_specific.h"
25 #include "hilog/log.h"
26
27 namespace DistributedDB {
28 Logger *Logger::logHandler = nullptr;
29 const std::string Logger::PRIVATE_TAG = "s{private}";
30
31 class HiLogger : public Logger {
32 public:
Print(Level level,const std::string & tag,const std::string & msg)33 void Print(Level level, const std::string &tag, const std::string &msg) override
34 {
35 if (msg.empty()) {
36 return;
37 }
38 #ifdef DB_DEBUG_ENV
39 #define FORMAT "%s"
40 #else
41 #define FORMAT "%{public}s"
42 #endif
43 OHOS::HiviewDFX::HiLogLabel label = { LOG_CORE, 0xD001630, tag.c_str() }; // log module id.
44 switch (level) {
45 case Level::LEVEL_DEBUG:
46 (void)HILOG_IMPL(label.type, LOG_DEBUG, label.domain, label.tag, FORMAT, msg.c_str());
47 break;
48 case Level::LEVEL_INFO:
49 (void)HILOG_IMPL(label.type, LOG_INFO, label.domain, label.tag, FORMAT, msg.c_str());
50 break;
51 case Level::LEVEL_WARN:
52 (void)HILOG_IMPL(label.type, LOG_WARN, label.domain, label.tag, FORMAT, msg.c_str());
53 break;
54 case Level::LEVEL_ERROR:
55 (void)HILOG_IMPL(label.type, LOG_ERROR, label.domain, label.tag, FORMAT, msg.c_str());
56 break;
57 case Level::LEVEL_FATAL:
58 (void)HILOG_IMPL(label.type, LOG_FATAL, label.domain, label.tag, FORMAT, msg.c_str());
59 break;
60 default:
61 break;
62 }
63 }
64 };
65
GetInstance()66 Logger *Logger::GetInstance()
67 {
68 static std::mutex logInstanceLock;
69 static std::atomic<Logger *> logInstance = nullptr;
70 // For Double-Checked Locking, we need check logInstance twice
71 if (logInstance == nullptr) {
72 std::lock_guard<std::mutex> lock(logInstanceLock);
73 if (logInstance == nullptr) {
74 // Here, we new logInstance to print log, if new failed, we can do nothing.
75 logInstance = new (std::nothrow) HiLogger;
76 }
77 }
78 return logInstance;
79 }
80
RegisterLogger(Logger * logger)81 void Logger::RegisterLogger(Logger *logger)
82 {
83 static std::mutex logHandlerLock;
84 if (logger == nullptr) {
85 return;
86 }
87 if (logHandler == nullptr) {
88 std::lock_guard<std::mutex> lock(logHandlerLock);
89 if (logHandler == nullptr) {
90 logHandler = logger;
91 }
92 }
93 }
94
Log(Level level,const std::string & tag,const char * func,int line,const char * format,...)95 void Logger::Log(Level level, const std::string &tag, const char *func, int line, const char *format, ...)
96 {
97 (void)func;
98 (void)line;
99 if (format == nullptr) {
100 return;
101 }
102
103 static const int maxLogLength = 1024;
104 va_list argList;
105 va_start(argList, format);
106 char logBuff[maxLogLength];
107 std::string msg;
108 std::string formatTemp;
109 PreparePrivateLog(format, formatTemp);
110 int bytes = vsnprintf_s(logBuff, maxLogLength, maxLogLength - 1, formatTemp.c_str(), argList);
111 if (bytes < 0) {
112 msg = "log buffer overflow!";
113 } else {
114 msg = logBuff;
115 }
116 va_end(argList);
117 if (logHandler != nullptr) {
118 logHandler->Print(level, tag, msg);
119 return;
120 }
121
122 Logger::RegisterLogger(Logger::GetInstance());
123 if (logHandler != nullptr) {
124 logHandler->Print(level, tag, msg);
125 }
126 }
127
PreparePrivateLog(const char * format,std::string & outStrFormat)128 void Logger::PreparePrivateLog(const char *format, std::string &outStrFormat)
129 {
130 outStrFormat = format;
131 std::string::size_type pos = outStrFormat.find(PRIVATE_TAG);
132 if (pos != std::string::npos) {
133 #ifdef DB_DEBUG_ENV
134 outStrFormat.replace(pos, PRIVATE_TAG.size(), "s");
135 #else
136 outStrFormat.replace(pos, PRIVATE_TAG.size(), ".3s");
137 #endif
138 }
139 }
140 } // namespace DistributedDB
141