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