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