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 25namespace OHOS { 26namespace HiviewDFX { 27using namespace std; 28 29static constexpr int COLOR_BLUE = 75; 30static constexpr int COLOR_DEFAULT = 231; 31static constexpr int COLOR_GREEN = 40; 32static constexpr int COLOR_ORANGE = 166; 33static constexpr int COLOR_RED = 196; 34static constexpr int COLOR_YELLOW = 226; 35static constexpr int TM_YEAR_BASE = 1900; 36static constexpr int DT_WIDTH = 2; 37static constexpr long long NS2US = 1000LL; 38static constexpr long long NS2MS = 1000000LL; 39static constexpr int MONO_WIDTH = 8; 40static constexpr int EPOCH_WIDTH = 10; 41static constexpr int MSEC_WIDTH = 3; 42static constexpr int USEC_WIDTH = 6; 43static constexpr int NSEC_WIDTH = 9; 44static constexpr int PID_WIDTH = 5; 45static constexpr int DOMAIN_WIDTH = 5; 46static constexpr int DOMAIN_SHORT_MASK = 0xFFFFF; 47static constexpr int PREFIX_LEN = 42; 48 49static 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 61static 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 73static inline uint32_t ShortDomain(uint32_t d) 74{ 75 return (d) & DOMAIN_SHORT_MASK; 76} 77 78static 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 146static 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 156void 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