12498b56bSopenharmony_ci/*
22498b56bSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
32498b56bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
42498b56bSopenharmony_ci * you may not use this file except in compliance with the License.
52498b56bSopenharmony_ci * You may obtain a copy of the License at
62498b56bSopenharmony_ci *
72498b56bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
82498b56bSopenharmony_ci *
92498b56bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
102498b56bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
112498b56bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
122498b56bSopenharmony_ci * See the License for the specific language governing permissions and
132498b56bSopenharmony_ci * limitations under the License.
142498b56bSopenharmony_ci */
152498b56bSopenharmony_ci#include <sys/time.h>
162498b56bSopenharmony_ci#include <iomanip>
172498b56bSopenharmony_ci#include <map>
182498b56bSopenharmony_ci#include <securec.h>
192498b56bSopenharmony_ci#include <hilog/log.h>
202498b56bSopenharmony_ci
212498b56bSopenharmony_ci#include "hilog_common.h"
222498b56bSopenharmony_ci#include "log_utils.h"
232498b56bSopenharmony_ci#include "log_print.h"
242498b56bSopenharmony_ci
252498b56bSopenharmony_cinamespace OHOS {
262498b56bSopenharmony_cinamespace HiviewDFX {
272498b56bSopenharmony_ciusing namespace std;
282498b56bSopenharmony_ci
292498b56bSopenharmony_cistatic constexpr int COLOR_BLUE = 75;
302498b56bSopenharmony_cistatic constexpr int COLOR_DEFAULT = 231;
312498b56bSopenharmony_cistatic constexpr int COLOR_GREEN = 40;
322498b56bSopenharmony_cistatic constexpr int COLOR_ORANGE = 166;
332498b56bSopenharmony_cistatic constexpr int COLOR_RED = 196;
342498b56bSopenharmony_cistatic constexpr int COLOR_YELLOW = 226;
352498b56bSopenharmony_cistatic constexpr int TM_YEAR_BASE = 1900;
362498b56bSopenharmony_cistatic constexpr int DT_WIDTH = 2;
372498b56bSopenharmony_cistatic constexpr long long NS2US = 1000LL;
382498b56bSopenharmony_cistatic constexpr long long NS2MS = 1000000LL;
392498b56bSopenharmony_cistatic constexpr int MONO_WIDTH = 8;
402498b56bSopenharmony_cistatic constexpr int EPOCH_WIDTH = 10;
412498b56bSopenharmony_cistatic constexpr int MSEC_WIDTH = 3;
422498b56bSopenharmony_cistatic constexpr int USEC_WIDTH = 6;
432498b56bSopenharmony_cistatic constexpr int NSEC_WIDTH = 9;
442498b56bSopenharmony_cistatic constexpr int PID_WIDTH = 5;
452498b56bSopenharmony_cistatic constexpr int DOMAIN_WIDTH = 5;
462498b56bSopenharmony_cistatic constexpr int DOMAIN_SHORT_MASK = 0xFFFFF;
472498b56bSopenharmony_cistatic constexpr int PREFIX_LEN = 42;
482498b56bSopenharmony_ci
492498b56bSopenharmony_cistatic inline int GetColor(uint16_t level)
502498b56bSopenharmony_ci{
512498b56bSopenharmony_ci    switch (LogLevel(level)) {
522498b56bSopenharmony_ci        case LOG_DEBUG: return COLOR_BLUE;
532498b56bSopenharmony_ci        case LOG_INFO: return COLOR_GREEN;
542498b56bSopenharmony_ci        case LOG_WARN: return COLOR_ORANGE;
552498b56bSopenharmony_ci        case LOG_ERROR: return COLOR_RED;
562498b56bSopenharmony_ci        case LOG_FATAL: return COLOR_YELLOW;
572498b56bSopenharmony_ci        default: return COLOR_DEFAULT;
582498b56bSopenharmony_ci    }
592498b56bSopenharmony_ci}
602498b56bSopenharmony_ci
612498b56bSopenharmony_cistatic inline const char* GetLogTypePrefix(uint16_t type)
622498b56bSopenharmony_ci{
632498b56bSopenharmony_ci    switch (LogType(type)) {
642498b56bSopenharmony_ci        case LOG_APP: return "A";
652498b56bSopenharmony_ci        case LOG_INIT: return "I";
662498b56bSopenharmony_ci        case LOG_CORE: return "C";
672498b56bSopenharmony_ci        case LOG_KMSG: return "K";
682498b56bSopenharmony_ci        case LOG_ONLY_PRERELEASE: return "P";
692498b56bSopenharmony_ci        default: return " ";
702498b56bSopenharmony_ci    }
712498b56bSopenharmony_ci}
722498b56bSopenharmony_ci
732498b56bSopenharmony_cistatic inline uint32_t ShortDomain(uint32_t d)
742498b56bSopenharmony_ci{
752498b56bSopenharmony_ci    return (d) & DOMAIN_SHORT_MASK;
762498b56bSopenharmony_ci}
772498b56bSopenharmony_ci
782498b56bSopenharmony_cistatic void PrintLogPrefix(const LogContent& content, const LogFormat& format, std::ostream& out)
792498b56bSopenharmony_ci{
802498b56bSopenharmony_ci    // 1. print day & time
812498b56bSopenharmony_ci    if (format.timeFormat == FormatTime::TIME) {
822498b56bSopenharmony_ci        struct tm tl;
832498b56bSopenharmony_ci        time_t time = content.tv_sec;
842498b56bSopenharmony_ci#if (defined( __WINDOWS__ ))
852498b56bSopenharmony_ci        if (localtime_s(&tl, &time) != 0) {
862498b56bSopenharmony_ci            return;
872498b56bSopenharmony_ci        }
882498b56bSopenharmony_ci#else
892498b56bSopenharmony_ci        if (localtime_r(&time, &tl) == nullptr) {
902498b56bSopenharmony_ci            return;
912498b56bSopenharmony_ci        }
922498b56bSopenharmony_ci        if (format.zone) {
932498b56bSopenharmony_ci            out << tl.tm_zone << " ";
942498b56bSopenharmony_ci        }
952498b56bSopenharmony_ci#endif
962498b56bSopenharmony_ci        if (format.year) {
972498b56bSopenharmony_ci            out << (tl.tm_year + TM_YEAR_BASE) << "-";
982498b56bSopenharmony_ci        }
992498b56bSopenharmony_ci        out << setfill('0');
1002498b56bSopenharmony_ci        out << setw(DT_WIDTH) << (tl.tm_mon + 1) << "-" << setw(DT_WIDTH) << tl.tm_mday << " ";
1012498b56bSopenharmony_ci        out << setw(DT_WIDTH) << tl.tm_hour << ":" << setw(DT_WIDTH) << tl.tm_min << ":";
1022498b56bSopenharmony_ci        out << setw(DT_WIDTH) << tl.tm_sec;
1032498b56bSopenharmony_ci    } else if (format.timeFormat == FormatTime::MONOTONIC) {
1042498b56bSopenharmony_ci        out << setfill(' ');
1052498b56bSopenharmony_ci        out << setw(MONO_WIDTH) << content.mono_sec;
1062498b56bSopenharmony_ci    } else if (format.timeFormat == FormatTime::EPOCH) {
1072498b56bSopenharmony_ci        out << setfill(' ');
1082498b56bSopenharmony_ci        out << setw(EPOCH_WIDTH) << content.tv_sec;
1092498b56bSopenharmony_ci    } else {
1102498b56bSopenharmony_ci        out << "Invalid time format" << endl;
1112498b56bSopenharmony_ci        return;
1122498b56bSopenharmony_ci    }
1132498b56bSopenharmony_ci    // 1.1 print msec/usec/nsec
1142498b56bSopenharmony_ci    out << ".";
1152498b56bSopenharmony_ci    out << setfill('0');
1162498b56bSopenharmony_ci    if (format.timeAccuFormat == FormatTimeAccu::MSEC) {
1172498b56bSopenharmony_ci        out << setw(MSEC_WIDTH) << (content.tv_nsec / NS2MS);
1182498b56bSopenharmony_ci    } else if (format.timeAccuFormat == FormatTimeAccu::USEC) {
1192498b56bSopenharmony_ci        out << setw(USEC_WIDTH) << (content.tv_nsec / NS2US);
1202498b56bSopenharmony_ci    } else if (format.timeAccuFormat == FormatTimeAccu::NSEC) {
1212498b56bSopenharmony_ci        out << setw(NSEC_WIDTH) << content.tv_nsec;
1222498b56bSopenharmony_ci    } else {
1232498b56bSopenharmony_ci        out << "Invalid time accuracy format" << endl;
1242498b56bSopenharmony_ci        return;
1252498b56bSopenharmony_ci    }
1262498b56bSopenharmony_ci    // The kmsg logs are taken from /proc/kmsg, cannot obtain pid, tid or domain information
1272498b56bSopenharmony_ci    // The kmsg log printing format: 08-06 16:51:04.945 <6> [4294.967295] hungtask_base whitelist[0]-init-1
1282498b56bSopenharmony_ci    if (content.type != LOG_KMSG) {
1292498b56bSopenharmony_ci        out << setfill(' ');
1302498b56bSopenharmony_ci        // 2. print pid/tid
1312498b56bSopenharmony_ci        out << " " << setw(PID_WIDTH) << content.pid << " " << setw(PID_WIDTH) << content.tid;
1322498b56bSopenharmony_ci        // 3. print level
1332498b56bSopenharmony_ci        out << " " << LogLevel2ShortStr(content.level) << " ";
1342498b56bSopenharmony_ci        // 4. print log type
1352498b56bSopenharmony_ci        out << GetLogTypePrefix(content.type);
1362498b56bSopenharmony_ci        // 5. print domain
1372498b56bSopenharmony_ci        out << setfill('0');
1382498b56bSopenharmony_ci        out << hex << setw(DOMAIN_WIDTH) << ShortDomain(content.domain) << dec;
1392498b56bSopenharmony_ci        // 5. print tag & log
1402498b56bSopenharmony_ci        out << "/" << content.tag << ": ";
1412498b56bSopenharmony_ci    } else {
1422498b56bSopenharmony_ci        out << " " << content.tag << " ";
1432498b56bSopenharmony_ci    }
1442498b56bSopenharmony_ci}
1452498b56bSopenharmony_ci
1462498b56bSopenharmony_cistatic void AdaptWrap(const LogContent& content, const LogFormat& format, std::ostream& out)
1472498b56bSopenharmony_ci{
1482498b56bSopenharmony_ci    if (format.wrap) {
1492498b56bSopenharmony_ci        out << setfill(' ');
1502498b56bSopenharmony_ci        out << std::setw(PREFIX_LEN + StringToWstring(content.tag).length()) << " ";
1512498b56bSopenharmony_ci    } else {
1522498b56bSopenharmony_ci        PrintLogPrefix(content, format, out);
1532498b56bSopenharmony_ci    }
1542498b56bSopenharmony_ci}
1552498b56bSopenharmony_ci
1562498b56bSopenharmony_civoid LogPrintWithFormat(const LogContent& content, const LogFormat& format, std::ostream& out)
1572498b56bSopenharmony_ci{
1582498b56bSopenharmony_ci    // set colorful log
1592498b56bSopenharmony_ci    if (format.colorful) {
1602498b56bSopenharmony_ci        out << "\x1B[38;5;" << GetColor(content.level) << "m";
1612498b56bSopenharmony_ci    }
1622498b56bSopenharmony_ci
1632498b56bSopenharmony_ci    const char *pHead = content.log;
1642498b56bSopenharmony_ci    const char *pScan = content.log;
1652498b56bSopenharmony_ci    // not print prefix if log is empty string or start with \n
1662498b56bSopenharmony_ci    if (*pScan != '\0' && *pScan != '\n') {
1672498b56bSopenharmony_ci        PrintLogPrefix(content, format, out);
1682498b56bSopenharmony_ci    }
1692498b56bSopenharmony_ci    // split the log content by '\n', and add log prefix(datetime, pid, tid....) to each new line
1702498b56bSopenharmony_ci    while (*pScan != '\0') {
1712498b56bSopenharmony_ci        if (*pScan == '\n') {
1722498b56bSopenharmony_ci            char tmp[MAX_LOG_LEN];
1732498b56bSopenharmony_ci            int len = static_cast<int>(pScan - pHead);
1742498b56bSopenharmony_ci            errno_t ret = memcpy_s(tmp, MAX_LOG_LEN - 1, pHead, len);
1752498b56bSopenharmony_ci            if (ret != EOK) {
1762498b56bSopenharmony_ci                break;
1772498b56bSopenharmony_ci            }
1782498b56bSopenharmony_ci            tmp[(MAX_LOG_LEN - 1) > len ? len : (MAX_LOG_LEN -1)] = '\0';
1792498b56bSopenharmony_ci            if (tmp[0] != '\0') {
1802498b56bSopenharmony_ci                out << tmp << endl;
1812498b56bSopenharmony_ci            }
1822498b56bSopenharmony_ci            pHead = pScan + 1;
1832498b56bSopenharmony_ci            if (pHead[0] != '\0' && pHead[0] != '\n') {
1842498b56bSopenharmony_ci                AdaptWrap(content, format, out);
1852498b56bSopenharmony_ci            }
1862498b56bSopenharmony_ci        }
1872498b56bSopenharmony_ci        pScan++;
1882498b56bSopenharmony_ci    }
1892498b56bSopenharmony_ci    if (pHead[0] != '\0') {
1902498b56bSopenharmony_ci        out << pHead;
1912498b56bSopenharmony_ci    }
1922498b56bSopenharmony_ci
1932498b56bSopenharmony_ci    // restore color
1942498b56bSopenharmony_ci    if (format.colorful) {
1952498b56bSopenharmony_ci        out << "\x1B[0m";
1962498b56bSopenharmony_ci    }
1972498b56bSopenharmony_ci    if (pHead[0] != '\0') {
1982498b56bSopenharmony_ci        out << endl;
1992498b56bSopenharmony_ci    }
2002498b56bSopenharmony_ci    return;
2012498b56bSopenharmony_ci}
2022498b56bSopenharmony_ci} // namespace HiviewDFX
2032498b56bSopenharmony_ci} // namespace OHOS