1 /*
2 * Copyright (c) 2022 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 <sys/time.h>
16 #include <iomanip>
17 #include <map>
18 #include <securec.h>
19 #include <hilog/log.h>
20
21 #include "hilog_common.h"
22 #include "log_utils.h"
23 #include "log_print.h"
24
25 namespace OHOS {
26 namespace HiviewDFX {
27 using namespace std;
28
29 static constexpr int COLOR_BLUE = 75;
30 static constexpr int COLOR_DEFAULT = 231;
31 static constexpr int COLOR_GREEN = 40;
32 static constexpr int COLOR_ORANGE = 166;
33 static constexpr int COLOR_RED = 196;
34 static constexpr int COLOR_YELLOW = 226;
35 static constexpr int TM_YEAR_BASE = 1900;
36 static constexpr int DT_WIDTH = 2;
37 static constexpr long long NS2US = 1000LL;
38 static constexpr long long NS2MS = 1000000LL;
39 static constexpr int MONO_WIDTH = 8;
40 static constexpr int EPOCH_WIDTH = 10;
41 static constexpr int MSEC_WIDTH = 3;
42 static constexpr int USEC_WIDTH = 6;
43 static constexpr int NSEC_WIDTH = 9;
44 static constexpr int PID_WIDTH = 5;
45 static constexpr int DOMAIN_WIDTH = 5;
46 static constexpr int DOMAIN_SHORT_MASK = 0xFFFFF;
47 static constexpr int PREFIX_LEN = 42;
48
GetColor(uint16_t level)49 static inline int GetColor(uint16_t level)
50 {
51 switch (LogLevel(level)) {
52 case LOG_DEBUG: return COLOR_BLUE;
53 case LOG_INFO: return COLOR_GREEN;
54 case LOG_WARN: return COLOR_ORANGE;
55 case LOG_ERROR: return COLOR_RED;
56 case LOG_FATAL: return COLOR_YELLOW;
57 default: return COLOR_DEFAULT;
58 }
59 }
60
GetLogTypePrefix(uint16_t type)61 static inline const char* GetLogTypePrefix(uint16_t type)
62 {
63 switch (LogType(type)) {
64 case LOG_APP: return "A";
65 case LOG_INIT: return "I";
66 case LOG_CORE: return "C";
67 case LOG_KMSG: return "K";
68 case LOG_ONLY_PRERELEASE: return "P";
69 default: return " ";
70 }
71 }
72
ShortDomain(uint32_t d)73 static inline uint32_t ShortDomain(uint32_t d)
74 {
75 return (d) & DOMAIN_SHORT_MASK;
76 }
77
PrintLogPrefix(const LogContent & content,const LogFormat & format,std::ostream & out)78 static void PrintLogPrefix(const LogContent& content, const LogFormat& format, std::ostream& out)
79 {
80 // 1. print day & time
81 if (format.timeFormat == FormatTime::TIME) {
82 struct tm tl;
83 time_t time = content.tv_sec;
84 #if (defined( __WINDOWS__ ))
85 if (localtime_s(&tl, &time) != 0) {
86 return;
87 }
88 #else
89 if (localtime_r(&time, &tl) == nullptr) {
90 return;
91 }
92 if (format.zone) {
93 out << tl.tm_zone << " ";
94 }
95 #endif
96 if (format.year) {
97 out << (tl.tm_year + TM_YEAR_BASE) << "-";
98 }
99 out << setfill('0');
100 out << setw(DT_WIDTH) << (tl.tm_mon + 1) << "-" << setw(DT_WIDTH) << tl.tm_mday << " ";
101 out << setw(DT_WIDTH) << tl.tm_hour << ":" << setw(DT_WIDTH) << tl.tm_min << ":";
102 out << setw(DT_WIDTH) << tl.tm_sec;
103 } else if (format.timeFormat == FormatTime::MONOTONIC) {
104 out << setfill(' ');
105 out << setw(MONO_WIDTH) << content.mono_sec;
106 } else if (format.timeFormat == FormatTime::EPOCH) {
107 out << setfill(' ');
108 out << setw(EPOCH_WIDTH) << content.tv_sec;
109 } else {
110 out << "Invalid time format" << endl;
111 return;
112 }
113 // 1.1 print msec/usec/nsec
114 out << ".";
115 out << setfill('0');
116 if (format.timeAccuFormat == FormatTimeAccu::MSEC) {
117 out << setw(MSEC_WIDTH) << (content.tv_nsec / NS2MS);
118 } else if (format.timeAccuFormat == FormatTimeAccu::USEC) {
119 out << setw(USEC_WIDTH) << (content.tv_nsec / NS2US);
120 } else if (format.timeAccuFormat == FormatTimeAccu::NSEC) {
121 out << setw(NSEC_WIDTH) << content.tv_nsec;
122 } else {
123 out << "Invalid time accuracy format" << endl;
124 return;
125 }
126 // The kmsg logs are taken from /proc/kmsg, cannot obtain pid, tid or domain information
127 // The kmsg log printing format: 08-06 16:51:04.945 <6> [4294.967295] hungtask_base whitelist[0]-init-1
128 if (content.type != LOG_KMSG) {
129 out << setfill(' ');
130 // 2. print pid/tid
131 out << " " << setw(PID_WIDTH) << content.pid << " " << setw(PID_WIDTH) << content.tid;
132 // 3. print level
133 out << " " << LogLevel2ShortStr(content.level) << " ";
134 // 4. print log type
135 out << GetLogTypePrefix(content.type);
136 // 5. print domain
137 out << setfill('0');
138 out << hex << setw(DOMAIN_WIDTH) << ShortDomain(content.domain) << dec;
139 // 5. print tag & log
140 out << "/" << content.tag << ": ";
141 } else {
142 out << " " << content.tag << " ";
143 }
144 }
145
AdaptWrap(const LogContent & content,const LogFormat & format,std::ostream & out)146 static void AdaptWrap(const LogContent& content, const LogFormat& format, std::ostream& out)
147 {
148 if (format.wrap) {
149 out << setfill(' ');
150 out << std::setw(PREFIX_LEN + StringToWstring(content.tag).length()) << " ";
151 } else {
152 PrintLogPrefix(content, format, out);
153 }
154 }
155
LogPrintWithFormat(const LogContent & content,const LogFormat & format,std::ostream & out)156 void LogPrintWithFormat(const LogContent& content, const LogFormat& format, std::ostream& out)
157 {
158 // set colorful log
159 if (format.colorful) {
160 out << "\x1B[38;5;" << GetColor(content.level) << "m";
161 }
162
163 const char *pHead = content.log;
164 const char *pScan = content.log;
165 // not print prefix if log is empty string or start with \n
166 if (*pScan != '\0' && *pScan != '\n') {
167 PrintLogPrefix(content, format, out);
168 }
169 // split the log content by '\n', and add log prefix(datetime, pid, tid....) to each new line
170 while (*pScan != '\0') {
171 if (*pScan == '\n') {
172 char tmp[MAX_LOG_LEN];
173 int len = static_cast<int>(pScan - pHead);
174 errno_t ret = memcpy_s(tmp, MAX_LOG_LEN - 1, pHead, len);
175 if (ret != EOK) {
176 break;
177 }
178 tmp[(MAX_LOG_LEN - 1) > len ? len : (MAX_LOG_LEN -1)] = '\0';
179 if (tmp[0] != '\0') {
180 out << tmp << endl;
181 }
182 pHead = pScan + 1;
183 if (pHead[0] != '\0' && pHead[0] != '\n') {
184 AdaptWrap(content, format, out);
185 }
186 }
187 pScan++;
188 }
189 if (pHead[0] != '\0') {
190 out << pHead;
191 }
192
193 // restore color
194 if (format.colorful) {
195 out << "\x1B[0m";
196 }
197 if (pHead[0] != '\0') {
198 out << endl;
199 }
200 return;
201 }
202 } // namespace HiviewDFX
203 } // namespace OHOS