• 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 
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