• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 
27 #ifdef __LINUX__
28 #include <atomic>
29 #endif
30 
31 #ifndef __WINDOWS__
32 #include <sys/syscall.h>
33 #include <sys/types.h>
34 #else
35 #include <windows.h>
36 #include <memory.h>
37 #endif
38 #include <unistd.h>
39 
40 #include "log_timestamp.h"
41 #include "hilog_trace.h"
42 #include "hilog_inner.h"
43 #include "hilog/log.h"
44 #include "hilog_common.h"
45 #include "vsnprintf_s_p.h"
46 #include "log_utils.h"
47 
48 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
49 #include "properties.h"
50 #include "hilog_input_socket_client.h"
51 #else
52 #include "log_print.h"
53 #endif
54 
55 using namespace std;
56 using namespace OHOS::HiviewDFX;
57 static RegisterFunc g_registerFunc = nullptr;
58 static LogCallback g_logCallback = nullptr;
59 static int g_logLevel = LOG_LEVEL_MIN;
60 static atomic_int g_hiLogGetIdCallCount = 0;
61 // protected by static lock guard
62 static char g_hiLogLastFatalMessage[MAX_LOG_LEN] = { 0 }; // MAX_lOG_LEN : 1024
63 
64 HILOG_PUBLIC_API
GetLastFatalMessage()65 extern "C" const char* GetLastFatalMessage()
66 {
67     return g_hiLogLastFatalMessage;
68 }
69 
HiLogRegisterGetIdFun(RegisterFunc registerFunc)70 int HiLogRegisterGetIdFun(RegisterFunc registerFunc)
71 {
72     if (g_registerFunc != nullptr) {
73         return -1;
74     }
75     g_registerFunc = registerFunc;
76     return 0;
77 }
78 
HiLogUnregisterGetIdFun(RegisterFunc registerFunc)79 void HiLogUnregisterGetIdFun(RegisterFunc registerFunc)
80 {
81     if (g_registerFunc != registerFunc) {
82         return;
83     }
84 
85     g_registerFunc = nullptr;
86     while (atomic_load(&g_hiLogGetIdCallCount) != 0) {
87         /* do nothing, just wait current callback return */
88     }
89 
90     return;
91 }
92 
LOG_SetCallback(LogCallback callback)93 void LOG_SetCallback(LogCallback callback)
94 {
95     g_logCallback = callback;
96 }
97 
HiLogSetAppMinLogLevel(LogLevel level)98 void HiLogSetAppMinLogLevel(LogLevel level)
99 {
100     g_logLevel = level;
101 }
102 
GetFinalLevel(unsigned int domain,const std::string & tag)103 static uint16_t GetFinalLevel(unsigned int domain, const std::string& tag)
104 {
105     // Priority: TagLevel > DomainLevel > GlobalLevel
106     // LOG_LEVEL_MIN is default Level
107 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
108     uint16_t tagLevel = GetTagLevel(tag);
109     if (tagLevel != LOG_LEVEL_MIN) {
110         return tagLevel;
111     }
112     uint16_t persistTagLevel = GetPersistTagLevel(tag);
113     if (persistTagLevel != LOG_LEVEL_MIN) {
114         return persistTagLevel;
115     }
116     uint16_t domainLevel = GetDomainLevel(domain);
117     if (domainLevel != LOG_LEVEL_MIN) {
118         return domainLevel;
119     }
120     uint16_t persistDomainLevel = GetPersistDomainLevel(domain);
121     if (persistDomainLevel != LOG_LEVEL_MIN) {
122         return persistDomainLevel;
123     }
124     // domain within the range of [DOMAIN_APP_MIN, DOMAIN_APP_MAX] is a js log,
125     // if this js log comes from debuggable hap, set the default level.
126     if ((domain >= DOMAIN_APP_MIN) && (domain <= DOMAIN_APP_MAX)) {
127         static bool isDebuggableHap = IsDebuggableHap();
128         if (isDebuggableHap) {
129             return LOG_LEVEL_MIN;
130         }
131     }
132     return GetGlobalLogLevel();
133 #else
134     return LOG_LEVEL_MIN;
135 #endif
136 }
137 
138 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
HiLogFlowCtrlProcess(int len,const struct timespec & ts)139 static int HiLogFlowCtrlProcess(int len, const struct timespec &ts)
140 {
141     static uint32_t processQuota = 0;
142     static atomic_int gSumLen = 0;
143     static atomic_int gDropped = 0;
144     static atomic<LogTimeStamp> gStartTime;
145     static LogTimeStamp period(1, 0);
146     static std::atomic_flag isFirstFlag = ATOMIC_FLAG_INIT;
147     if (!isFirstFlag.test_and_set()) {
148         processQuota = GetProcessQuota(GetProgName());
149     }
150     LogTimeStamp tsStart = atomic_load(&gStartTime);
151     LogTimeStamp tsNow(ts);
152     tsStart += period;
153     /* in statistic period(1 second) */
154     if (tsNow > tsStart) { /* new statistic period, return how many lines were dropped */
155         int dropped = atomic_exchange_explicit(&gDropped, 0, memory_order_relaxed);
156         atomic_store(&gStartTime, tsNow);
157         atomic_store(&gSumLen, len);
158         return dropped;
159     } else {
160         uint32_t sumLen = (uint32_t)atomic_load(&gSumLen);
161         if (sumLen > processQuota) { /* over quota, -1 means don't print */
162             atomic_fetch_add_explicit(&gDropped, 1, memory_order_relaxed);
163             return -1;
164         } else { /* under quota, 0 means do print */
165             atomic_fetch_add_explicit(&gSumLen, len, memory_order_relaxed);
166         }
167     }
168     return 0;
169 }
170 
IsNeedProcFlowCtr(const LogType type)171 static bool IsNeedProcFlowCtr(const LogType type)
172 {
173     if (type != LOG_APP) {
174         return false;
175     }
176     //debuggable hap don't perform process flow control
177     static bool isDebuggableHap = IsDebuggableHap();
178     if (IsProcessSwitchOn() && !isDebuggableHap) {
179         return true;
180     }
181     return false;
182 }
183 #else
PrintLog(HilogMsg & header,const char * tag,uint16_t tagLen,const char * fmt,uint16_t fmtLen)184 static int PrintLog(HilogMsg& header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)
185 {
186     LogContent content = {
187         .level = header.level,
188         .type = header.type,
189         .pid = header.pid,
190         .tid = header.tid,
191         .domain = header.domain,
192         .tv_sec = header.tv_sec,
193         .tv_nsec = header.tv_nsec,
194         .mono_sec = header.mono_sec,
195         .tag = tag,
196         .log = fmt,
197     };
198     LogFormat format = {
199         .colorful = false,
200         .timeFormat = FormatTime::TIME,
201         .timeAccuFormat = FormatTimeAccu::MSEC,
202         .year = false,
203         .zone = false,
204     };
205     LogPrintWithFormat(content, format);
206     return RET_SUCCESS;
207 }
208 #endif
209 
LogToKmsg(const LogLevel level,const char * tag,const char * info)210 static int LogToKmsg(const LogLevel level, const char *tag, const char* info)
211 {
212     static int fd = open("/dev/kmsg", O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
213     if (fd < 0) {
214         printf("open /dev/kmsg failed, fd=%d. \n", fd);
215         return -1;
216     }
217     char logInfo[MAX_LOG_LEN] = {0};
218     if (snprintf_s(logInfo, sizeof(logInfo), sizeof(logInfo) - 1, "<%d>%s: %s\n", level, tag, info) == -1) {
219         logInfo[sizeof(logInfo) - 2] = '\n';  // 2 add \n to tail
220         logInfo[sizeof(logInfo) - 1] = '\0';
221     }
222 #ifdef __LINUX__
223     return TEMP_FAILURE_RETRY(write(fd, logInfo, strlen(logInfo)));
224 #else
225     return write(fd, logInfo, strlen(logInfo));
226 #endif
227 }
228 
HiLogIsPrivacyOn()229 bool HiLogIsPrivacyOn()
230 {
231     bool priv = true;
232 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
233     priv = (!IsDebugOn()) && IsPrivateSwitchOn();
234 #endif
235     return priv;
236 }
237 
HiLogPrintArgs(const LogType type,const LogLevel level,const unsigned int domain,const char * tag,const char * fmt,va_list ap)238 int HiLogPrintArgs(const LogType type, const LogLevel level, const unsigned int domain, const char *tag,
239     const char *fmt, va_list ap)
240 {
241     if ((type != LOG_APP) && ((domain < DOMAIN_OS_MIN) || (domain > DOMAIN_OS_MAX))) {
242         return -1;
243     }
244     if (!HiLogIsLoggable(domain, tag, level)) {
245         return -1;
246     }
247     if (type == LOG_KMSG) {
248         char tmpFmt[MAX_LOG_LEN] = {0};
249         // format va_list info to char*
250         if (vsnprintfp_s(tmpFmt, sizeof(tmpFmt), sizeof(tmpFmt) - 1, HiLogIsPrivacyOn(), fmt, ap) == -1) {
251             tmpFmt[sizeof(tmpFmt) - 2] = '\n';  // 2 add \n to tail
252             tmpFmt[sizeof(tmpFmt) - 1] = '\0';
253         }
254         return LogToKmsg(level, tag, tmpFmt);
255     }
256 
257     HilogMsg header = {0};
258     struct timespec ts = {0};
259     (void)clock_gettime(CLOCK_REALTIME, &ts);
260     struct timespec ts_mono = {0};
261     (void)clock_gettime(CLOCK_MONOTONIC, &ts_mono);
262     header.tv_sec = static_cast<uint32_t>(ts.tv_sec);
263     header.tv_nsec = static_cast<uint32_t>(ts.tv_nsec);
264     header.mono_sec = static_cast<uint32_t>(ts_mono.tv_sec);
265 
266     char buf[MAX_LOG_LEN] = {0};
267     char *logBuf = buf;
268     int traceBufLen = 0;
269     int ret;
270     /* print traceid */
271     if (g_registerFunc != nullptr) {
272         uint64_t chainId = 0;
273         uint32_t flag = 0;
274         uint64_t spanId = 0;
275         uint64_t parentSpanId = 0;
276         ret = -1;  /* default value -1: invalid trace id */
277         atomic_fetch_add_explicit(&g_hiLogGetIdCallCount, 1, memory_order_relaxed);
278         RegisterFunc func = g_registerFunc;
279         if (func != nullptr) {
280             ret = func(&chainId, &flag, &spanId, &parentSpanId);
281         }
282         atomic_fetch_sub_explicit(&g_hiLogGetIdCallCount, 1, memory_order_relaxed);
283         if (ret == 0) {  /* 0: trace id with span id */
284             traceBufLen = snprintf_s(logBuf, MAX_LOG_LEN, MAX_LOG_LEN - 1, "[%llx, %llx, %llx] ",
285                 (unsigned long long)chainId, (unsigned long long)spanId, (unsigned long long)parentSpanId);
286         } else if (ret != -1) {  /* trace id without span id, -1: invalid trace id */
287             traceBufLen = snprintf_s(logBuf, MAX_LOG_LEN, MAX_LOG_LEN - 1, "[%llx] ",
288                 (unsigned long long)chainId);
289         }
290         if (traceBufLen > 0) {
291             logBuf += traceBufLen;
292         } else {
293             traceBufLen = 0;
294         }
295     }
296 
297 /* format log string */
298 #ifdef __clang__
299 /* code specific to clang compiler */
300 #pragma clang diagnostic push
301 #pragma clang diagnostic ignored "-Wformat-nonliteral"
302 #elif __GNUC__
303 /* code for GNU C compiler */
304 #pragma GCC diagnostic push
305 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
306 #endif
307     vsnprintfp_s(logBuf, MAX_LOG_LEN - traceBufLen, MAX_LOG_LEN - traceBufLen - 1, HiLogIsPrivacyOn(), fmt, ap);
308     LogCallback logCallbackFunc = g_logCallback;
309     if (logCallbackFunc != nullptr) {
310         logCallbackFunc(type, level, domain, tag, logBuf);
311     }
312 #ifdef __clang__
313 #pragma clang diagnostic pop
314 #elif __GNUC__
315 #pragma GCC diagnostic pop
316 #endif
317 
318     /* fill header info */
319     auto tagLen = strnlen(tag, MAX_TAG_LEN - 1);
320     auto logLen = strnlen(buf, MAX_LOG_LEN - 1);
321     header.type = type;
322     header.level = level;
323 #ifndef __RECV_MSG_WITH_UCRED_
324 #if defined(is_ohos) && is_ohos
325     header.pid = static_cast<uint32_t>(getprocpid());
326 #elif not defined(__WINDOWS__)
327     header.pid = getpid();
328 #else
329     header.pid = static_cast<uint32_t>(GetCurrentProcessId());
330 #endif
331 #endif
332 #ifdef __WINDOWS__
333     header.tid = static_cast<uint32_t>(GetCurrentThreadId());
334 #elif defined(__MAC__)
335     uint64_t tid;
336     pthread_threadid_np(NULL, &tid);
337     header.tid = static_cast<uint32_t>(tid);
338 #elif defined(__OHOS__)
339     header.tid = static_cast<uint32_t>(gettid());
340 #else
341     header.tid = static_cast<uint32_t>(syscall(SYS_gettid));
342 #endif
343     header.domain = domain;
344 
345     if (level == LOG_FATAL) {
346         static std::mutex fatalMessageBufMutex;
347         std::lock_guard<std::mutex> lock(fatalMessageBufMutex);
348         (void)memcpy_s(g_hiLogLastFatalMessage, sizeof(g_hiLogLastFatalMessage), buf, sizeof(buf));
349     }
350 
351 #if not (defined( __WINDOWS__ ) || defined( __MAC__ ) || defined( __LINUX__ ))
352     /* flow control */
353     if (!IsDebugOn() && IsNeedProcFlowCtr(type)) {
354         ret = HiLogFlowCtrlProcess(tagLen + logLen - traceBufLen, ts_mono);
355         if (ret < 0) {
356             return ret;
357         } else if (ret > 0) {
358             static const char P_LIMIT_TAG[] = "LOGLIMIT";
359             uint16_t level = header.level;
360             header.level = LOG_WARN;
361             char dropLogBuf[MAX_LOG_LEN] = {0};
362             if (snprintf_s(dropLogBuf, MAX_LOG_LEN, MAX_LOG_LEN - 1,
363                 "==LOGS OVER PROC QUOTA, %d DROPPED==", ret) > 0) {
364                 HilogWriteLogMessage(&header, P_LIMIT_TAG, strlen(P_LIMIT_TAG) + 1, dropLogBuf,
365                     strnlen(dropLogBuf, MAX_LOG_LEN - 1) + 1);
366             }
367             header.level = level;
368         }
369     }
370     return HilogWriteLogMessage(&header, tag, tagLen + 1, buf, logLen + 1);
371 #else
372     return PrintLog(header, tag, tagLen + 1, buf, logLen + 1);
373 #endif
374 }
375 
HiLogPrint(LogType type,LogLevel level,unsigned int domain,const char * tag,const char * fmt,...)376 int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)
377 {
378     int ret;
379     va_list ap;
380     va_start(ap, fmt);
381     ret = HiLogPrintArgs(type, level, domain, tag, fmt, ap);
382     va_end(ap);
383     return ret;
384 }
385 
IsAppDomain(const unsigned int domain)386 static bool IsAppDomain(const unsigned int domain)
387 {
388     return ((domain >= DOMAIN_APP_MIN) && (domain <= DOMAIN_APP_MAX));
389 }
390 
HiLogIsLoggable(unsigned int domain,const char * tag,LogLevel level)391 bool HiLogIsLoggable(unsigned int domain, const char *tag, LogLevel level)
392 {
393     if (IsAppDomain(domain) && level < g_logLevel) {
394         return false;
395     }
396     if ((level <= LOG_LEVEL_MIN) || (level >= LOG_LEVEL_MAX) || (tag == nullptr) || (domain >= DOMAIN_OS_MAX)) {
397         return false;
398     }
399     if (level < GetFinalLevel(domain, tag)) {
400         return false;
401     }
402     return true;
403 }
404