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 #include <cerrno>
16 #include <cstdarg>
17 #include <cstdio>
18 #include <ctime>
19 #include <fstream>
20 #include <iostream>
21 #include <mutex>
22 #include <securec.h>
23
24 #ifdef __LINUX__
25 #include <atomic>
26 #endif
27
28 #ifndef __WINDOWS__
29 #include <sys/syscall.h>
30 #else
31 #include <windows.h>
32 #include <memory.h>
33 #endif
34 #include <unistd.h>
35
36 #include "log_timestamp.h"
37 #include "hilog_trace.h"
38 #include "hilog_inner.h"
39 #include "hilog/log.h"
40 #include "hilog_common.h"
41 #include "vsnprintf_s_p.h"
42 #include "log_utils.h"
43
44 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
45 #include "properties.h"
46 #include "hilog_input_socket_client.h"
47 #else
48 #include "log_print.h"
49 #endif
50
51 using namespace std;
52 using namespace OHOS::HiviewDFX;
53 static RegisterFunc g_registerFunc = nullptr;
54 static atomic_int g_hiLogGetIdCallCount = 0;
55 // protected by static lock guard
56 static char g_hiLogLastFatalMessage[MAX_LOG_LEN] = { 0 }; // MAX_lOG_LEN : 1024
57
58 HILOG_PUBLIC_API
GetLastFatalMessage()59 extern "C" const char* GetLastFatalMessage()
60 {
61 return g_hiLogLastFatalMessage;
62 }
63
HiLogRegisterGetIdFun(RegisterFunc registerFunc)64 int HiLogRegisterGetIdFun(RegisterFunc registerFunc)
65 {
66 if (g_registerFunc != nullptr) {
67 return -1;
68 }
69 g_registerFunc = registerFunc;
70 return 0;
71 }
72
HiLogUnregisterGetIdFun(RegisterFunc registerFunc)73 void HiLogUnregisterGetIdFun(RegisterFunc registerFunc)
74 {
75 if (g_registerFunc != registerFunc) {
76 return;
77 }
78
79 g_registerFunc = nullptr;
80 while (atomic_load(&g_hiLogGetIdCallCount) != 0) {
81 /* do nothing, just wait current callback return */
82 }
83
84 return;
85 }
86
GetFinalLevel(unsigned int domain,const std::string & tag)87 static uint16_t GetFinalLevel(unsigned int domain, const std::string& tag)
88 {
89 // Priority: TagLevel > DomainLevel > GlobalLevel
90 // LOG_LEVEL_MIN is default Level
91 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
92 // domain within the range of [DOMAIN_APP_MIN, DOMAIN_APP_MAX] is a js log,
93 // if this js log comes from debuggable hap, set the default level.
94 if ((domain >= DOMAIN_APP_MIN) && (domain <= DOMAIN_APP_MAX)) {
95 static bool isDebuggableHap = IsDebuggableHap();
96 if (isDebuggableHap) {
97 return LOG_LEVEL_MIN;
98 }
99 }
100 uint16_t tagLevel = GetTagLevel(tag);
101 if (tagLevel != LOG_LEVEL_MIN) {
102 return tagLevel;
103 }
104 uint16_t domainLevel = GetDomainLevel(domain);
105 if (domainLevel != LOG_LEVEL_MIN) {
106 return domainLevel;
107 }
108 return GetGlobalLevel();
109 #else
110 return LOG_LEVEL_MIN;
111 #endif
112 }
113
114 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
HiLogFlowCtrlProcess(int len,const struct timespec & ts)115 static int HiLogFlowCtrlProcess(int len, const struct timespec &ts)
116 {
117 static uint32_t processQuota = 0;
118 static atomic_int gSumLen = 0;
119 static atomic_int gDropped = 0;
120 static atomic<LogTimeStamp> gStartTime;
121 static LogTimeStamp period(1, 0);
122 static std::atomic_flag isFirstFlag = ATOMIC_FLAG_INIT;
123 if (!isFirstFlag.test_and_set()) {
124 processQuota = GetProcessQuota(GetProgName());
125 }
126 LogTimeStamp tsStart = atomic_load(&gStartTime);
127 LogTimeStamp tsNow(ts);
128 tsStart += period;
129 /* in statistic period(1 second) */
130 if (tsNow > tsStart) { /* new statistic period, return how many lines were dropped */
131 int dropped = atomic_exchange_explicit(&gDropped, 0, memory_order_relaxed);
132 atomic_store(&gStartTime, tsNow);
133 atomic_store(&gSumLen, len);
134 return dropped;
135 } else {
136 uint32_t sumLen = (uint32_t)atomic_load(&gSumLen);
137 if (sumLen > processQuota) { /* over quota, -1 means don't print */
138 atomic_fetch_add_explicit(&gDropped, 1, memory_order_relaxed);
139 return -1;
140 } else { /* under quota, 0 means do print */
141 atomic_fetch_add_explicit(&gSumLen, len, memory_order_relaxed);
142 }
143 }
144 return 0;
145 }
146 #else
PrintLog(HilogMsg & header,const char * tag,uint16_t tagLen,const char * fmt,uint16_t fmtLen)147 static int PrintLog(HilogMsg& header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)
148 {
149 LogContent content = {
150 .level = header.level,
151 .type = header.type,
152 .pid = header.pid,
153 .tid = header.tid,
154 .domain = header.domain,
155 .tv_sec = header.tv_sec,
156 .tv_nsec = header.tv_nsec,
157 .mono_sec = header.mono_sec,
158 .tag = tag,
159 .log = fmt,
160 };
161 LogFormat format = {
162 .colorful = false,
163 .timeFormat = FormatTime::TIME,
164 .timeAccuFormat = FormatTimeAccu::MSEC,
165 .year = false,
166 .zone = false,
167 };
168 LogPrintWithFormat(content, format);
169 return RET_SUCCESS;
170 }
171 #endif
172
HiLogPrintArgs(const LogType type,const LogLevel level,const unsigned int domain,const char * tag,const char * fmt,va_list ap)173 int HiLogPrintArgs(const LogType type, const LogLevel level, const unsigned int domain, const char *tag,
174 const char *fmt, va_list ap)
175 {
176 if ((type != LOG_APP) && ((domain < DOMAIN_OS_MIN) || (domain > DOMAIN_OS_MAX))) {
177 return -1;
178 }
179 if (!HiLogIsLoggable(domain, tag, level)) {
180 return -1;
181 }
182 HilogMsg header = {0};
183 struct timespec ts = {0};
184 (void)clock_gettime(CLOCK_REALTIME, &ts);
185 struct timespec ts_mono = {0};
186 (void)clock_gettime(CLOCK_MONOTONIC, &ts_mono);
187 header.tv_sec = static_cast<uint32_t>(ts.tv_sec);
188 header.tv_nsec = static_cast<uint32_t>(ts.tv_nsec);
189 header.mono_sec = static_cast<uint32_t>(ts_mono.tv_sec);
190
191 char buf[MAX_LOG_LEN] = {0};
192 char *logBuf = buf;
193 int traceBufLen = 0;
194 int ret;
195 /* print traceid */
196 if (g_registerFunc != nullptr) {
197 uint64_t chainId = 0;
198 uint32_t flag = 0;
199 uint64_t spanId = 0;
200 uint64_t parentSpanId = 0;
201 ret = -1; /* default value -1: invalid trace id */
202 atomic_fetch_add_explicit(&g_hiLogGetIdCallCount, 1, memory_order_relaxed);
203 RegisterFunc func = g_registerFunc;
204 if (g_registerFunc != nullptr) {
205 ret = func(&chainId, &flag, &spanId, &parentSpanId);
206 }
207 atomic_fetch_sub_explicit(&g_hiLogGetIdCallCount, 1, memory_order_relaxed);
208 if (ret == 0) { /* 0: trace id with span id */
209 traceBufLen = snprintf_s(logBuf, MAX_LOG_LEN, MAX_LOG_LEN - 1, "[%llx, %llx, %llx] ",
210 (unsigned long long)chainId, (unsigned long long)spanId, (unsigned long long)parentSpanId);
211 } else if (ret != -1) { /* trace id without span id, -1: invalid trace id */
212 traceBufLen = snprintf_s(logBuf, MAX_LOG_LEN, MAX_LOG_LEN - 1, "[%llx] ",
213 (unsigned long long)chainId);
214 }
215 if (traceBufLen > 0) {
216 logBuf += traceBufLen;
217 } else {
218 traceBufLen = 0;
219 }
220 }
221
222 /* format log string */
223 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
224 bool debug = IsDebugOn();
225 bool priv = (!debug) && IsPrivateSwitchOn();
226 #else
227 bool priv = true;
228 #endif
229
230 #ifdef __clang__
231 /* code specific to clang compiler */
232 #pragma clang diagnostic push
233 #pragma clang diagnostic ignored "-Wformat-nonliteral"
234 #elif __GNUC__
235 /* code for GNU C compiler */
236 #pragma GCC diagnostic push
237 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
238 #endif
239 ret = vsnprintfp_s(logBuf, MAX_LOG_LEN - traceBufLen, MAX_LOG_LEN - traceBufLen - 1, priv, fmt, ap);
240 #ifdef __clang__
241 #pragma clang diagnostic pop
242 #elif __GNUC__
243 #pragma GCC diagnostic pop
244 #endif
245
246 /* fill header info */
247 auto tagLen = strnlen(tag, MAX_TAG_LEN - 1);
248 auto logLen = strnlen(buf, MAX_LOG_LEN - 1);
249 header.type = type;
250 header.level = level;
251 #ifndef __RECV_MSG_WITH_UCRED_
252 #ifndef __WINDOWS__
253 header.pid = getpid();
254 #else
255 header.pid = static_cast<uint32_t>(GetCurrentProcessId());
256 #endif
257 #endif
258 #ifdef __WINDOWS__
259 header.tid = static_cast<uint32_t>(GetCurrentThreadId());
260 #elif defined(__MAC__)
261 uint64_t tid;
262 pthread_threadid_np(NULL, &tid);
263 header.tid = static_cast<uint32_t>(tid);
264 #else
265 header.tid = static_cast<uint32_t>(syscall(SYS_gettid));
266 #endif
267 header.domain = domain;
268
269 if (level == LOG_FATAL) {
270 static std::mutex fatalMessageBufMutex;
271 std::lock_guard<std::mutex> lock(fatalMessageBufMutex);
272 (void)memcpy_s(g_hiLogLastFatalMessage, sizeof(g_hiLogLastFatalMessage), buf, sizeof(buf));
273 }
274
275 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
276 /* flow control */
277 if (type == LOG_APP && !debug && IsProcessSwitchOn()) {
278 ret = HiLogFlowCtrlProcess(tagLen + logLen - traceBufLen, ts_mono);
279 if (ret < 0) {
280 return ret;
281 } else if (ret > 0) {
282 static const char P_LIMIT_TAG[] = "LOGLIMIT";
283 uint16_t level = header.level;
284 header.level = LOG_WARN;
285 char dropLogBuf[MAX_LOG_LEN] = {0};
286 if (snprintf_s(dropLogBuf, MAX_LOG_LEN, MAX_LOG_LEN - 1,
287 "==LOGS OVER PROC QUOTA, %d DROPPED==", ret) > 0) {
288 ret = HilogWriteLogMessage(&header, P_LIMIT_TAG, strlen(P_LIMIT_TAG) + 1, dropLogBuf,
289 strnlen(dropLogBuf, MAX_LOG_LEN - 1) + 1);
290 }
291 header.level = level;
292 }
293 }
294 return HilogWriteLogMessage(&header, tag, tagLen + 1, buf, logLen + 1);
295 #else
296 return PrintLog(header, tag, tagLen + 1, buf, logLen + 1);
297 #endif
298 }
299
HiLogPrint(LogType type,LogLevel level,unsigned int domain,const char * tag,const char * fmt,...)300 int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)
301 {
302 int ret;
303 va_list ap;
304 va_start(ap, fmt);
305 ret = HiLogPrintArgs(type, level, domain, tag, fmt, ap);
306 va_end(ap);
307 return ret;
308 }
309
HiLogIsLoggable(unsigned int domain,const char * tag,LogLevel level)310 bool HiLogIsLoggable(unsigned int domain, const char *tag, LogLevel level)
311 {
312 if ((level <= LOG_LEVEL_MIN) || (level >= LOG_LEVEL_MAX) || (tag == nullptr) || (domain >= DOMAIN_OS_MAX)) {
313 return false;
314 }
315 if (level < GetFinalLevel(domain, tag)) {
316 return false;
317 }
318 return true;
319 }
320