• 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 
16 #include <cstring>
17 #include <iostream>
18 #include <queue>
19 #include <vector>
20 #include <regex>
21 #include <unordered_map>
22 #include "hilog/log.h"
23 #include "format.h"
24 #include "log_controller.h"
25 #include "log_display.h"
26 
27 namespace OHOS {
28 namespace HiviewDFX {
29 using namespace std;
30 
31 using hash_t = std::uint64_t;
32 unordered_map<uint16_t, std::string> errorMsg
33 {
34     {RET_FAIL, "Unexpected error"},
35     {ERR_LOG_LEVEL_INVALID, "Invalid log level, the valid log levels include D/I/W/E/F"},
36     {ERR_LOG_TYPE_INVALID, "Invalid log type, the valid log types include app/core/init/kmsg"},
37     {ERR_QUERY_TYPE_INVALID, "Query condition on both types and excluded types is undefined or\
38     queryTypes can not contain app/core/init and kmsg at the same time"},
39     {ERR_QUERY_LEVEL_INVALID, "Query condition on both levels and excluded levels is undefined"},
40     {ERR_QUERY_DOMAIN_INVALID, "Invalid domain format, a hexadecimal number is needed"},
41     {ERR_QUERY_TAG_INVALID, "Query condition on both tags and excluded tags is undefined"},
42     {ERR_QUERY_PID_INVALID, "Query condition on both pid and excluded pid is undefined"},
43     {ERR_BUFF_SIZE_EXP, "Buffer resize exception"},
44     {ERR_LOG_PERSIST_FILE_SIZE_INVALID, "Invalid log persist file size, file size should be not less than "
45     + to_string(MAX_PERSISTER_BUFFER_SIZE)},
46     {ERR_LOG_PERSIST_FILE_NAME_INVALID, "Invalid log persist file name, file name should not contain [\\/:*?\"<>|]"},
47     {ERR_LOG_PERSIST_COMPRESS_BUFFER_EXP, "Invalid Log persist compression buffer"},
48     {ERR_LOG_PERSIST_FILE_PATH_INVALID, "Invalid persister file path or persister directory does not exist"},
49     {ERR_LOG_PERSIST_COMPRESS_INIT_FAIL, "Log persist compression initialization failed"},
50     {ERR_LOG_PERSIST_FILE_OPEN_FAIL, "Log persist open file failed"},
51     {ERR_LOG_PERSIST_MMAP_FAIL, "Log persist mmap failed"},
52     {ERR_LOG_PERSIST_JOBID_FAIL, "Log persist jobid not exist"},
53     {ERR_LOG_PERSIST_TASK_FAIL, "Log persist task is existed"},
54     {ERR_DOMAIN_INVALID, "Invalid domain, domain should not be  more than 0 and less than "
55     + to_string(DOMAIN_MAX_SCOPE)},
56     {ERR_MEM_ALLOC_FAIL, "Alloc memory failed"},
57     {ERR_MSG_LEN_INVALID, "Invalid message length, message length should be not more than "
58     + to_string(MSG_MAX_LEN)},
59     {ERR_PRIVATE_SWITCH_VALUE_INVALID, "Invalid private switch value, valid:on/off"},
60     {ERR_FLOWCTRL_SWITCH_VALUE_INVALID, "Invalid flowcontrl switch value, valid:pidon/pidoff/domainon/domainoff"},
61     {ERR_LOG_PERSIST_JOBID_INVALID, "Invalid jobid, jobid should be more than 0"},
62     {ERR_LOG_CONTENT_NULL, "Log content NULL"},
63     {ERR_COMMAND_NOT_FOUND, "Command not found"},
64     {ERR_FORMAT_INVALID, "Invalid format parameter"},
65     {ERR_BUFF_SIZE_INVALID, "Invalid buffer size, buffer size should be more than 0 and less than "
66     + to_string(MAX_BUFFER_SIZE)},
67     {ERR_COMMAND_INVALID, "Invalid command, only one control command can be executed each time"},
68     {ERR_KMSG_SWITCH_VALUE_INVALID, "Invalid kmsg switch value, valid:on/off"},
69     {ERR_LOG_FILE_NUM_INVALID, "Invalid log number, log number should be more than " + to_string(MIN_LOG_FILE_NUM)
70     + " and less than " + to_string(MAX_LOG_FILE_NUM)},
71 };
72 
ParseErrorCode(ErrorCode errorCode)73 string ParseErrorCode(ErrorCode errorCode)
74 {
75     if (errorMsg.count(errorCode) == 0) {
76         cout << "ERR_CODE not exist" << endl;
77     }
78     string errorMsgStr = "[ERR_CODE:" + to_string(errorCode) + "], " + errorMsg[errorCode];
79     return errorMsgStr;
80 }
81 
Hash(char const * str)82 hash_t Hash(char const *str)
83 {
84     hash_t ret {BASIS};
85     while (*str) {
86         ret ^= *str;
87         ret *= PRIME;
88         str++;
89     }
90     return ret;
91 }
HashCompileTime(char const * str,hash_t lastValue=BASIS)92 constexpr hash_t HashCompileTime(char const *str, hash_t lastValue = BASIS)
93 {
94     return *str ? HashCompileTime(str + 1, (*str ^ lastValue) * PRIME) : lastValue;
95 }
operator ""_hash(char const * p,size_t)96 constexpr unsigned long long operator "" _hash(char const *p, size_t)
97 {
98     return HashCompileTime(p);
99 }
100 
GetLogTypeStr(uint16_t logType)101 string GetLogTypeStr(uint16_t logType)
102 {
103     string logTypeStr = "invalid";
104     if (logType == LOG_INIT) {
105         logTypeStr = "init";
106     }
107     if (logType == LOG_CORE) {
108         logTypeStr = "core";
109     }
110     if (logType == LOG_APP) {
111         logTypeStr = "app";
112     }
113     if (logType == LOG_KMSG) {
114         logTypeStr = "kmsg";
115     }
116     return logTypeStr;
117 }
118 
GetOrigType(uint16_t shiftType)119 string GetOrigType(uint16_t shiftType)
120 {
121     string logType = "";
122     if (((1 << LOG_INIT) & shiftType) != 0) {
123         logType += "init,";
124     }
125     if (((1 << LOG_CORE) & shiftType) != 0) {
126         logType += "core,";
127     }
128     if (((1 << LOG_APP) & shiftType) != 0) {
129         logType += "app,";
130     }
131     if (((1 << LOG_KMSG) & shiftType) != 0) {
132         logType += "kmsg,";
133     }
134     logType.erase(logType.end() - 1);
135     return logType;
136 }
137 
GetPressAlgStr(uint16_t pressAlg)138 string GetPressAlgStr(uint16_t pressAlg)
139 {
140     string pressAlgStr;
141     if (pressAlg == COMPRESS_TYPE_ZSTD) {
142         pressAlgStr = "zstd";
143     }
144     if (pressAlg == COMPRESS_TYPE_ZLIB) {
145         pressAlgStr = "zlib";
146     }
147     return pressAlgStr;
148 }
149 
GetByteLenStr(uint64_t buffSize)150 string GetByteLenStr(uint64_t buffSize)
151 {
152     string buffSizeStr;
153     if (buffSize < ONE_KB) {
154         buffSizeStr += to_string(buffSize);
155         buffSizeStr += "B";
156     } else if (buffSize < ONE_MB) {
157         buffSize = buffSize / ONE_KB;
158         buffSizeStr += to_string(buffSize);
159         buffSizeStr += "K";
160     } else if (buffSize < ONE_GB) {
161         buffSize = buffSize / ONE_MB;
162         buffSizeStr += to_string(buffSize);
163         buffSizeStr += "M";
164     } else if (buffSize < ONE_TB) {
165         buffSize = buffSize / ONE_GB;
166         buffSizeStr += to_string(buffSize);
167         buffSizeStr += "G";
168     } else {
169         buffSize = buffSize / ONE_TB;
170         buffSizeStr += to_string(buffSize);
171         buffSizeStr += "T";
172     }
173     return buffSizeStr;
174 }
175 
176 /*
177  * print control command operation result
178  */
ControlCmdResult(const char * message)179 int32_t ControlCmdResult(const char* message)
180 {
181     MessageHeader* msgHeader = (MessageHeader*)message;
182     uint8_t msgCmd = msgHeader->msgType;
183     uint16_t msgLen = msgHeader->msgLen;
184     string outputStr = "";
185     uint32_t resultLen = 0;
186     switch (msgCmd) {
187         case MC_RSP_BUFFER_SIZE: {
188             BufferSizeResponse* pBuffSizeRsp = (BufferSizeResponse*)message;
189             if (!pBuffSizeRsp) {
190                 return RET_FAIL;
191             }
192             BuffSizeResult* pBuffSizeRst = (BuffSizeResult*)&pBuffSizeRsp->buffSizeRst;
193             while (pBuffSizeRst && resultLen < msgLen) {
194                 if (pBuffSizeRst->result < 0) {
195                     outputStr += GetLogTypeStr(pBuffSizeRst->logType);
196                     outputStr += " buffer size fail\n";
197                     outputStr += ParseErrorCode((ErrorCode)pBuffSizeRst->result);
198                     outputStr += "\n";
199                 } else {
200                     outputStr += GetLogTypeStr(pBuffSizeRst->logType);
201                     outputStr += " buffer size is ";
202                     outputStr += GetByteLenStr(pBuffSizeRst->buffSize);
203                     outputStr += "\n";
204                 }
205                 pBuffSizeRst++;
206                 resultLen += sizeof(BuffSizeResult);
207             }
208             break;
209         }
210         case MC_RSP_BUFFER_RESIZE: {
211             BufferResizeResponse* pBuffResizeRsp = (BufferResizeResponse*)message;
212             if (!pBuffResizeRsp) {
213                 return RET_FAIL;
214             }
215             BuffResizeResult* pBuffResizeRst = (BuffResizeResult*)&pBuffResizeRsp->buffResizeRst;
216             while (pBuffResizeRst && resultLen < msgLen) {
217                 if (pBuffResizeRst->result < 0) {
218                     outputStr += GetLogTypeStr(pBuffResizeRst->logType);
219                     outputStr += " buffer resize fail\n";
220                     outputStr += ParseErrorCode((ErrorCode)pBuffResizeRst->result);
221                     outputStr += "\n";
222                 } else {
223                     outputStr += GetLogTypeStr(pBuffResizeRst->logType);
224                     outputStr += " buffer size is ";
225                     outputStr += GetByteLenStr(pBuffResizeRst->buffSize);
226                     outputStr += "\n";
227                 }
228                 pBuffResizeRst++;
229                 resultLen += sizeof(BuffSizeResult);
230             }
231             break;
232         }
233         case MC_RSP_STATISTIC_INFO_QUERY: {
234             StatisticInfoQueryResponse* staInfoQueryRsp = (StatisticInfoQueryResponse*)message;
235             string logOrDomain;
236             if (!staInfoQueryRsp) {
237                 return RET_FAIL;
238             }
239             if (staInfoQueryRsp->domain != 0xffffffff) {
240                 logOrDomain = to_string(staInfoQueryRsp->domain);
241             } else {
242                 logOrDomain = GetLogTypeStr(staInfoQueryRsp->logType);
243             }
244             if (staInfoQueryRsp->result == RET_SUCCESS) {
245                 outputStr += logOrDomain;
246                 outputStr += " print log length is ";
247                 outputStr += GetByteLenStr(staInfoQueryRsp->printLen);
248                 outputStr += "\n";
249                 outputStr += logOrDomain;
250                 outputStr += " cache log length is ";
251                 outputStr += GetByteLenStr(staInfoQueryRsp->cacheLen);
252                 outputStr += "\n";
253                 outputStr += logOrDomain;
254                 outputStr += " dropped log lines is ";
255                 outputStr += GetByteLenStr(staInfoQueryRsp->dropped);
256             } else if (staInfoQueryRsp->result < 0) {
257                 outputStr += logOrDomain;
258                 outputStr += " statistic info query fail\n";
259                 outputStr += ParseErrorCode((ErrorCode)staInfoQueryRsp->result);
260             }
261             break;
262         }
263         case MC_RSP_STATISTIC_INFO_CLEAR: {
264             StatisticInfoClearResponse* staInfoClearRsp = (StatisticInfoClearResponse*)message;
265             string logOrDomain;
266             if (!staInfoClearRsp) {
267                 return RET_FAIL;
268             }
269             if (staInfoClearRsp->domain != 0xffffffff) {
270                 logOrDomain = to_string(staInfoClearRsp->domain);
271             } else {
272                 logOrDomain = GetLogTypeStr(staInfoClearRsp->logType);
273             }
274             if (staInfoClearRsp->result == RET_SUCCESS) {
275                 outputStr += logOrDomain;
276                 outputStr += " statistic info clear success ";
277             } else if (staInfoClearRsp->result < 0) {
278                 outputStr += logOrDomain;
279                 outputStr += " statistic info clear fail\n";
280                 outputStr += ParseErrorCode((ErrorCode)staInfoClearRsp->result);
281             }
282             break;
283         }
284         case MC_RSP_LOG_CLEAR: {
285             LogClearResponse* pLogClearRsp = (LogClearResponse*)message;
286             if (!pLogClearRsp) {
287                 RET_FAIL;
288             }
289             LogClearResult* pLogClearRst = (LogClearResult*)&pLogClearRsp->logClearRst;
290             while (pLogClearRst && resultLen < msgLen) {
291                 if (pLogClearRst->result < 0) {
292                     outputStr += GetLogTypeStr(pLogClearRst->logType);
293                     outputStr += " log clear fail\n";
294                     outputStr += ParseErrorCode((ErrorCode)pLogClearRst->result);
295                     outputStr += "\n";
296                 } else {
297                     outputStr += GetLogTypeStr(pLogClearRst->logType);
298                     outputStr += " log clear success ";
299                     outputStr += "\n";
300                 }
301                 pLogClearRst++;
302                 resultLen += sizeof(LogClearResult);
303             }
304             break;
305         }
306         case MC_RSP_LOG_PERSIST_START: {
307             LogPersistStartResponse* pLogPersistStartRsp = (LogPersistStartResponse*)message;
308             if (!pLogPersistStartRsp) {
309                 return RET_FAIL;
310             }
311             LogPersistStartResult* pLogPersistStartRst =
312                 (LogPersistStartResult*)&pLogPersistStartRsp->logPersistStartRst;
313             while (pLogPersistStartRst && resultLen < msgLen) {
314                 if (pLogPersistStartRst->result < 0) {
315                     outputStr += "Persist task [jobid:";
316                     outputStr += to_string(pLogPersistStartRst->jobId);
317                     outputStr += "] start failed\n";
318                     outputStr += ParseErrorCode((ErrorCode)pLogPersistStartRst->result);
319                 } else {
320                     outputStr += "Persist task [jobid:";
321                     outputStr += to_string(pLogPersistStartRst->jobId);
322                     outputStr += "] started successfully\n";
323                 }
324                 pLogPersistStartRst++;
325                 resultLen += sizeof(LogPersistStartResult);
326             }
327             break;
328         }
329         case MC_RSP_LOG_PERSIST_STOP: {
330             LogPersistStopResponse* pLogPersistStopRsp = (LogPersistStopResponse*)message;
331             if (!pLogPersistStopRsp) {
332                 return RET_FAIL;
333             }
334             LogPersistStopResult* pLogPersistStopRst = (LogPersistStopResult*)&pLogPersistStopRsp->logPersistStopRst;
335             while (pLogPersistStopRst && resultLen < msgLen) {
336                 if (pLogPersistStopRst->result < 0) {
337                     outputStr += "Persist task [jobid:";
338                     outputStr += to_string(pLogPersistStopRst->jobId);
339                     outputStr += "] stop failed\n";
340                     outputStr += ParseErrorCode((ErrorCode)pLogPersistStopRst->result);
341                 } else {
342                     outputStr += "Persist task [jobid:";
343                     outputStr += to_string(pLogPersistStopRst->jobId);
344                     outputStr += "] stopped successfully\n";
345                 }
346                 pLogPersistStopRst++;
347                 resultLen += sizeof(LogPersistStopResult);
348             }
349             break;
350         }
351         case MC_RSP_LOG_PERSIST_QUERY: {
352             LogPersistQueryResponse* pLogPersistQueryRsp = (LogPersistQueryResponse*)message;
353             if (!pLogPersistQueryRsp) {
354                 return RET_FAIL;
355             }
356             LogPersistQueryResult* pLogPersistQueryRst =
357                 (LogPersistQueryResult*)&pLogPersistQueryRsp->logPersistQueryRst;
358             while (pLogPersistQueryRst && resultLen < msgLen) {
359                 if (pLogPersistQueryRst->result < 0) {
360                     outputStr = "Persist task [logtype:";
361                     outputStr += GetLogTypeStr(pLogPersistQueryRst->logType);
362                     outputStr += "] query failed\n";
363                     outputStr += ParseErrorCode((ErrorCode)pLogPersistQueryRst->result);
364                 } else {
365                     outputStr += to_string(pLogPersistQueryRst->jobId);
366                     outputStr += " ";
367                     outputStr += GetOrigType(pLogPersistQueryRst->logType);
368                     outputStr += " ";
369                     outputStr += GetPressAlgStr(pLogPersistQueryRst->compressAlg);
370                     outputStr += " ";
371                     outputStr += pLogPersistQueryRst->filePath;
372                     outputStr += " ";
373                     outputStr += to_string(pLogPersistQueryRst->fileSize);
374                     outputStr += " ";
375                     outputStr += to_string(pLogPersistQueryRst->fileNum);
376                     outputStr += "\n";
377                 }
378                 pLogPersistQueryRst++;
379                 resultLen += sizeof(LogPersistQueryResult);
380             }
381             break;
382         }
383         default:
384             break;
385     }
386     cout << outputStr << endl;
387     return 0;
388 }
389 
HilogFormat(const char * formatArg)390 HilogShowFormat HilogFormat (const char* formatArg)
391 {
392     static HilogShowFormat format;
393 
394     switch (Hash(formatArg)) {
395         case "color"_hash:
396             format = COLOR_SHOWFORMAT;
397             break;
398         case "colour"_hash:
399             format = COLOR_SHOWFORMAT;
400             break;
401         case "time"_hash:
402             format = TIME_SHOWFORMAT;
403             break;
404         case "usec"_hash:
405             format = TIME_USEC_SHOWFORMAT;
406             break;
407         case "nsec"_hash:
408             format = TIME_NSEC_SHOWFORMAT;
409             break;
410         case "year"_hash:
411             format = YEAR_SHOWFORMAT;
412             break;
413         case "zone"_hash:
414             format = ZONE_SHOWFORMAT;
415             break;
416         case "epoch"_hash:
417             format = EPOCH_SHOWFORMAT;
418             break;
419         case "monotonic"_hash:
420             format = MONOTONIC_SHOWFORMAT;
421             break;
422         default:
423             cout << ParseErrorCode(ERR_FORMAT_INVALID) << endl;
424             exit(1);
425     }
426     return format;
427 }
428 
429 /*
430  * Match the logs according to the regular expression
431 */
HilogMatchByRegex(string context,string regExpArg)432 bool HilogMatchByRegex(string context, string regExpArg)
433 {
434     smatch regExpSmatch;
435     regex regExp(regExpArg);
436     if (regex_search(context, regExpSmatch, regExp)) {
437         return false;
438     } else {
439         return true;
440     }
441 }
442 
HilogShowLog(uint32_t showFormat,HilogDataMessage * data,const HilogArgs * context,vector<string> & tailBuffer)443 void HilogShowLog(uint32_t showFormat, HilogDataMessage* data, const HilogArgs* context,
444     vector<string>& tailBuffer)
445 {
446     if (data->sendId == SENDIDN) {
447         return;
448     }
449 
450     if (data->length == 0) {
451         std::cout << ParseErrorCode(ERR_LOG_CONTENT_NULL) << endl;
452         return;
453     }
454 
455     static int printHeadCnt = 0;
456     HilogShowFormatBuffer showBuffer;
457     const char* content = data->data + data->tag_len;
458 
459     if (context->headLines) {
460         if (printHeadCnt++ >= context->headLines) {
461             exit(1);
462         }
463     }
464     if (context->regexArgs != "") {
465         string str = content;
466         if (HilogMatchByRegex(str, context->regexArgs)) {
467             return;
468         }
469     }
470 
471     char buffer[MAX_LOG_LEN + MAX_LOG_LEN];
472     showBuffer.level = data->level;
473     showBuffer.pid = data->pid;
474     showBuffer.tid = data->tid;
475     showBuffer.domain = data->domain;
476     showBuffer.tag_len = data->tag_len;
477     showBuffer.tv_sec = data->tv_sec;
478     showBuffer.tv_nsec = data->tv_nsec;
479     auto offset = data->tag_len;
480     const char *dataBegin = data->data + offset;
481     char *dataPos = data->data + offset;
482     while (*dataPos != 0) {
483         if (*dataPos == '\n') {
484             if (dataPos != dataBegin) {
485                 *dataPos = 0;
486                 showBuffer.tag_len = offset;
487                 showBuffer.data = data->data;
488                 HilogShowBuffer(buffer, MAX_LOG_LEN + MAX_LOG_LEN, showBuffer, showFormat);
489                 if (context->tailLines) {
490                     tailBuffer.emplace_back(buffer);
491                     return;
492                 } else {
493                     cout << buffer << endl;
494                 }
495                 offset += dataPos - dataBegin + 1;
496             } else {
497                 offset++;
498             }
499             dataBegin = dataPos + 1;
500         }
501         dataPos++;
502     }
503     if (dataPos != dataBegin) {
504         showBuffer.data = data->data;
505         HilogShowBuffer(buffer, MAX_LOG_LEN + MAX_LOG_LEN, showBuffer, showFormat);
506         if (context->tailLines) {
507             tailBuffer.emplace_back(buffer);
508             return;
509         } else {
510             cout << buffer << endl;
511         }
512     }
513     return;
514 }
515 } // namespace HiviewDFX
516 } // namespace OHOS
517