From 4611bb6a513f43fee84946994d5b5fe05e341c16 Mon Sep 17 00:00:00 2001 From: tian2020 Date: Wed, 14 Jun 2023 17:32:44 +0800 Subject: [PATCH 1/3] init and adapt to openeuler --- frameworks/libhilog/BUILD.gn | 101 +- frameworks/libhilog/base/hilog_base.cpp | 535 +++---- frameworks/libhilog/hilog.cpp | 121 +- frameworks/libhilog/hilog_printf.cpp | 3 +- frameworks/libhilog/include/hilog_cmd.h | 2 +- frameworks/libhilog/utils/include/log_print.h | 94 +- frameworks/libhilog/utils/include/log_utils.h | 220 +-- frameworks/libhilog/utils/log_print.cpp | 360 ++--- frameworks/libhilog/utils/log_utils.cpp | 1044 ++++++------- .../libhilog/vsnprintf/include/output_p.inl | 1294 +++++++++++++++++ hilog.gni | 6 +- interfaces/bundle.json | 5 +- interfaces/native/innerkits/BUILD.gn | 41 +- .../native/innerkits/include/hilog/log_c.h | 4 +- .../native/innerkits/include/hilog/log_cpp.h | 17 +- 15 files changed, 2590 insertions(+), 1257 deletions(-) create mode 100644 frameworks/libhilog/vsnprintf/include/output_p.inl diff --git a/frameworks/libhilog/BUILD.gn b/frameworks/libhilog/BUILD.gn index fe1a662..f8372a9 100644 --- a/frameworks/libhilog/BUILD.gn +++ b/frameworks/libhilog/BUILD.gn @@ -39,78 +39,33 @@ config("libhilog_config") { ] } -template("libhilog_source") { - forward_variables_from(invoker, "*") - ohos_source_set(target_name) { - if (platform != "windows" && platform != "mac" && platform != "linux") { - param_sources = [ "$param_root/properties.cpp" ] - ioctl_sources = [ "$ioctl_root/log_ioctl.cpp" ] - - socket_sources = [ - "$socket_root/dgram_socket_client.cpp", - "$socket_root/dgram_socket_server.cpp", - "$socket_root/hilog_input_socket_client.cpp", - "$socket_root/hilog_input_socket_server.cpp", - "$socket_root/seq_packet_socket_client.cpp", - "$socket_root/seq_packet_socket_server.cpp", - "$socket_root/socket.cpp", - "$socket_root/socket_client.cpp", - "$socket_root/socket_server.cpp", - ] - } - - utils_sources = [ - "$utils_root/log_print.cpp", - "$utils_root/log_utils.cpp", - ] - - vsnprintf_sources = [ "$vsnprintf_root/vsnprintf_s_p.cpp" ] - - sources = [ - "hilog.cpp", - "hilog_printf.cpp", - ] - if (platform != "windows" && platform != "mac" && platform != "linux") { - sources += param_sources - sources += ioctl_sources - sources += socket_sources - } - sources += utils_sources - sources += vsnprintf_sources - - defines = [] - if (platform == "windows") { - cflags_cc = [ "-std=c++17" ] - defines += [ "__WINDOWS__" ] - } else if (platform == "mac") { - defines += [ "__MAC__" ] - } else if (platform == "linux") { - cflags_cc = [ "-std=c++17" ] - defines += [ "__LINUX__" ] - } else { - defines = [ "__RECV_MSG_WITH_UCRED_" ] - if (use_musl) { - defines += [ "HILOG_USE_MUSL" ] - } - } - public_configs = [ ":libhilog_config" ] - configs = [ ":libhilog_config" ] - - deps = [ "//third_party/bounds_checking_function:libsec_shared" ] - - if (platform != "windows" && platform != "mac" && platform != "linux") { - external_deps = [ "init:libbegetutil" ] - } - - part_name = "hilog_native" - subsystem_name = "hiviewdfx" - } -} +ohos_source_set("libhilog_source") { + + utils_sources = [ + "$utils_root/log_print.cpp", + "$utils_root/log_utils.cpp", + ] + + vsnprintf_sources = [ "$vsnprintf_root/vsnprintf_s_p.cpp" ] + + sources = [ + "hilog.cpp", + "hilog_printf.cpp", + ] + sources += utils_sources + sources += vsnprintf_sources -foreach(item, platforms) { - libhilog_source("libhilog_source_" + item) { - platform = item - } + defines = [] + cflags_cc = [ "-std=c++17" ] + defines += [ "__LINUX__" ] + + public_configs = [ ":libhilog_config" ] + configs = [ ":libhilog_config" ] + + deps = [ "//third_party/bounds_checking_function:libsec_shared" ] + + part_name = "hilog_native" + subsystem_name = "hiviewdfx" } config("libhilog_base_config") { @@ -124,10 +79,10 @@ ohos_source_set("libhilog_base_source") { "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", ] - vsnprintf_sources = [ "$vsnprintf_root/vsnprintf_s_p.cpp" ] + # vsnprintf_sources = [ "$vsnprintf_root/vsnprintf_s_p.cpp" ] sources = [ "$libhilog_base_root/hilog_base.cpp" ] - sources += vsnprintf_sources + # sources += vsnprintf_sources defines = [ "__RECV_MSG_WITH_UCRED_", diff --git a/frameworks/libhilog/base/hilog_base.cpp b/frameworks/libhilog/base/hilog_base.cpp index 8e8e248..85337b8 100644 --- a/frameworks/libhilog/base/hilog_base.cpp +++ b/frameworks/libhilog/base/hilog_base.cpp @@ -16,279 +16,280 @@ #include "hilog_base/log_base.h" #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { -constexpr int SOCKET_TYPE = SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC; -constexpr int INVALID_SOCKET = -1; -constexpr size_t HILOG_VEC_MAX_SIZE = 4; -constexpr size_t HILOG_VEC_SIZE_OHCORE = 4; -constexpr size_t HILOG_VEC_SIZE_OH = 3; -constexpr int32_t MAX_DOMAIN_TAGSIZE = 64; - -struct SocketHandler { - std::atomic_int socketFd {INVALID_SOCKET}; - std::atomic_bool isConnected {false}; - ~SocketHandler() - { - int currentFd = socketFd.exchange(INVALID_SOCKET); - if (currentFd >= 0) { - close(currentFd); - } - } -}; - -typedef struct LogTime { - uint32_t tvSec; - uint32_t tvNsec; -} __attribute__((__packed__)) LogTime; - -typedef struct __attribute__((__packed__)) { - uint8_t id; - uint16_t tid; - uint16_t ohPid; - LogTime realtime; -} LogHeader; - -struct HiLogMsgInfo { - HilogMsg *header_; - const char *tag_; - uint16_t tagLen_; - const char *fmt_; - uint16_t fmtLen_; - HiLogMsgInfo(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen) - { - header_ = header; - tag_ = tag; - tagLen_ = tagLen; - fmt_ = fmt; - fmtLen_ = fmtLen; - } -}; - -typedef enum { - TYPE_OH = 0, - TYPE_OHCORE = 1, -} HiLogProtocolType; - -sockaddr_un g_sockAddr = {AF_UNIX, SOCKET_FILE_DIR INPUT_SOCKET_NAME}; -HiLogProtocolType g_protocolType = TYPE_OH; - -struct Initializer { - Initializer() - { - constexpr char configFile[] = "/system/etc/hilog_config"; - if (access(configFile, F_OK) != 0) { - return; - } - std::ifstream file; - file.open(configFile); - if (file.fail()) { - std::cerr << "open hilog_config config file failed" << std::endl; - return; - } - - std::string sock; - std::string protocol; - file >> sock >> protocol; - if (auto posColon = sock.find(":"); posColon != sock.npos) { - std::string sockPath = sock.substr(posColon + 1); - size_t pos = 0; - while (pos < sockPath.size() && pos < (sizeof(g_sockAddr.sun_path) - 1)) { - g_sockAddr.sun_path[pos] = sockPath[pos]; - pos++; - } - g_sockAddr.sun_path[pos] = '\0'; - } - if (auto posColon = protocol.find(":"); posColon != protocol.npos) { - g_protocolType = protocol.substr(posColon + 1) == "ohcore" ? TYPE_OHCORE : TYPE_OH; - } - file.close(); - } -}; -Initializer g_initializer; - -static int GenerateFD() -{ - int tmpFd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCKET_TYPE, 0)); - int res = tmpFd; - if (tmpFd == 0) { - res = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCKET_TYPE, 0)); - close(tmpFd); - } - return res; -} - -static int CheckSocket(SocketHandler& socketHandler) -{ - int currentFd = socketHandler.socketFd.load(); - if (currentFd >= 0) { - return currentFd; - } - - int fd = GenerateFD(); - if (fd < 0) { - std::cerr << "Can't get hilog socket! Errno: " << errno << std::endl; - return fd; - } - - currentFd = INVALID_SOCKET; - if (!socketHandler.socketFd.compare_exchange_strong(currentFd, fd)) { - close(fd); - return currentFd; - } - return fd; -} - -static int CheckConnection(SocketHandler& socketHandler) -{ - bool isConnected = socketHandler.isConnected.load(); - if (isConnected) { - return 0; - } - - isConnected = socketHandler.isConnected.load(); - if (isConnected) { - return 0; - } - - auto result = TEMP_FAILURE_RETRY(connect(socketHandler.socketFd.load(), - reinterpret_cast(&g_sockAddr), sizeof(g_sockAddr))); - if (result < 0) { - std::cerr << "Can't connect to hilog server. Errno: " << errno << std::endl; - return result; - } - socketHandler.isConnected.store(true); - return 0; -} - -static size_t BuildHilogMessageForOhCore(struct HiLogMsgInfo* logMsgInfo, LogHeader& logHeader, uint16_t& logLevel, - char tagBuf[], struct iovec *vec) -{ - struct timespec ts = {0}; - (void)clock_gettime(CLOCK_REALTIME, &ts); - logHeader.realtime.tvSec = static_cast(ts.tv_sec); - logHeader.realtime.tvNsec = static_cast(ts.tv_nsec); - logHeader.tid = static_cast(gettid()); - logHeader.ohPid = static_cast(getpid()); - logLevel = logMsgInfo->header_->level; - constexpr uint32_t domainFilter = 0x000FFFFF; - if (vsnprintfp_s(tagBuf, MAX_DOMAIN_TAGSIZE, MAX_DOMAIN_TAGSIZE - 1, false, "%05X/%s", - (logMsgInfo->header_->domain & domainFilter), logMsgInfo->tag_) < 0) { - return 0; - } - - vec[0].iov_base = reinterpret_cast(&logHeader); // 0 : index of hos log header - vec[0].iov_len = sizeof(logHeader); // 0 : index of hos log header - vec[1].iov_base = reinterpret_cast(&logLevel); // 1 : index of log level - vec[1].iov_len = 1; // 1 : index of log level - vec[2].iov_base = reinterpret_cast(const_cast(tagBuf)); // 2 : index of log tag - vec[2].iov_len = strlen(tagBuf) + 1; // 2 : index of log tag - vec[3].iov_base = reinterpret_cast(const_cast(logMsgInfo->fmt_)); // 3 : index of log format - vec[3].iov_len = logMsgInfo->fmtLen_; // 3 : index of log format - return HILOG_VEC_SIZE_OHCORE; -} - -static size_t BuildHilogMessageForOh(struct HiLogMsgInfo* logMsgInfo, struct iovec *vec) -{ - struct timespec ts = {0}; - (void)clock_gettime(CLOCK_REALTIME, &ts); - struct timespec tsMono = {0}; - (void)clock_gettime(CLOCK_MONOTONIC, &tsMono); - logMsgInfo->header_->tv_sec = static_cast(ts.tv_sec); - logMsgInfo->header_->tv_nsec = static_cast(ts.tv_nsec); - logMsgInfo->header_->mono_sec = static_cast(tsMono.tv_sec); - logMsgInfo->header_->len = sizeof(HilogMsg) + logMsgInfo->tagLen_ + logMsgInfo->fmtLen_; - logMsgInfo->header_->tag_len = logMsgInfo->tagLen_; - - vec[0].iov_base = logMsgInfo->header_; // 0 : index of hos log header - vec[0].iov_len = sizeof(HilogMsg); // 0 : index of hos log header - vec[1].iov_base = reinterpret_cast(const_cast(logMsgInfo->tag_)); // 1 : index of log tag - vec[1].iov_len = logMsgInfo->tagLen_; // 1 : index of log tag - vec[2].iov_base = reinterpret_cast(const_cast(logMsgInfo->fmt_)); // 2 : index of log content - vec[2].iov_len = logMsgInfo->fmtLen_; // 2 : index of log content - return HILOG_VEC_SIZE_OH; -} - -static int SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen) -{ - SocketHandler socketHandler; - int ret = CheckSocket(socketHandler); - if (ret < 0) { - return ret; - } - ret = CheckConnection(socketHandler); - if (ret < 0) { - return ret; - } - - struct iovec vec[HILOG_VEC_MAX_SIZE]; - struct HiLogMsgInfo msgInfo(header, tag, tagLen, fmt, fmtLen); - LogHeader logHeader; - uint16_t logLevel = 0; - char tagBuf[MAX_DOMAIN_TAGSIZE] = {0}; - auto vecSize = (g_protocolType == TYPE_OHCORE) ? - BuildHilogMessageForOhCore(&msgInfo, logHeader, logLevel, tagBuf, vec) : - BuildHilogMessageForOh(&msgInfo, vec); - if (vecSize == 0) { - std::cerr << "BuildHilogMessage failed ret = " << vecSize << std::endl; - return RET_FAIL; - } - return TEMP_FAILURE_RETRY(::writev(socketHandler.socketFd.load(), vec, vecSize)); -} - -static int HiLogBasePrintArgs(const LogType type, const LogLevel level, const unsigned int domain, const char *tag, - const char *fmt, va_list ap) -{ - if (!HiLogBaseIsLoggable(domain, tag, level)) { - return -1; - } - - char buf[MAX_LOG_LEN] = {0}; - - vsnprintfp_s(buf, MAX_LOG_LEN, MAX_LOG_LEN - 1, true, fmt, ap); - - auto tagLen = strnlen(tag, MAX_TAG_LEN - 1); - auto logLen = strnlen(buf, MAX_LOG_LEN - 1); - HilogMsg header = {0}; - header.type = type; - header.level = level; -#ifndef __RECV_MSG_WITH_UCRED_ - header.pid = getpid(); -#endif - header.tid = static_cast(gettid()); - header.domain = domain; - - return SendMessage(&header, tag, tagLen + 1, buf, logLen + 1); -} - -} // namespace +// #include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// namespace { +// constexpr int SOCKET_TYPE = SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC; +// constexpr int INVALID_SOCKET = -1; +// constexpr size_t HILOG_VEC_MAX_SIZE = 4; +// constexpr size_t HILOG_VEC_SIZE_OHCORE = 4; +// constexpr size_t HILOG_VEC_SIZE_OH = 3; +// constexpr int32_t MAX_DOMAIN_TAGSIZE = 64; + +// struct SocketHandler { +// std::atomic_int socketFd {INVALID_SOCKET}; +// std::atomic_bool isConnected {false}; +// ~SocketHandler() +// { +// int currentFd = socketFd.exchange(INVALID_SOCKET); +// if (currentFd >= 0) { +// close(currentFd); +// } +// } +// }; + +// typedef struct LogTime { +// uint32_t tvSec; +// uint32_t tvNsec; +// } __attribute__((__packed__)) LogTime; + +// typedef struct __attribute__((__packed__)) { +// uint8_t id; +// uint16_t tid; +// uint16_t ohPid; +// LogTime realtime; +// } LogHeader; + +// struct HiLogMsgInfo { +// HilogMsg *header_; +// const char *tag_; +// uint16_t tagLen_; +// const char *fmt_; +// uint16_t fmtLen_; +// HiLogMsgInfo(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen) +// { +// header_ = header; +// tag_ = tag; +// tagLen_ = tagLen; +// fmt_ = fmt; +// fmtLen_ = fmtLen; +// } +// }; + +// typedef enum { +// TYPE_OH = 0, +// TYPE_OHCORE = 1, +// } HiLogProtocolType; + +// sockaddr_un g_sockAddr = {AF_UNIX, SOCKET_FILE_DIR INPUT_SOCKET_NAME}; +// HiLogProtocolType g_protocolType = TYPE_OH; + +// struct Initializer { +// Initializer() +// { +// constexpr char configFile[] = "/system/etc/hilog_config"; +// if (access(configFile, F_OK) != 0) { +// return; +// } +// std::ifstream file; +// file.open(configFile); +// if (file.fail()) { +// std::cerr << "open hilog_config config file failed" << std::endl; +// return; +// } + +// std::string sock; +// std::string protocol; +// file >> sock >> protocol; +// if (auto posColon = sock.find(":"); posColon != sock.npos) { +// std::string sockPath = sock.substr(posColon + 1); +// size_t pos = 0; +// while (pos < sockPath.size() && pos < (sizeof(g_sockAddr.sun_path) - 1)) { +// g_sockAddr.sun_path[pos] = sockPath[pos]; +// pos++; +// } +// g_sockAddr.sun_path[pos] = '\0'; +// } +// if (auto posColon = protocol.find(":"); posColon != protocol.npos) { +// g_protocolType = protocol.substr(posColon + 1) == "ohcore" ? TYPE_OHCORE : TYPE_OH; +// } +// file.close(); +// } +// }; +// Initializer g_initializer; + +// static int GenerateFD() +// { +// int tmpFd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCKET_TYPE, 0)); +// int res = tmpFd; +// if (tmpFd == 0) { +// res = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCKET_TYPE, 0)); +// close(tmpFd); +// } +// return res; +// } + +// static int CheckSocket(SocketHandler& socketHandler) +// { +// int currentFd = socketHandler.socketFd.load(); +// if (currentFd >= 0) { +// return currentFd; +// } + +// int fd = GenerateFD(); +// if (fd < 0) { +// std::cerr << "Can't get hilog socket! Errno: " << errno << std::endl; +// return fd; +// } + +// currentFd = INVALID_SOCKET; +// if (!socketHandler.socketFd.compare_exchange_strong(currentFd, fd)) { +// close(fd); +// return currentFd; +// } +// return fd; +// } + +// static int CheckConnection(SocketHandler& socketHandler) +// { +// bool isConnected = socketHandler.isConnected.load(); +// if (isConnected) { +// return 0; +// } + +// isConnected = socketHandler.isConnected.load(); +// if (isConnected) { +// return 0; +// } + +// auto result = TEMP_FAILURE_RETRY(connect(socketHandler.socketFd.load(), +// reinterpret_cast(&g_sockAddr), sizeof(g_sockAddr))); +// if (result < 0) { +// std::cerr << "Can't connect to hilog server. Errno: " << errno << std::endl; +// return result; +// } +// socketHandler.isConnected.store(true); +// return 0; +// } + +// static size_t BuildHilogMessageForOhCore(struct HiLogMsgInfo* logMsgInfo, LogHeader& logHeader, uint16_t& logLevel, +// char tagBuf[], struct iovec *vec) +// { +// struct timespec ts = {0}; +// (void)clock_gettime(CLOCK_REALTIME, &ts); +// logHeader.realtime.tvSec = static_cast(ts.tv_sec); +// logHeader.realtime.tvNsec = static_cast(ts.tv_nsec); +// logHeader.tid = static_cast(gettid()); +// logHeader.ohPid = static_cast(getpid()); +// logLevel = logMsgInfo->header_->level; +// constexpr uint32_t domainFilter = 0x000FFFFF; +// if (vsnprintfp_s(tagBuf, MAX_DOMAIN_TAGSIZE, MAX_DOMAIN_TAGSIZE - 1, false, "%05X/%s", +// (logMsgInfo->header_->domain & domainFilter), logMsgInfo->tag_) < 0) { +// return 0; +// } + +// vec[0].iov_base = reinterpret_cast(&logHeader); // 0 : index of hos log header +// vec[0].iov_len = sizeof(logHeader); // 0 : index of hos log header +// vec[1].iov_base = reinterpret_cast(&logLevel); // 1 : index of log level +// vec[1].iov_len = 1; // 1 : index of log level +// vec[2].iov_base = reinterpret_cast(const_cast(tagBuf)); // 2 : index of log tag +// vec[2].iov_len = strlen(tagBuf) + 1; // 2 : index of log tag +// vec[3].iov_base = reinterpret_cast(const_cast(logMsgInfo->fmt_)); // 3 : index of log format +// vec[3].iov_len = logMsgInfo->fmtLen_; // 3 : index of log format +// return HILOG_VEC_SIZE_OHCORE; +// } + +// static size_t BuildHilogMessageForOh(struct HiLogMsgInfo* logMsgInfo, struct iovec *vec) +// { +// struct timespec ts = {0}; +// (void)clock_gettime(CLOCK_REALTIME, &ts); +// struct timespec tsMono = {0}; +// (void)clock_gettime(CLOCK_MONOTONIC, &tsMono); +// logMsgInfo->header_->tv_sec = static_cast(ts.tv_sec); +// logMsgInfo->header_->tv_nsec = static_cast(ts.tv_nsec); +// logMsgInfo->header_->mono_sec = static_cast(tsMono.tv_sec); +// logMsgInfo->header_->len = sizeof(HilogMsg) + logMsgInfo->tagLen_ + logMsgInfo->fmtLen_; +// logMsgInfo->header_->tag_len = logMsgInfo->tagLen_; + +// vec[0].iov_base = logMsgInfo->header_; // 0 : index of hos log header +// vec[0].iov_len = sizeof(HilogMsg); // 0 : index of hos log header +// vec[1].iov_base = reinterpret_cast(const_cast(logMsgInfo->tag_)); // 1 : index of log tag +// vec[1].iov_len = logMsgInfo->tagLen_; // 1 : index of log tag +// vec[2].iov_base = reinterpret_cast(const_cast(logMsgInfo->fmt_)); // 2 : index of log content +// vec[2].iov_len = logMsgInfo->fmtLen_; // 2 : index of log content +// return HILOG_VEC_SIZE_OH; +// } + +// static int SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen) +// { +// SocketHandler socketHandler; +// int ret = CheckSocket(socketHandler); +// if (ret < 0) { +// return ret; +// } +// ret = CheckConnection(socketHandler); +// if (ret < 0) { +// return ret; +// } + +// struct iovec vec[HILOG_VEC_MAX_SIZE]; +// struct HiLogMsgInfo msgInfo(header, tag, tagLen, fmt, fmtLen); +// LogHeader logHeader; +// uint16_t logLevel = 0; +// char tagBuf[MAX_DOMAIN_TAGSIZE] = {0}; +// auto vecSize = (g_protocolType == TYPE_OHCORE) ? +// BuildHilogMessageForOhCore(&msgInfo, logHeader, logLevel, tagBuf, vec) : +// BuildHilogMessageForOh(&msgInfo, vec); +// if (vecSize == 0) { +// std::cerr << "BuildHilogMessage failed ret = " << vecSize << std::endl; +// return RET_FAIL; +// } +// return TEMP_FAILURE_RETRY(::writev(socketHandler.socketFd.load(), vec, vecSize)); +// } + +// static int HiLogBasePrintArgs(const LogType type, const LogLevel level, const unsigned int domain, const char *tag, +// const char *fmt, va_list ap) +// { +// if (!HiLogBaseIsLoggable(domain, tag, level)) { +// return -1; +// } + +// char buf[MAX_LOG_LEN] = {0}; + +// vsnprintfp_s(buf, MAX_LOG_LEN, MAX_LOG_LEN - 1, true, fmt, ap); + +// auto tagLen = strnlen(tag, MAX_TAG_LEN - 1); +// auto logLen = strnlen(buf, MAX_LOG_LEN - 1); +// HilogMsg header = {0}; +// header.type = type; +// header.level = level; +// #ifndef __RECV_MSG_WITH_UCRED_ +// header.pid = getpid(); +// #endif +// header.tid = static_cast(gettid()); +// header.domain = domain; + +// return SendMessage(&header, tag, tagLen + 1, buf, logLen + 1); +// } + +// } // namespace int HiLogBasePrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) { - int ret; - va_list ap; - va_start(ap, fmt); - ret = HiLogBasePrintArgs(type, level, domain, tag, fmt, ap); - va_end(ap); - return ret; + // int ret; + // va_list ap; + // va_start(ap, fmt); + // ret = HiLogBasePrintArgs(type, level, domain, tag, fmt, ap); + // va_end(ap); + // return ret; + return 0; } bool HiLogBaseIsLoggable(unsigned int domain, const char *tag, LogLevel level) { - if ((level <= LOG_LEVEL_MIN) || (level >= LOG_LEVEL_MAX) || tag == nullptr) { - return false; - } + // if ((level <= LOG_LEVEL_MIN) || (level >= LOG_LEVEL_MAX) || tag == nullptr) { + // return false; + // } return true; } diff --git a/frameworks/libhilog/hilog.cpp b/frameworks/libhilog/hilog.cpp index 80980cb..e58c6d6 100644 --- a/frameworks/libhilog/hilog.cpp +++ b/frameworks/libhilog/hilog.cpp @@ -1,23 +1,26 @@ -/* - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - #include "hilog/log.h" -#include "hilog_inner.h" +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log_utils.h" +#include "hilog_common.h" +#include "log_timestamp.h" +#include "vsnprintf_s_p.h" +#include "log_print.h" + +using namespace std; +using namespace OHOS::HiviewDFX; namespace OHOS { namespace HiviewDFX { @@ -29,6 +32,82 @@ namespace HiviewDFX { va_end(args); \ } while (0) +int HiPrintLog(HilogMsg& header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen) +{ + LogContent content = { + .level = header.level, + .type = header.type, + .pid = header.pid, + .tid = header.tid, + .domain = header.domain, + .tv_sec = header.tv_sec, + .tv_nsec = header.tv_nsec, + .mono_sec = header.mono_sec, + .tag = tag, + .log = fmt, + }; + LogFormat format = { + .colorful = false, + .timeFormat = FormatTime::TIME, + .timeAccuFormat = FormatTimeAccu::MSEC, + .year = false, + .zone = false, + }; + LogPrintWithFormat(content, format); + return RET_SUCCESS; +} + +int HiLogPrintArgs(const LogType type, const LogLevel level, const unsigned int domain, const char *tag, + const char *fmt, va_list ap) +{ + if ((tag == nullptr)) { + return -1; + } + + HilogMsg header = {0}; + struct timespec ts = {0}; + (void)clock_gettime(CLOCK_REALTIME, &ts); + struct timespec ts_mono = {0}; + (void)clock_gettime(CLOCK_MONOTONIC, &ts_mono); + header.tv_sec = static_cast(ts.tv_sec); + header.tv_nsec = static_cast(ts.tv_nsec); + header.mono_sec = static_cast(ts_mono.tv_sec); + + char buf[MAX_LOG_LEN] = {0}; + char *logBuf = buf; + int traceBufLen = 0; + int ret; + bool priv = true; + +#ifdef __clang__ +/* code specific to clang compiler */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#elif __GNUC__ +/* code for GNU C compiler */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif + ret = vsnprintfp_s(logBuf, MAX_LOG_LEN - traceBufLen, MAX_LOG_LEN - traceBufLen - 1, priv, fmt, ap); +#ifdef __clang__ +#pragma clang diagnostic pop +#elif __GNUC__ +#pragma GCC diagnostic pop +#endif + + /* fill header info */ + auto tagLen = strnlen(tag, MAX_TAG_LEN - 1); + auto logLen = strnlen(buf, MAX_LOG_LEN - 1); + header.type = type; + header.level = level; + header.pid = getpid(); + header.tid = static_cast(syscall(SYS_gettid)); + header.domain = domain; + + return HiPrintLog(header, tag, tagLen + 1, buf, logLen + 1); + +} + int HiLog::Debug(const HiLogLabel &label, const char *fmt, ...) { int ret; @@ -65,3 +144,13 @@ int HiLog::Fatal(const HiLogLabel &label, const char *fmt, ...) } } // namespace HiviewDFX } // namespace OHOS + +int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = HiLogPrintArgs(type, level, domain, tag, fmt, ap); + va_end(ap); + return ret; +} diff --git a/frameworks/libhilog/hilog_printf.cpp b/frameworks/libhilog/hilog_printf.cpp index 9db1742..1316128 100644 --- a/frameworks/libhilog/hilog_printf.cpp +++ b/frameworks/libhilog/hilog_printf.cpp @@ -55,8 +55,7 @@ static atomic_int g_hiLogGetIdCallCount = 0; // protected by static lock guard static char g_hiLogLastFatalMessage[MAX_LOG_LEN] = { 0 }; // MAX_lOG_LEN : 1024 -HILOG_PUBLIC_API -extern "C" const char* GetLastFatalMessage() +extern "C" HILOG_PUBLIC_API const char* GetLastFatalMessage() { return g_hiLogLastFatalMessage; } diff --git a/frameworks/libhilog/include/hilog_cmd.h b/frameworks/libhilog/include/hilog_cmd.h index 1043e1b..677da27 100644 --- a/frameworks/libhilog/include/hilog_cmd.h +++ b/frameworks/libhilog/include/hilog_cmd.h @@ -258,4 +258,4 @@ struct KmsgEnableRqst { struct KmsgEnableRsp { char placeholder; } __attribute__((__packed__)); -#endif /* HILOG_CMD_H */ \ No newline at end of file +#endif /* HILOG_CMD_H */ diff --git a/frameworks/libhilog/utils/include/log_print.h b/frameworks/libhilog/utils/include/log_print.h index a84cdc5..e90626a 100644 --- a/frameworks/libhilog/utils/include/log_print.h +++ b/frameworks/libhilog/utils/include/log_print.h @@ -1,47 +1,47 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef LOG_PRINT_H -#define LOG_PRINT_H -#include - -#include "hilog_cmd.h" - -namespace OHOS { -namespace HiviewDFX { -struct LogContent { - uint8_t level; - uint8_t type; - uint32_t pid; - uint32_t tid; - uint32_t domain; - uint32_t tv_sec; - uint32_t tv_nsec; - uint32_t mono_sec; - const char *tag; - const char *log; -}; - -struct LogFormat { - bool colorful; - FormatTime timeFormat; - FormatTimeAccu timeAccuFormat; - bool year; - bool zone; -}; - -void LogPrintWithFormat(const LogContent& content, const LogFormat& format, std::ostream& out = std::cout); -} // namespace HiviewDFX -} // namespace OHOS -#endif /* LOG_PRINT_H */ \ No newline at end of file +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LOG_PRINT_H +#define LOG_PRINT_H +#include + +#include "hilog_cmd.h" + +namespace OHOS { +namespace HiviewDFX { +struct LogContent { + uint8_t level; + uint8_t type; + uint32_t pid; + uint32_t tid; + uint32_t domain; + uint32_t tv_sec; + uint32_t tv_nsec; + uint32_t mono_sec; + const char *tag; + const char *log; +}; + +struct LogFormat { + bool colorful; + FormatTime timeFormat; + FormatTimeAccu timeAccuFormat; + bool year; + bool zone; +}; + +void LogPrintWithFormat(const LogContent& content, const LogFormat& format, std::ostream& out = std::cout); +} // namespace HiviewDFX +} // namespace OHOS +#endif /* LOG_PRINT_H */ diff --git a/frameworks/libhilog/utils/include/log_utils.h b/frameworks/libhilog/utils/include/log_utils.h index 464fe84..6a79155 100644 --- a/frameworks/libhilog/utils/include/log_utils.h +++ b/frameworks/libhilog/utils/include/log_utils.h @@ -1,110 +1,110 @@ -/* - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef LOG_UTILS_H -#define LOG_UTILS_H - -#include -#include -#include - -namespace OHOS { -namespace HiviewDFX { -template -class KVMap { -using ValueCmp = std::function; -public: - KVMap(std::unordered_map map, K def_k, V def_v, - ValueCmp cmp = [](const V& v1, const V& v2) { return v1 == v2; }) - : str_map(map), def_key(def_k), def_value(def_v), compare(cmp) - { - } - - const V& GetValue(K key) const - { - auto it = str_map.find(key); - return it == str_map.end() ? def_value : it->second; - } - - const K GetKey(const V& value) const - { - for (auto& it : str_map) { - if (compare(value, it.second)) { - return it.first; - } - } - return def_key; - } - - std::vector GetAllKeys() const - { - std::vector keys; - for (auto& it : str_map) { - keys.push_back(it.first); - } - return keys; - } - - bool IsValidKey(K key) const - { - return (str_map.find(key) != str_map.end()); - } - -private: - const std::unordered_map str_map; - const K def_key; - const V def_value; - const ValueCmp compare; -}; -using StringMap = KVMap; -std::string ErrorCode2Str(int16_t errorCode); -std::string LogType2Str(uint16_t logType); -uint16_t Str2LogType(const std::string& str); -std::string ComboLogType2Str(uint16_t shiftType); -uint16_t Str2ComboLogType(const std::string& str); -std::vector GetAllLogTypes(); -std::string LogLevel2Str(uint16_t logLevel); -uint16_t Str2LogLevel(const std::string& str); -std::string LogLevel2ShortStr(uint16_t logLevel); -uint16_t ShortStr2LogLevel(const std::string& str); -uint16_t PrettyStr2LogLevel(const std::string& str); -std::string ComboLogLevel2Str(uint16_t shiftLevel); -uint16_t Str2ComboLogLevel(const std::string& str); -std::string ShowFormat2Str(uint16_t showFormat); -uint16_t Str2ShowFormat(const std::string& str); -std::string Size2Str(uint64_t size); -uint64_t Str2Size(const std::string& str); - -constexpr char DEFAULT_SPLIT_DELIMIT[] = ","; -void Split(const std::string& src, std::vector& dest, - const std::string& separator = DEFAULT_SPLIT_DELIMIT); -uint32_t GetBitsCount(uint64_t n); -uint16_t GetBitPos(uint64_t n); - -std::string Uint2DecStr(uint32_t i); -uint32_t DecStr2Uint(const std::string& str); -std::string Uint2HexStr(uint32_t i); -uint32_t HexStr2Uint(const std::string& str); - -#if !defined(__WINDOWS__) and !defined(__LINUX__) -std::string GetProgName(); -#endif -std::string GetNameByPid(uint32_t pid); -uint32_t GetPPidByPid(uint32_t pid); -uint64_t GenerateHash(const char *p, size_t size); -void PrintErrorno(int err); -int WaitingToDo(int max, const std::string& path, std::function func); -} // namespace HiviewDFX -} // namespace OHOS -#endif // LOG_UTILS_H \ No newline at end of file +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LOG_UTILS_H +#define LOG_UTILS_H + +#include +#include +#include + +namespace OHOS { +namespace HiviewDFX { +template +class KVMap { +using ValueCmp = std::function; +public: + KVMap(std::unordered_map map, K def_k, V def_v, + ValueCmp cmp = [](const V& v1, const V& v2) { return v1 == v2; }) + : str_map(map), def_key(def_k), def_value(def_v), compare(cmp) + { + } + + const V& GetValue(K key) const + { + auto it = str_map.find(key); + return it == str_map.end() ? def_value : it->second; + } + + const K GetKey(const V& value) const + { + for (auto& it : str_map) { + if (compare(value, it.second)) { + return it.first; + } + } + return def_key; + } + + std::vector GetAllKeys() const + { + std::vector keys; + for (auto& it : str_map) { + keys.push_back(it.first); + } + return keys; + } + + bool IsValidKey(K key) const + { + return (str_map.find(key) != str_map.end()); + } + +private: + const std::unordered_map str_map; + const K def_key; + const V def_value; + const ValueCmp compare; +}; +using StringMap = KVMap; +std::string ErrorCode2Str(int16_t errorCode); +std::string LogType2Str(uint16_t logType); +uint16_t Str2LogType(const std::string& str); +std::string ComboLogType2Str(uint16_t shiftType); +uint16_t Str2ComboLogType(const std::string& str); +std::vector GetAllLogTypes(); +std::string LogLevel2Str(uint16_t logLevel); +uint16_t Str2LogLevel(const std::string& str); +std::string LogLevel2ShortStr(uint16_t logLevel); +uint16_t ShortStr2LogLevel(const std::string& str); +uint16_t PrettyStr2LogLevel(const std::string& str); +std::string ComboLogLevel2Str(uint16_t shiftLevel); +uint16_t Str2ComboLogLevel(const std::string& str); +std::string ShowFormat2Str(uint16_t showFormat); +uint16_t Str2ShowFormat(const std::string& str); +std::string Size2Str(uint64_t size); +uint64_t Str2Size(const std::string& str); + +constexpr char DEFAULT_SPLIT_DELIMIT[] = ","; +void Split(const std::string& src, std::vector& dest, + const std::string& separator = DEFAULT_SPLIT_DELIMIT); +uint32_t GetBitsCount(uint64_t n); +uint16_t GetBitPos(uint64_t n); + +std::string Uint2DecStr(uint32_t i); +uint32_t DecStr2Uint(const std::string& str); +std::string Uint2HexStr(uint32_t i); +uint32_t HexStr2Uint(const std::string& str); + +#if !defined(__WINDOWS__) and !defined(__LINUX__) +std::string GetProgName(); +#endif +std::string GetNameByPid(uint32_t pid); +uint32_t GetPPidByPid(uint32_t pid); +uint64_t GenerateHash(const char *p, size_t size); +void PrintErrorno(int err); +int WaitingToDo(int max, const std::string& path, std::function func); +} // namespace HiviewDFX +} // namespace OHOS +#endif // LOG_UTILS_H diff --git a/frameworks/libhilog/utils/log_print.cpp b/frameworks/libhilog/utils/log_print.cpp index 6d47a9a..c7ebf21 100644 --- a/frameworks/libhilog/utils/log_print.cpp +++ b/frameworks/libhilog/utils/log_print.cpp @@ -1,180 +1,180 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -#include "hilog_common.h" -#include "log_utils.h" -#include "log_print.h" - -namespace OHOS { -namespace HiviewDFX { -using namespace std; - -static constexpr int COLOR_BLUE = 75; -static constexpr int COLOR_DEFAULT = 231; -static constexpr int COLOR_GREEN = 40; -static constexpr int COLOR_ORANGE = 166; -static constexpr int COLOR_RED = 196; -static constexpr int COLOR_YELLOW = 226; -static constexpr int TM_YEAR_BASE = 1900; -static constexpr int DT_WIDTH = 2; -static constexpr long long NS2US = 1000LL; -static constexpr long long NS2MS = 1000000LL; -static constexpr int MONO_WIDTH = 8; -static constexpr int EPOCH_WIDTH = 10; -static constexpr int MSEC_WIDTH = 3; -static constexpr int USEC_WIDTH = 6; -static constexpr int NSEC_WIDTH = 9; -static constexpr int PID_WIDTH = 5; -static constexpr int DOMAIN_WIDTH = 5; -static constexpr int DOMAIN_SHORT_MASK = 0xFFFFF; - -static inline int GetColor(uint16_t level) -{ - switch (LogLevel(level)) { - case LOG_DEBUG: return COLOR_BLUE; - case LOG_INFO: return COLOR_GREEN; - case LOG_WARN: return COLOR_ORANGE; - case LOG_ERROR: return COLOR_RED; - case LOG_FATAL: return COLOR_YELLOW; - default: return COLOR_DEFAULT; - } -} - -static inline const char* GetLogTypePrefix(uint16_t type) -{ - switch (LogType(type)) { - case LOG_APP: return "A"; - case LOG_INIT: return "I"; - case LOG_CORE: return "C"; - case LOG_KMSG: return "K"; - default: return " "; - } -} - -static inline uint32_t ShortDomain(uint32_t d) -{ - return (d) & DOMAIN_SHORT_MASK; -} - -static void PrintLogPrefix(const LogContent& content, const LogFormat& format, std::ostream& out) -{ - // 1. print day & time - if (format.timeFormat == FormatTime::TIME) { - struct tm tl; - time_t time = content.tv_sec; -#if (defined( __WINDOWS__ )) - if (localtime_s(&tl, &time) != 0) { - return; - } -#else - if (localtime_r(&time, &tl) == nullptr) { - return; - } - if (format.zone) { - out << tl.tm_zone << " "; - } -#endif - if (format.year) { - out << (tl.tm_year + TM_YEAR_BASE) << "-"; - } - out << setfill('0'); - out << setw(DT_WIDTH) << (tl.tm_mon + 1) << "-" << setw(DT_WIDTH) << tl.tm_mday << " "; - out << setw(DT_WIDTH) << tl.tm_hour << ":" << setw(DT_WIDTH) << tl.tm_min << ":"; - out << setw(DT_WIDTH) << tl.tm_sec; - } else if (format.timeFormat == FormatTime::MONOTONIC) { - out << setfill(' '); - out << setw(MONO_WIDTH) << content.mono_sec; - } else if (format.timeFormat == FormatTime::EPOCH) { - out << setfill(' '); - out << setw(EPOCH_WIDTH) << content.tv_sec; - } else { - out << "Invalid time format" << endl; - return; - } - // 1.1 print msec/usec/nsec - out << "."; - out << setfill('0'); - if (format.timeAccuFormat == FormatTimeAccu::MSEC) { - out << setw(MSEC_WIDTH) << (content.tv_nsec / NS2MS); - } else if (format.timeAccuFormat == FormatTimeAccu::USEC) { - out << setw(USEC_WIDTH) << (content.tv_nsec / NS2US); - } else if (format.timeAccuFormat == FormatTimeAccu::NSEC) { - out << setw(NSEC_WIDTH) << content.tv_nsec; - } else { - out << "Invalid time accuracy format" << endl; - return; - } - out << setfill(' '); - // 2. print pid/tid - out << " " << setw(PID_WIDTH) << content.pid << " " << setw(PID_WIDTH) << content.tid; - // 3. print level - out << " " << LogLevel2ShortStr(content.level) << " "; - // 4. print log type - out << GetLogTypePrefix(content.type); - // 5. print domain - out << setfill('0'); - out << hex << setw(DOMAIN_WIDTH) << ShortDomain(content.domain) << dec; - // 5. print tag & log - out << "/" << content.tag << ": "; -} - -void LogPrintWithFormat(const LogContent& content, const LogFormat& format, std::ostream& out) -{ - // set colorful log - if (format.colorful) { - out << "\x1B[38;5;" << GetColor(content.level) << "m"; - } - - const char *pHead = content.log; - const char *pScan = content.log; - // split the log content by '\n', and add log prefix(datetime, pid, tid....) to each new line - while (*pScan != '\0') { - if (*pScan == '\n') { - char tmp[MAX_LOG_LEN]; - int len = static_cast(pScan - pHead); - errno_t ret = memcpy_s(tmp, MAX_LOG_LEN - 1, pHead, len); - if (ret != EOK) { - break; - } - tmp[(MAX_LOG_LEN - 1) > len ? len : (MAX_LOG_LEN -1)] = '\0'; - if (tmp[0] != '\0') { - PrintLogPrefix(content, format, out); - out << tmp << endl; - } - pHead = pScan + 1; - } - pScan++; - } - if (pHead[0] != '\0') { - PrintLogPrefix(content, format, out); - out << pHead; - } - - // restore color - if (format.colorful) { - out << "\x1B[0m"; - } - if (pHead[0] != '\0') { - out << endl; - } - return; -} -} // namespace HiviewDFX -} // namespace OHOS \ No newline at end of file +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#include "hilog_common.h" +#include "log_utils.h" +#include "log_print.h" + +namespace OHOS { +namespace HiviewDFX { +using namespace std; + +static constexpr int COLOR_BLUE = 75; +static constexpr int COLOR_DEFAULT = 231; +static constexpr int COLOR_GREEN = 40; +static constexpr int COLOR_ORANGE = 166; +static constexpr int COLOR_RED = 196; +static constexpr int COLOR_YELLOW = 226; +static constexpr int TM_YEAR_BASE = 1900; +static constexpr int DT_WIDTH = 2; +static constexpr long long NS2US = 1000LL; +static constexpr long long NS2MS = 1000000LL; +static constexpr int MONO_WIDTH = 8; +static constexpr int EPOCH_WIDTH = 10; +static constexpr int MSEC_WIDTH = 3; +static constexpr int USEC_WIDTH = 6; +static constexpr int NSEC_WIDTH = 9; +static constexpr int PID_WIDTH = 5; +static constexpr int DOMAIN_WIDTH = 5; +static constexpr int DOMAIN_SHORT_MASK = 0xFFFFF; + +static inline int GetColor(uint16_t level) +{ + switch (LogLevel(level)) { + case LOG_DEBUG: return COLOR_BLUE; + case LOG_INFO: return COLOR_GREEN; + case LOG_WARN: return COLOR_ORANGE; + case LOG_ERROR: return COLOR_RED; + case LOG_FATAL: return COLOR_YELLOW; + default: return COLOR_DEFAULT; + } +} + +static inline const char* GetLogTypePrefix(uint16_t type) +{ + switch (LogType(type)) { + case LOG_APP: return "A"; + case LOG_INIT: return "I"; + case LOG_CORE: return "C"; + case LOG_KMSG: return "K"; + default: return " "; + } +} + +static inline uint32_t ShortDomain(uint32_t d) +{ + return (d) & DOMAIN_SHORT_MASK; +} + +static void PrintLogPrefix(const LogContent& content, const LogFormat& format, std::ostream& out) +{ + // 1. print day & time + if (format.timeFormat == FormatTime::TIME) { + struct tm tl; + time_t time = content.tv_sec; +#if (defined( __WINDOWS__ )) + if (localtime_s(&tl, &time) != 0) { + return; + } +#else + if (localtime_r(&time, &tl) == nullptr) { + return; + } + if (format.zone) { + out << tl.tm_zone << " "; + } +#endif + if (format.year) { + out << (tl.tm_year + TM_YEAR_BASE) << "-"; + } + out << setfill('0'); + out << setw(DT_WIDTH) << (tl.tm_mon + 1) << "-" << setw(DT_WIDTH) << tl.tm_mday << " "; + out << setw(DT_WIDTH) << tl.tm_hour << ":" << setw(DT_WIDTH) << tl.tm_min << ":"; + out << setw(DT_WIDTH) << tl.tm_sec; + } else if (format.timeFormat == FormatTime::MONOTONIC) { + out << setfill(' '); + out << setw(MONO_WIDTH) << content.mono_sec; + } else if (format.timeFormat == FormatTime::EPOCH) { + out << setfill(' '); + out << setw(EPOCH_WIDTH) << content.tv_sec; + } else { + out << "Invalid time format" << endl; + return; + } + // 1.1 print msec/usec/nsec + out << "."; + out << setfill('0'); + if (format.timeAccuFormat == FormatTimeAccu::MSEC) { + out << setw(MSEC_WIDTH) << (content.tv_nsec / NS2MS); + } else if (format.timeAccuFormat == FormatTimeAccu::USEC) { + out << setw(USEC_WIDTH) << (content.tv_nsec / NS2US); + } else if (format.timeAccuFormat == FormatTimeAccu::NSEC) { + out << setw(NSEC_WIDTH) << content.tv_nsec; + } else { + out << "Invalid time accuracy format" << endl; + return; + } + out << setfill(' '); + // 2. print pid/tid + out << " " << setw(PID_WIDTH) << content.pid << " " << setw(PID_WIDTH) << content.tid; + // 3. print level + out << " " << LogLevel2ShortStr(content.level) << " "; + // 4. print log type + out << GetLogTypePrefix(content.type); + // 5. print domain + out << setfill('0'); + out << hex << setw(DOMAIN_WIDTH) << ShortDomain(content.domain) << dec; + // 5. print tag & log + out << "/" << content.tag << ": "; +} + +void LogPrintWithFormat(const LogContent& content, const LogFormat& format, std::ostream& out) +{ + // set colorful log + if (format.colorful) { + out << "\x1B[38;5;" << GetColor(content.level) << "m"; + } + + const char *pHead = content.log; + const char *pScan = content.log; + // split the log content by '\n', and add log prefix(datetime, pid, tid....) to each new line + while (*pScan != '\0') { + if (*pScan == '\n') { + char tmp[MAX_LOG_LEN]; + int len = static_cast(pScan - pHead); + errno_t ret = memcpy_s(tmp, MAX_LOG_LEN - 1, pHead, len); + if (ret != EOK) { + break; + } + tmp[(MAX_LOG_LEN - 1) > len ? len : (MAX_LOG_LEN -1)] = '\0'; + if (tmp[0] != '\0') { + PrintLogPrefix(content, format, out); + out << tmp << endl; + } + pHead = pScan + 1; + } + pScan++; + } + if (pHead[0] != '\0') { + PrintLogPrefix(content, format, out); + out << pHead; + } + + // restore color + if (format.colorful) { + out << "\x1B[0m"; + } + if (pHead[0] != '\0') { + out << endl; + } + return; +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/frameworks/libhilog/utils/log_utils.cpp b/frameworks/libhilog/utils/log_utils.cpp index 7cef847..af130c4 100644 --- a/frameworks/libhilog/utils/log_utils.cpp +++ b/frameworks/libhilog/utils/log_utils.cpp @@ -1,522 +1,522 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hilog_common.h" -#include "hilog_cmd.h" -#include "log_utils.h" - -namespace { - constexpr uint32_t ONE_KB = (1UL << 10); - constexpr uint32_t ONE_MB = (1UL << 20); - constexpr uint32_t ONE_GB = (1UL << 30); - constexpr uint64_t ONE_TB = (1ULL << 40); - constexpr uint32_t DOMAIN_MIN = DOMAIN_APP_MIN; - constexpr uint32_t DOMAIN_MAX = DOMAIN_OS_MAX; - constexpr int CMDLINE_PATH_LEN = 32; - constexpr int CMDLINE_LEN = 128; - constexpr int STATUS_PATH_LEN = 32; - constexpr int STATUS_LEN = 1024; - const std::string SH_NAMES[] = { "sh", "/bin/sh", "/system/bin/sh", "/xbin/sh", "/system/xbin/sh"}; -} - -namespace OHOS { -namespace HiviewDFX { -using namespace std; -using namespace std::chrono; - -// Buffer Size&Char Map -static const KVMap g_SizeMap({ - {'B', 1}, {'K', ONE_KB}, {'M', ONE_MB}, - {'G', ONE_GB}, {'T', ONE_TB} -}, ' ', 0); - -string Size2Str(uint64_t size) -{ - string str; - uint64_t unit = 1; - switch (size) { - case 0 ... ONE_KB - 1: unit = 1; break; - case ONE_KB ... ONE_MB - 1: unit = ONE_KB; break; - case ONE_MB ... ONE_GB - 1: unit = ONE_MB; break; - case ONE_GB ... ONE_TB - 1: unit = ONE_GB; break; - default: unit = ONE_TB; break; - } - float i = (static_cast(size)) / unit; - constexpr int len = 16; - char buf[len] = { 0 }; - int ret = snprintf_s(buf, len, len - 1, "%.1f", i); - if (ret <= 0) { - str = to_string(size); - } else { - str = buf; - } - return str + g_SizeMap.GetKey(unit); -} - -uint64_t Str2Size(const string& str) -{ - std::regex reg("[0-9]+[BKMGT]?"); - if (!std::regex_match(str, reg)) { - return 0; - } - uint64_t index = str.size() - 1; - uint64_t unit = g_SizeMap.GetValue(str[index]); - - uint64_t value = stoull(str.substr(0, unit !=0 ? index : index + 1)); - return value * (unit != 0 ? unit : 1); -} - -// Error Codes&Strings Map -static const KVMap g_ErrorMsgs({ - {RET_SUCCESS, "Success"}, - {RET_FAIL, "Unknown failure reason"}, - {ERR_LOG_LEVEL_INVALID, "Invalid log level, the valid log levels include D/I/W/E/F" - " or DEBUG/INFO/WARN/ERROR/FATAL"}, - {ERR_LOG_TYPE_INVALID, "Invalid log type, the valid log types include app/core/init/kmsg"}, - {ERR_INVALID_RQST_CMD, "Invalid request cmd, please check sourcecode"}, - {ERR_QUERY_TYPE_INVALID, "Can't query kmsg type logs combined with other types logs."}, - {ERR_INVALID_DOMAIN_STR, "Invalid domain string"}, - {ERR_LOG_PERSIST_FILE_SIZE_INVALID, "Invalid log persist file size, file size should be in range [" - + Size2Str(MIN_LOG_FILE_SIZE) + ", " + Size2Str(MAX_LOG_FILE_SIZE) + "]"}, - {ERR_LOG_PERSIST_FILE_NAME_INVALID, "Invalid log persist file name, file name should not contain [\\/:*?\"<>|]"}, - {ERR_LOG_PERSIST_COMPRESS_BUFFER_EXP, "Invalid Log persist compression buffer"}, - {ERR_LOG_PERSIST_FILE_PATH_INVALID, "Invalid persister file path or persister directory does not exist"}, - {ERR_LOG_PERSIST_COMPRESS_INIT_FAIL, "Log persist compression initialization failed"}, - {ERR_LOG_PERSIST_FILE_OPEN_FAIL, "Log persist open file failed"}, - {ERR_LOG_PERSIST_JOBID_FAIL, "Log persist jobid not exist"}, - {ERR_LOG_PERSIST_TASK_EXISTED, "Log persist task is existed"}, - {ERR_DOMAIN_INVALID, ("Invalid domain, domain should be in range (" + Uint2HexStr(DOMAIN_MIN) - + ", " +Uint2HexStr(DOMAIN_MAX) +"]")}, - {ERR_MSG_LEN_INVALID, "Invalid message length"}, - {ERR_LOG_PERSIST_JOBID_INVALID, "Invalid jobid, jobid should be in range [" + to_string(JOB_ID_MIN) - + ", " + to_string(JOB_ID_MAX) + ")"}, - {ERR_BUFF_SIZE_INVALID, ("Invalid buffer size, buffer size should be in range [" + Size2Str(MIN_BUFFER_SIZE) - + ", " + Size2Str(MAX_BUFFER_SIZE) + "]")}, - {ERR_COMMAND_INVALID, "Mutlti commands can't be used in combination"}, - {ERR_LOG_FILE_NUM_INVALID, "Invalid number of files"}, - {ERR_NOT_NUMBER_STR, "Not a numeric string"}, - {ERR_TOO_MANY_ARGUMENTS, "Too many arguments"}, - {ERR_DUPLICATE_OPTION, "Too many duplicate options"}, - {ERR_INVALID_ARGUMENT, "Invalid argument"}, - {ERR_TOO_MANY_DOMAINS, "Max domain count is " + to_string(MAX_DOMAINS)}, - {ERR_INVALID_SIZE_STR, "Invalid size string"}, - {ERR_TOO_MANY_PIDS, "Max pid count is " + to_string(MAX_PIDS)}, - {ERR_TOO_MANY_TAGS, "Max tag count is " + to_string(MAX_TAGS)}, - {ERR_TAG_STR_TOO_LONG, ("Tag string too long, max length is " + to_string(MAX_TAG_LEN - 1))}, - {ERR_REGEX_STR_TOO_LONG, ("Regular expression too long, max length is " + to_string(MAX_REGEX_STR_LEN - 1))}, - {ERR_FILE_NAME_TOO_LONG, ("File name too long, max length is " + to_string(MAX_FILE_NAME_LEN))}, - {ERR_SOCKET_CLIENT_INIT_FAIL, "Socket client init failed"}, - {ERR_SOCKET_WRITE_MSG_HEADER_FAIL, "Socket rite message header failed"}, - {ERR_SOCKET_WRITE_CMD_FAIL, "Socket write command failed"}, - {ERR_SOCKET_RECEIVE_RSP, "Unable to receive message from socket"}, - {ERR_PERSIST_TASK_EMPTY, "No running persist task, please check"}, - {ERR_JOBID_NOT_EXSIST, "Persist task of this job id doesn't exist, please check"}, - {ERR_TOO_MANY_JOBS, ("Too many jobs are running, max job count is:" + to_string(MAX_JOBS))}, - {ERR_STATS_NOT_ENABLE, "Statistic feature is not enable, " - "please set param persist.sys.hilog.stats true to enable it, " - "further more, you can set persist.sys.hilog.stats.tag true to enable counting log by tags"}, - {ERR_NO_RUNNING_TASK, "No running persistent task"}, - {ERR_NO_PID_PERMISSION, "Permission denied, only shell and root can filter logs by pid"}, -}, RET_FAIL, "Unknown error code"); - -string ErrorCode2Str(int16_t errorCode) -{ - return g_ErrorMsgs.GetValue((uint16_t)errorCode) + " [CODE: " + to_string(errorCode) + "]"; -} - -// Log Types&Strings Map -static const StringMap g_LogTypes({ - {LOG_INIT, "init"}, {LOG_CORE, "core"}, {LOG_APP, "app"}, {LOG_KMSG, "kmsg"} -}, LOG_TYPE_MAX, "invalid"); - -string LogType2Str(uint16_t logType) -{ - return g_LogTypes.GetValue(logType); -} - -uint16_t Str2LogType(const string& str) -{ - return g_LogTypes.GetKey(str); -} - -string ComboLogType2Str(uint16_t shiftType) -{ - vector types = g_LogTypes.GetAllKeys(); - string str = ""; - uint16_t typeAll = 0; - - for (uint16_t t : types) { - typeAll |= (1 << t); - } - shiftType &= typeAll; - for (uint16_t t: types) { - if ((1 << t) & shiftType) { - shiftType &= (~(1 << t)); - str += (LogType2Str(t) + (shiftType != 0 ? "," : "")); - } - if (shiftType == 0) { - break; - } - } - return str; -} - -uint16_t Str2ComboLogType(const string& str) -{ - uint16_t logTypes = 0; - if (str == "") { - logTypes = (1 << LOG_CORE) | (1 << LOG_APP); - return logTypes; - } - vector vec; - Split(str, vec); - for (auto& it : vec) { - if (it == "") { - continue; - } - uint16_t t = Str2LogType(it); - if (t == LOG_TYPE_MAX) { - return 0; - } - logTypes |= (1 << t); - } - return logTypes; -} - -vector GetAllLogTypes() -{ - return g_LogTypes.GetAllKeys(); -} - -// Log Levels&Strings Map -static const StringMap g_LogLevels({ - {LOG_DEBUG, "DEBUG"}, {LOG_INFO, "INFO"}, {LOG_WARN, "WARN"}, - {LOG_ERROR, "ERROR"}, {LOG_FATAL, "FATAL"}, {LOG_LEVEL_MAX, "X"} -}, LOG_LEVEL_MIN, "INVALID", [](const string& l1, const string& l2) { - if (l1.length() == l2.length()) { - return std::equal(l1.begin(), l1.end(), l2.begin(), [](char a, char b) { - return std::tolower(a) == std::tolower(b); - }); - } else { - return false; - } -}); - -string LogLevel2Str(uint16_t logLevel) -{ - return g_LogLevels.GetValue(logLevel); -} - -uint16_t Str2LogLevel(const string& str) -{ - return g_LogLevels.GetKey(str); -} - -// Log Levels&Short Strings Map -static const StringMap g_ShortLogLevels({ - {LOG_DEBUG, "D"}, {LOG_INFO, "I"}, {LOG_WARN, "W"}, - {LOG_ERROR, "E"}, {LOG_FATAL, "F"}, {LOG_LEVEL_MAX, "X"} -}, LOG_LEVEL_MIN, "V", [](const string& l1, const string& l2) { - return (l1.length() == 1 && std::tolower(l1[0]) == std::tolower(l2[0])); -}); - -string LogLevel2ShortStr(uint16_t logLevel) -{ - return g_ShortLogLevels.GetValue(logLevel); -} - -uint16_t ShortStr2LogLevel(const string& str) -{ - return g_ShortLogLevels.GetKey(str); -} - -uint16_t PrettyStr2LogLevel(const string& str) -{ - uint16_t level = ShortStr2LogLevel(str); - if (level == static_cast(LOG_LEVEL_MIN)) { - return Str2LogLevel(str); - } - return level; -} - -string ComboLogLevel2Str(uint16_t shiftLevel) -{ - vector levels = g_ShortLogLevels.GetAllKeys(); - string str = ""; - uint16_t levelAll = 0; - - for (uint16_t l : levels) { - levelAll |= (1 << l); - } - shiftLevel &= levelAll; - for (uint16_t l: levels) { - if ((1 << l) & shiftLevel) { - shiftLevel &= (~(1 << l)); - str += (LogLevel2Str(l) + (shiftLevel != 0 ? "," : "")); - } - if (shiftLevel == 0) { - break; - } - } - return str; -} - -uint16_t Str2ComboLogLevel(const string& str) -{ - uint16_t logLevels = 0; - if (str == "") { - logLevels = 0xFFFF; - return logLevels; - } - vector vec; - Split(str, vec); - for (auto& it : vec) { - if (it == "") { - continue; - } - uint16_t t = PrettyStr2LogLevel(it); - if (t == LOG_LEVEL_MIN || t >= LOG_LEVEL_MAX) { - return 0; - } - logLevels |= (1 << t); - } - return logLevels; -} - -void Split(const std::string& src, std::vector& dest, const std::string& separator) -{ - std::string str = src; - std::string substring; - std::string::size_type start = 0; - std::string::size_type index; - dest.clear(); - index = str.find_first_of(separator, start); - if (index == std::string::npos) { - dest.emplace_back(str); - return; - } - do { - substring = str.substr(start, index - start); - dest.emplace_back(substring); - start = index + separator.size(); - index = str.find(separator, start); - } while (index != std::string::npos); - substring = str.substr(start); - if (substring != "") { - dest.emplace_back(substring); - } -} - -uint32_t GetBitsCount(uint64_t n) -{ - uint32_t count = 0; - while (n != 0) { - ++count; - n = n & (n-1); - } - return count; -} - -uint16_t GetBitPos(uint64_t n) -{ - if (!(n && (!(n & (n-1))))) { // only accpet the number which is power of 2 - return 0; - } - - uint16_t i = 0; - while (n >> (i++)) {} - i--; - return i-1; -} - -enum class Radix { - RADIX_DEC, - RADIX_HEX, -}; -template -static string Num2Str(T num, Radix radix) -{ - stringstream ss; - auto r = std::dec; - if (radix == Radix::RADIX_HEX) { - r = std::hex; - } - ss << r << num; - return ss.str(); -} - -template -static void Str2Num(const string& str, T& num, Radix radix) -{ - T i = 0; - std::stringstream ss; - auto r = std::dec; - if (radix == Radix::RADIX_HEX) { - r = std::hex; - } - ss << r << str; - ss >> i; - num = i; - return; -} - -string Uint2DecStr(uint32_t i) -{ - return Num2Str(i, Radix::RADIX_DEC); -} - -uint32_t DecStr2Uint(const string& str) -{ - uint32_t i = 0; - Str2Num(str, i, Radix::RADIX_DEC); - return i; -} - -string Uint2HexStr(uint32_t i) -{ - return Num2Str(i, Radix::RADIX_HEX); -} - -uint32_t HexStr2Uint(const string& str) -{ - uint32_t i = 0; - Str2Num(str, i, Radix::RADIX_HEX); - return i; -} - -#if !defined(__WINDOWS__) and !defined(__LINUX__) -string GetProgName() -{ -#ifdef HILOG_USE_MUSL - return program_invocation_short_name; -#else - return getprogname(); -#endif -} -#endif - -string GetNameByPid(uint32_t pid) -{ - char path[CMDLINE_PATH_LEN] = { 0 }; - if (snprintf_s(path, CMDLINE_PATH_LEN, CMDLINE_PATH_LEN - 1, "/proc/%d/cmdline", pid) <= 0) { - return ""; - } - char cmdline[CMDLINE_LEN] = { 0 }; - int i = 0; - FILE *fp = fopen(path, "r"); - if (fp == nullptr) { - return ""; - } - while (i < (CMDLINE_LEN - 1)) { - char c = static_cast(fgetc(fp)); - // 0. don't need args of cmdline - // 1. ignore unvisible character - if (!isgraph(c)) { - break; - } - cmdline[i] = c; - i++; - } - (void)fclose(fp); - return cmdline; -} - -uint32_t GetPPidByPid(uint32_t pid) -{ - uint32_t ppid = 0; - char path[STATUS_PATH_LEN] = { 0 }; - if (snprintf_s(path, STATUS_PATH_LEN, STATUS_PATH_LEN - 1, "/proc/%u/status", pid) <= 0) { - return ppid; - } - FILE *fp = fopen(path, "r"); - if (fp == nullptr) { - return ppid; - } - char buf[STATUS_LEN] = { 0 }; - size_t ret = fread(buf, sizeof(char), STATUS_LEN - 1, fp); - (void)fclose(fp); - if (ret <= 0) { - return ppid; - } else { - buf[ret++] = '\0'; - } - char *ppidLoc = strstr(buf, "PPid:"); - if ((ppidLoc == nullptr) || (sscanf_s(ppidLoc, "PPid:%d", &ppid) == -1)) { - return ppid; - } - std::string ppidName = GetNameByPid(ppid); - // ppid fork the sh to execute hilog, sh is not wanted ppid - if (std::find(std::begin(SH_NAMES), std::end(SH_NAMES), ppidName) != std::end(SH_NAMES)) { - return GetPPidByPid(ppid); - } - return ppid; -} - -uint64_t GenerateHash(const char *p, size_t size) -{ - static const uint64_t PRIME = 0x100000001B3ull; - static const uint64_t BASIS = 0xCBF29CE484222325ull; - uint64_t ret {BASIS}; - unsigned long i = 0; - while (i < size) { - ret ^= *(p + i); - ret *= PRIME; - i++; - } - return ret; -} - -void PrintErrorno(int err) -{ - constexpr int bufSize = 256; - char buf[bufSize] = { 0 }; -#ifndef __WINDOWS__ - (void)strerror_r(err, buf, bufSize); -#else - (void)strerror_s(buf, bufSize, err); -#endif - std::cerr << "Errno: " << err << ", " << buf << std::endl; -} - -int WaitingToDo(int max, const string& path, function func) -{ - chrono::steady_clock::time_point start = chrono::steady_clock::now(); - chrono::milliseconds wait(max); - while (true) { - if (func(path) != RET_FAIL) { - cout << "waiting for " << path << " successfully!" << endl; - return RET_SUCCESS; - } - - std::this_thread::sleep_for(10ms); - if ((chrono::steady_clock::now() - start) > wait) { - cerr << "waiting for " << path << " failed!" << endl; - return RET_FAIL; - } - } -} -} // namespace HiviewDFX -} // namespace OHOS +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hilog_common.h" +#include "hilog_cmd.h" +#include "log_utils.h" + +namespace { + constexpr uint32_t ONE_KB = (1UL << 10); + constexpr uint32_t ONE_MB = (1UL << 20); + constexpr uint32_t ONE_GB = (1UL << 30); + constexpr uint64_t ONE_TB = (1ULL << 40); + constexpr uint32_t DOMAIN_MIN = DOMAIN_APP_MIN; + constexpr uint32_t DOMAIN_MAX = DOMAIN_OS_MAX; + constexpr int CMDLINE_PATH_LEN = 32; + constexpr int CMDLINE_LEN = 128; + constexpr int STATUS_PATH_LEN = 32; + constexpr int STATUS_LEN = 1024; + const std::string SH_NAMES[] = { "sh", "/bin/sh", "/system/bin/sh", "/xbin/sh", "/system/xbin/sh"}; +} + +namespace OHOS { +namespace HiviewDFX { +using namespace std; +using namespace std::chrono; + +// Buffer Size&Char Map +static const KVMap g_SizeMap({ + {'B', 1}, {'K', ONE_KB}, {'M', ONE_MB}, + {'G', ONE_GB}, {'T', ONE_TB} +}, ' ', 0); + +string Size2Str(uint64_t size) +{ + string str; + uint64_t unit = 1; + switch (size) { + case 0 ... ONE_KB - 1: unit = 1; break; + case ONE_KB ... ONE_MB - 1: unit = ONE_KB; break; + case ONE_MB ... ONE_GB - 1: unit = ONE_MB; break; + case ONE_GB ... ONE_TB - 1: unit = ONE_GB; break; + default: unit = ONE_TB; break; + } + float i = (static_cast(size)) / unit; + constexpr int len = 16; + char buf[len] = { 0 }; + int ret = snprintf_s(buf, len, len - 1, "%.1f", i); + if (ret <= 0) { + str = to_string(size); + } else { + str = buf; + } + return str + g_SizeMap.GetKey(unit); +} + +uint64_t Str2Size(const string& str) +{ + std::regex reg("[0-9]+[BKMGT]?"); + if (!std::regex_match(str, reg)) { + return 0; + } + uint64_t index = str.size() - 1; + uint64_t unit = g_SizeMap.GetValue(str[index]); + + uint64_t value = stoull(str.substr(0, unit !=0 ? index : index + 1)); + return value * (unit != 0 ? unit : 1); +} + +// Error Codes&Strings Map +static const KVMap g_ErrorMsgs({ + {RET_SUCCESS, "Success"}, + {RET_FAIL, "Unknown failure reason"}, + {ERR_LOG_LEVEL_INVALID, "Invalid log level, the valid log levels include D/I/W/E/F" + " or DEBUG/INFO/WARN/ERROR/FATAL"}, + {ERR_LOG_TYPE_INVALID, "Invalid log type, the valid log types include app/core/init/kmsg"}, + {ERR_INVALID_RQST_CMD, "Invalid request cmd, please check sourcecode"}, + {ERR_QUERY_TYPE_INVALID, "Can't query kmsg type logs combined with other types logs."}, + {ERR_INVALID_DOMAIN_STR, "Invalid domain string"}, + {ERR_LOG_PERSIST_FILE_SIZE_INVALID, "Invalid log persist file size, file size should be in range [" + + Size2Str(MIN_LOG_FILE_SIZE) + ", " + Size2Str(MAX_LOG_FILE_SIZE) + "]"}, + {ERR_LOG_PERSIST_FILE_NAME_INVALID, "Invalid log persist file name, file name should not contain [\\/:*?\"<>|]"}, + {ERR_LOG_PERSIST_COMPRESS_BUFFER_EXP, "Invalid Log persist compression buffer"}, + {ERR_LOG_PERSIST_FILE_PATH_INVALID, "Invalid persister file path or persister directory does not exist"}, + {ERR_LOG_PERSIST_COMPRESS_INIT_FAIL, "Log persist compression initialization failed"}, + {ERR_LOG_PERSIST_FILE_OPEN_FAIL, "Log persist open file failed"}, + {ERR_LOG_PERSIST_JOBID_FAIL, "Log persist jobid not exist"}, + {ERR_LOG_PERSIST_TASK_EXISTED, "Log persist task is existed"}, + {ERR_DOMAIN_INVALID, ("Invalid domain, domain should be in range (" + Uint2HexStr(DOMAIN_MIN) + + ", " +Uint2HexStr(DOMAIN_MAX) +"]")}, + {ERR_MSG_LEN_INVALID, "Invalid message length"}, + {ERR_LOG_PERSIST_JOBID_INVALID, "Invalid jobid, jobid should be in range [" + to_string(JOB_ID_MIN) + + ", " + to_string(JOB_ID_MAX) + ")"}, + {ERR_BUFF_SIZE_INVALID, ("Invalid buffer size, buffer size should be in range [" + Size2Str(MIN_BUFFER_SIZE) + + ", " + Size2Str(MAX_BUFFER_SIZE) + "]")}, + {ERR_COMMAND_INVALID, "Mutlti commands can't be used in combination"}, + {ERR_LOG_FILE_NUM_INVALID, "Invalid number of files"}, + {ERR_NOT_NUMBER_STR, "Not a numeric string"}, + {ERR_TOO_MANY_ARGUMENTS, "Too many arguments"}, + {ERR_DUPLICATE_OPTION, "Too many duplicate options"}, + {ERR_INVALID_ARGUMENT, "Invalid argument"}, + {ERR_TOO_MANY_DOMAINS, "Max domain count is " + to_string(MAX_DOMAINS)}, + {ERR_INVALID_SIZE_STR, "Invalid size string"}, + {ERR_TOO_MANY_PIDS, "Max pid count is " + to_string(MAX_PIDS)}, + {ERR_TOO_MANY_TAGS, "Max tag count is " + to_string(MAX_TAGS)}, + {ERR_TAG_STR_TOO_LONG, ("Tag string too long, max length is " + to_string(MAX_TAG_LEN - 1))}, + {ERR_REGEX_STR_TOO_LONG, ("Regular expression too long, max length is " + to_string(MAX_REGEX_STR_LEN - 1))}, + {ERR_FILE_NAME_TOO_LONG, ("File name too long, max length is " + to_string(MAX_FILE_NAME_LEN))}, + {ERR_SOCKET_CLIENT_INIT_FAIL, "Socket client init failed"}, + {ERR_SOCKET_WRITE_MSG_HEADER_FAIL, "Socket rite message header failed"}, + {ERR_SOCKET_WRITE_CMD_FAIL, "Socket write command failed"}, + {ERR_SOCKET_RECEIVE_RSP, "Unable to receive message from socket"}, + {ERR_PERSIST_TASK_EMPTY, "No running persist task, please check"}, + {ERR_JOBID_NOT_EXSIST, "Persist task of this job id doesn't exist, please check"}, + {ERR_TOO_MANY_JOBS, ("Too many jobs are running, max job count is:" + to_string(MAX_JOBS))}, + {ERR_STATS_NOT_ENABLE, "Statistic feature is not enable, " + "please set param persist.sys.hilog.stats true to enable it, " + "further more, you can set persist.sys.hilog.stats.tag true to enable counting log by tags"}, + {ERR_NO_RUNNING_TASK, "No running persistent task"}, + {ERR_NO_PID_PERMISSION, "Permission denied, only shell and root can filter logs by pid"}, +}, RET_FAIL, "Unknown error code"); + +string ErrorCode2Str(int16_t errorCode) +{ + return g_ErrorMsgs.GetValue((uint16_t)errorCode) + " [CODE: " + to_string(errorCode) + "]"; +} + +// Log Types&Strings Map +static const StringMap g_LogTypes({ + {LOG_INIT, "init"}, {LOG_CORE, "core"}, {LOG_APP, "app"}, {LOG_KMSG, "kmsg"} +}, LOG_TYPE_MAX, "invalid"); + +string LogType2Str(uint16_t logType) +{ + return g_LogTypes.GetValue(logType); +} + +uint16_t Str2LogType(const string& str) +{ + return g_LogTypes.GetKey(str); +} + +string ComboLogType2Str(uint16_t shiftType) +{ + vector types = g_LogTypes.GetAllKeys(); + string str = ""; + uint16_t typeAll = 0; + + for (uint16_t t : types) { + typeAll |= (1 << t); + } + shiftType &= typeAll; + for (uint16_t t: types) { + if ((1 << t) & shiftType) { + shiftType &= (~(1 << t)); + str += (LogType2Str(t) + (shiftType != 0 ? "," : "")); + } + if (shiftType == 0) { + break; + } + } + return str; +} + +uint16_t Str2ComboLogType(const string& str) +{ + uint16_t logTypes = 0; + if (str == "") { + logTypes = (1 << LOG_CORE) | (1 << LOG_APP); + return logTypes; + } + vector vec; + Split(str, vec); + for (auto& it : vec) { + if (it == "") { + continue; + } + uint16_t t = Str2LogType(it); + if (t == LOG_TYPE_MAX) { + return 0; + } + logTypes |= (1 << t); + } + return logTypes; +} + +vector GetAllLogTypes() +{ + return g_LogTypes.GetAllKeys(); +} + +// Log Levels&Strings Map +static const StringMap g_LogLevels({ + {LOG_DEBUG, "DEBUG"}, {LOG_INFO, "INFO"}, {LOG_WARN, "WARN"}, + {LOG_ERROR, "ERROR"}, {LOG_FATAL, "FATAL"}, {LOG_LEVEL_MAX, "X"} +}, LOG_LEVEL_MIN, "INVALID", [](const string& l1, const string& l2) { + if (l1.length() == l2.length()) { + return std::equal(l1.begin(), l1.end(), l2.begin(), [](char a, char b) { + return std::tolower(a) == std::tolower(b); + }); + } else { + return false; + } +}); + +string LogLevel2Str(uint16_t logLevel) +{ + return g_LogLevels.GetValue(logLevel); +} + +uint16_t Str2LogLevel(const string& str) +{ + return g_LogLevels.GetKey(str); +} + +// Log Levels&Short Strings Map +static const StringMap g_ShortLogLevels({ + {LOG_DEBUG, "D"}, {LOG_INFO, "I"}, {LOG_WARN, "W"}, + {LOG_ERROR, "E"}, {LOG_FATAL, "F"}, {LOG_LEVEL_MAX, "X"} +}, LOG_LEVEL_MIN, "V", [](const string& l1, const string& l2) { + return (l1.length() == 1 && std::tolower(l1[0]) == std::tolower(l2[0])); +}); + +string LogLevel2ShortStr(uint16_t logLevel) +{ + return g_ShortLogLevels.GetValue(logLevel); +} + +uint16_t ShortStr2LogLevel(const string& str) +{ + return g_ShortLogLevels.GetKey(str); +} + +uint16_t PrettyStr2LogLevel(const string& str) +{ + uint16_t level = ShortStr2LogLevel(str); + if (level == static_cast(LOG_LEVEL_MIN)) { + return Str2LogLevel(str); + } + return level; +} + +string ComboLogLevel2Str(uint16_t shiftLevel) +{ + vector levels = g_ShortLogLevels.GetAllKeys(); + string str = ""; + uint16_t levelAll = 0; + + for (uint16_t l : levels) { + levelAll |= (1 << l); + } + shiftLevel &= levelAll; + for (uint16_t l: levels) { + if ((1 << l) & shiftLevel) { + shiftLevel &= (~(1 << l)); + str += (LogLevel2Str(l) + (shiftLevel != 0 ? "," : "")); + } + if (shiftLevel == 0) { + break; + } + } + return str; +} + +uint16_t Str2ComboLogLevel(const string& str) +{ + uint16_t logLevels = 0; + if (str == "") { + logLevels = 0xFFFF; + return logLevels; + } + vector vec; + Split(str, vec); + for (auto& it : vec) { + if (it == "") { + continue; + } + uint16_t t = PrettyStr2LogLevel(it); + if (t == LOG_LEVEL_MIN || t >= LOG_LEVEL_MAX) { + return 0; + } + logLevels |= (1 << t); + } + return logLevels; +} + +void Split(const std::string& src, std::vector& dest, const std::string& separator) +{ + std::string str = src; + std::string substring; + std::string::size_type start = 0; + std::string::size_type index; + dest.clear(); + index = str.find_first_of(separator, start); + if (index == std::string::npos) { + dest.emplace_back(str); + return; + } + do { + substring = str.substr(start, index - start); + dest.emplace_back(substring); + start = index + separator.size(); + index = str.find(separator, start); + } while (index != std::string::npos); + substring = str.substr(start); + if (substring != "") { + dest.emplace_back(substring); + } +} + +uint32_t GetBitsCount(uint64_t n) +{ + uint32_t count = 0; + while (n != 0) { + ++count; + n = n & (n-1); + } + return count; +} + +uint16_t GetBitPos(uint64_t n) +{ + if (!(n && (!(n & (n-1))))) { // only accpet the number which is power of 2 + return 0; + } + + uint16_t i = 0; + while (n >> (i++)) {} + i--; + return i-1; +} + +enum class Radix { + RADIX_DEC, + RADIX_HEX, +}; +template +static string Num2Str(T num, Radix radix) +{ + stringstream ss; + auto r = std::dec; + if (radix == Radix::RADIX_HEX) { + r = std::hex; + } + ss << r << num; + return ss.str(); +} + +template +static void Str2Num(const string& str, T& num, Radix radix) +{ + T i = 0; + std::stringstream ss; + auto r = std::dec; + if (radix == Radix::RADIX_HEX) { + r = std::hex; + } + ss << r << str; + ss >> i; + num = i; + return; +} + +string Uint2DecStr(uint32_t i) +{ + return Num2Str(i, Radix::RADIX_DEC); +} + +uint32_t DecStr2Uint(const string& str) +{ + uint32_t i = 0; + Str2Num(str, i, Radix::RADIX_DEC); + return i; +} + +string Uint2HexStr(uint32_t i) +{ + return Num2Str(i, Radix::RADIX_HEX); +} + +uint32_t HexStr2Uint(const string& str) +{ + uint32_t i = 0; + Str2Num(str, i, Radix::RADIX_HEX); + return i; +} + +#if !defined(__WINDOWS__) and !defined(__LINUX__) +string GetProgName() +{ +#ifdef HILOG_USE_MUSL + return program_invocation_short_name; +#else + return getprogname(); +#endif +} +#endif + +string GetNameByPid(uint32_t pid) +{ + char path[CMDLINE_PATH_LEN] = { 0 }; + if (snprintf_s(path, CMDLINE_PATH_LEN, CMDLINE_PATH_LEN - 1, "/proc/%d/cmdline", pid) <= 0) { + return ""; + } + char cmdline[CMDLINE_LEN] = { 0 }; + int i = 0; + FILE *fp = fopen(path, "r"); + if (fp == nullptr) { + return ""; + } + while (i < (CMDLINE_LEN - 1)) { + char c = static_cast(fgetc(fp)); + // 0. don't need args of cmdline + // 1. ignore unvisible character + if (!isgraph(c)) { + break; + } + cmdline[i] = c; + i++; + } + (void)fclose(fp); + return cmdline; +} + +uint32_t GetPPidByPid(uint32_t pid) +{ + uint32_t ppid = 0; + char path[STATUS_PATH_LEN] = { 0 }; + if (snprintf_s(path, STATUS_PATH_LEN, STATUS_PATH_LEN - 1, "/proc/%u/status", pid) <= 0) { + return ppid; + } + FILE *fp = fopen(path, "r"); + if (fp == nullptr) { + return ppid; + } + char buf[STATUS_LEN] = { 0 }; + size_t ret = fread(buf, sizeof(char), STATUS_LEN - 1, fp); + (void)fclose(fp); + if (ret <= 0) { + return ppid; + } else { + buf[ret++] = '\0'; + } + char *ppidLoc = strstr(buf, "PPid:"); + if ((ppidLoc == nullptr) || (sscanf_s(ppidLoc, "PPid:%d", &ppid) == -1)) { + return ppid; + } + std::string ppidName = GetNameByPid(ppid); + // ppid fork the sh to execute hilog, sh is not wanted ppid + if (std::find(std::begin(SH_NAMES), std::end(SH_NAMES), ppidName) != std::end(SH_NAMES)) { + return GetPPidByPid(ppid); + } + return ppid; +} + +uint64_t GenerateHash(const char *p, size_t size) +{ + static const uint64_t PRIME = 0x100000001B3ull; + static const uint64_t BASIS = 0xCBF29CE484222325ull; + uint64_t ret {BASIS}; + unsigned long i = 0; + while (i < size) { + ret ^= *(p + i); + ret *= PRIME; + i++; + } + return ret; +} + +void PrintErrorno(int err) +{ + constexpr int bufSize = 256; + char buf[bufSize] = { 0 }; +#ifndef __WINDOWS__ + (void)strerror_r(err, buf, bufSize); +#else + (void)strerror_s(buf, bufSize, err); +#endif + std::cerr << "Errno: " << err << ", " << buf << std::endl; +} + +int WaitingToDo(int max, const string& path, function func) +{ + chrono::steady_clock::time_point start = chrono::steady_clock::now(); + chrono::milliseconds wait(max); + while (true) { + if (func(path) != RET_FAIL) { + cout << "waiting for " << path << " successfully!" << endl; + return RET_SUCCESS; + } + + std::this_thread::sleep_for(10ms); + if ((chrono::steady_clock::now() - start) > wait) { + cerr << "waiting for " << path << " failed!" << endl; + return RET_FAIL; + } + } +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/frameworks/libhilog/vsnprintf/include/output_p.inl b/frameworks/libhilog/vsnprintf/include/output_p.inl new file mode 100644 index 0000000..d58873b --- /dev/null +++ b/frameworks/libhilog/vsnprintf/include/output_p.inl @@ -0,0 +1,1294 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/* [Standardize-exceptions] Use unsafe function: Portability + * [reason] Use unsafe function to implement security function to maintain platform compatibility. + * And sufficient input validation is performed before calling + */ + +#ifndef OUTPUT_P_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 +#define OUTPUT_P_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 + +#define SECUREC_FLOAT_BUFSIZE (309+40) /* max float point value */ +#define SECUREC_FLOAT_BUFSIZE_LB (4932+40) /* max long double value */ + +#define SECUREC_INT_MAX 2147483647 + +#define SECUREC_MUL10(x) ((((x) << 2) + (x)) << 1) +#define SECUREC_INT_MAX_DIV_TEN 21474836 +#define SECUREC_MUL10_ADD_BEYOND_MAX(val) (((val) > SECUREC_INT_MAX_DIV_TEN)) + +#ifdef SECUREC_STACK_SIZE_LESS_THAN_1K +#define SECUREC_FMT_STR_LEN (8) +#else +#define SECUREC_FMT_STR_LEN (16) +#endif + +typedef struct { + unsigned int flags; + int fldWidth; + int precision; + int bufferIsWide; /* flag for buffer contains wide chars */ + int dynWidth; /* %* 1 width from variable parameter ;0 not */ + int dynPrecision; /* %.* 1 precision from variable parameter ;0 not */ +} SecFormatAttr; + +typedef union { + char *str; /* not a null terminated string */ + wchar_t *wStr; +} SecFormatBuf; + +typedef union { + char str[SECUREC_BUFFER_SIZE + 1]; +#ifdef SECUREC_FOR_WCHAR + wchar_t wStr[SECUREC_BUFFER_SIZE + 1]; +#endif +} SecBuffer; + +static int SecIndirectSprintf(char *strDest, const char *format, ...) +{ + int ret; /* If initialization causes e838 */ + va_list arglist; + + va_start(arglist, format); + SECUREC_MASK_MSVC_CRT_WARNING + ret = vsprintf(strDest, format, arglist); + SECUREC_END_MASK_MSVC_CRT_WARNING + va_end(arglist); + (void)arglist; /* to clear e438 last value assigned not used , the compiler will optimize this code */ + + return ret; +} + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +/* to clear e506 warning */ +static int SecIsSameSize(size_t sizeA, size_t sizeB) +{ + return sizeA == sizeB; +} +#endif + +#define SECUREC_SPECIAL(_val, Base) \ + case Base: \ + do { \ + *--formatBuf.str = digits[_val % Base]; \ + }while ((_val /= Base) != 0) + +#define SECUREC_SAFE_WRITE_PREFIX(src, txtLen, _stream, outChars) do { \ + for (ii = 0; ii < txtLen; ++ii) { \ + *((SecChar *)(void *)(_stream->cur)) = *(src); \ + _stream->cur += sizeof(SecChar); \ + ++(src); \ + } \ + _stream->count -= txtLen * (int)(sizeof(SecChar)); \ + *(outChars) = *(outChars) + (txtLen); \ + } SECUREC_WHILE_ZERO + +#define SECUREC_SAFE_WRITE_STR(src, txtLen, _stream, outChars) do { \ + if (txtLen < 12 /* for mobile number length */) { \ + for (ii = 0; ii < txtLen; ++ii) { \ + *((SecChar *)(void *)(_stream->cur)) = *(src); \ + _stream->cur += sizeof(SecChar); \ + ++(src); \ + } \ + } else { \ + (void)memcpy(_stream->cur, src, ((size_t)(unsigned int)txtLen * (sizeof(SecChar)))); \ + _stream->cur += (size_t)(unsigned int)txtLen * (sizeof(SecChar)); \ + } \ + _stream->count -= txtLen * (int)(sizeof(SecChar)); \ + *(outChars) = *(outChars) + (txtLen); \ + } SECUREC_WHILE_ZERO + +#define SECUREC_SAFE_WRITE_CHAR(_ch, _stream, outChars) do { \ + *((SecChar *)(void *)(_stream->cur)) = (SecChar)_ch; \ + _stream->cur += sizeof(SecChar); \ + _stream->count -= (int)(sizeof(SecChar)); \ + *(outChars) = *(outChars) + 1; \ + } SECUREC_WHILE_ZERO + +#define SECUREC_SAFE_PADDING(padChar, padLen, _stream, outChars) do { \ + for (ii = 0; ii < padLen; ++ii) { \ + *((SecChar *)(void *)(_stream->cur)) = (SecChar)padChar; \ + _stream->cur += sizeof(SecChar); \ + } \ + _stream->count -= padLen * (int)(sizeof(SecChar)); \ + *(outChars) = *(outChars) + (padLen); \ + } SECUREC_WHILE_ZERO + +/* The count variable can be reduced to 0, and the external function complements the \0 terminator. */ +#define SECUREC_IS_REST_BUF_ENOUGH(needLen) ((int)(stream->count - (int)needLen * (int)(sizeof(SecChar))) >= 0) + +#define SECUREC_FMT_STATE_OFFSET 256 +#ifdef SECUREC_FOR_WCHAR +#define SECUREC_FMT_TYPE(c, fmtTable) ((((unsigned int)(int)(c)) <= (unsigned int)(int)SECUREC_CHAR('~')) ? \ + (fmtTable[(unsigned char)(c)]) : 0) +#define SECUREC_DECODE_STATE(c, fmtTable, laststate) (SecFmtState)(((fmtTable[(SECUREC_FMT_TYPE(c,fmtTable)) * \ + ((unsigned char)STAT_INVALID + 1) + \ + (unsigned char)(laststate) + \ + SECUREC_FMT_STATE_OFFSET]))) +#else +#define SECUREC_DECODE_STATE(c,fmtTable,laststate) (SecFmtState)((fmtTable[(fmtTable[(unsigned char)(c)]) * \ + ((unsigned char)STAT_INVALID + 1) + \ + (unsigned char)(laststate) + \ + SECUREC_FMT_STATE_OFFSET])) +#endif + +#define PUBLIC_FLAG_LEN 8 +#define PRIVATE_FLAG_LEN 9 +#define PUBLIC_FLAG "{public}" +#define PRIVATE_FLAG "{private}" + +static void SecWritePrivateStr(SecPrintfStream *stream, int *pCharsOut) +{ + int ii = 0; +#define PRIVATE_STR_LEN (9) +#ifndef SECUREC_FOR_WCHAR + static const char privacyString[] = ""; + const char *pPrivStr = privacyString; + + if (SECUREC_IS_REST_BUF_ENOUGH(PRIVATE_STR_LEN)) { + SECUREC_SAFE_WRITE_STR(pPrivStr, PRIVATE_STR_LEN, stream, pCharsOut); + } else { + SECUREC_WRITE_STRING(pPrivStr, PRIVATE_STR_LEN, stream, pCharsOut); + } +#else + static const wchar_t wprivacyString[] = { L'<', L'p', L'r', L'i', L'v', L'a', L't', L'e', L'>', L'\0' }; + const wchar_t *pwPrivStr = wprivacyString; + + if (SECUREC_IS_REST_BUF_ENOUGH(PRIVATE_STR_LEN)) { + SECUREC_SAFE_WRITE_STR(pwPrivStr, PRIVATE_STR_LEN, stream, pCharsOut); + } else { + SECUREC_WRITE_STRING(pwPrivStr, PRIVATE_STR_LEN, stream, pCharsOut); + } +#endif +} + +static void SecDecodeFlags(SecChar ch, SecFormatAttr *attr) +{ + switch (ch) { + case SECUREC_CHAR(' '): + attr->flags |= SECUREC_FLAG_SIGN_SPACE; + break; + case SECUREC_CHAR('+'): + attr->flags |= SECUREC_FLAG_SIGN; + break; + case SECUREC_CHAR('-'): + attr->flags |= SECUREC_FLAG_LEFT; + break; + case SECUREC_CHAR('0'): + attr->flags |= SECUREC_FLAG_LEADZERO; /* add zero th the front */ + break; + case SECUREC_CHAR('#'): + attr->flags |= SECUREC_FLAG_ALTERNATE; /* output %x with 0x */ + break; + default: + break; + } + return; +} + +static int SecDecodeSize(SecChar ch, SecFormatAttr *attr, const SecChar **format) +{ + switch (ch) { +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + case SECUREC_CHAR('j'): + attr->flags |= SECUREC_FLAG_INTMAX; + break; +#endif + case SECUREC_CHAR('q'): [[fallthrough]]; + case SECUREC_CHAR('L'): + attr->flags |= SECUREC_FLAG_LONGLONG | SECUREC_FLAG_LONG_DOUBLE; + break; + case SECUREC_CHAR('l'): + if (**format == SECUREC_CHAR('l')) { + ++(*format); + attr->flags |= SECUREC_FLAG_LONGLONG; /* long long */ + } else { + attr->flags |= SECUREC_FLAG_LONG; /* long int or wchar_t */ + } + break; + case SECUREC_CHAR('t'): + attr->flags |= SECUREC_FLAG_PTRDIFF; + break; +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + case SECUREC_CHAR('z'): + attr->flags |= SECUREC_FLAG_SIZE; + break; + case SECUREC_CHAR('Z'): + attr->flags |= SECUREC_FLAG_SIZE; + break; +#endif + + case SECUREC_CHAR('I'): +#ifdef SECUREC_ON_64BITS + attr->flags |= SECUREC_FLAG_I64; /* %I to INT64 */ +#endif + if ((**format == SECUREC_CHAR('6')) && (*((*format) + 1) == SECUREC_CHAR('4'))) { + (*format) += 2; + attr->flags |= SECUREC_FLAG_I64; /* %I64 to INT64 */ + } else if ((**format == SECUREC_CHAR('3')) && (*((*format) + 1) == SECUREC_CHAR('2'))) { + (*format) += 2; + attr->flags &= ~SECUREC_FLAG_I64; /* %I64 to INT32 */ + } else if ((**format == SECUREC_CHAR('d')) || (**format == SECUREC_CHAR('i')) || + (**format == SECUREC_CHAR('o')) || (**format == SECUREC_CHAR('u')) || + (**format == SECUREC_CHAR('x')) || (**format == SECUREC_CHAR('X'))) { + /* do nothing */ + } else { + /* Compatibility code for "%I" just print I */ + return -1; + } + break; + + case SECUREC_CHAR('h'): + if (**format == SECUREC_CHAR('h')) + attr->flags |= SECUREC_FLAG_CHAR; /* char */ + else + attr->flags |= SECUREC_FLAG_SHORT; /* short int */ + break; + + case SECUREC_CHAR('w'): + attr->flags |= SECUREC_FLAG_WIDECHAR; /* wide char */ + break; + default: + break; + + } + + return 0; +} + +static int SecDecodeTypeC(SecFormatAttr *attr, unsigned int cValue, SecFormatBuf *formatBuf, SecBuffer *buffer) +{ + int textLen; + wchar_t wchar; + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && !(defined(__hpux)) && !(defined(SECUREC_ON_SOLARIS)) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + +#ifdef SECUREC_FOR_WCHAR + attr->bufferIsWide = 1; + wchar = (wchar_t)cValue; + if (attr->flags & SECUREC_FLAG_SHORT) { + /* multibyte character to wide character */ + char tempchar[2]; + tempchar[0] = (char)(wchar & 0x00ff); + tempchar[1] = '\0'; + + if (mbtowc(buffer->wStr, tempchar, sizeof(tempchar)) < 0) { + return -1; + } + } else { + buffer->wStr[0] = wchar; + } + formatBuf->wStr = buffer->wStr; + textLen = 1; /* only 1 wide character */ +#else + attr->bufferIsWide = 0; + if (attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) { + wchar = (wchar_t)cValue; + /* wide character to multibyte character */ + SECUREC_MASK_MSVC_CRT_WARNING + textLen = wctomb(buffer->str, wchar); + SECUREC_END_MASK_MSVC_CRT_WARNING + if (textLen < 0) { + return -1; + } + } else { + /* get multibyte character from argument */ + unsigned short temp; + temp = (unsigned short)cValue; + buffer->str[0] = (char)temp; + textLen = 1; + } + formatBuf->str = buffer->str; +#endif + + return textLen; +} + +static int SecDecodeTypeS(SecFormatAttr *attr, char *argPtr, SecFormatBuf *formatBuf) +{ + /* literal string to print null ptr, define it on stack rather than const text area + is to avoid gcc warning with pointing const text with variable */ + static char strNullString[8] = "(null)"; + static wchar_t wStrNullString[8] = { L'(', L'n', L'u', L'l', L'l', L')', L'\0', L'\0' }; + + int finalPrecision; + char *strEnd = NULL; + wchar_t *wStrEnd = NULL; + int textLen; + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && (!defined(SECUREC_ON_UNIX)) + attr->flags &= ~SECUREC_FLAG_LEADZERO; +#endif + finalPrecision = (attr->precision == -1) ? SECUREC_INT_MAX : attr->precision; + formatBuf->str = argPtr; + +#ifdef SECUREC_FOR_WCHAR +#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) + if (!(attr->flags & SECUREC_FLAG_LONG)) { + attr->flags |= SECUREC_FLAG_SHORT; + } +#endif + if (attr->flags & SECUREC_FLAG_SHORT) { + if (formatBuf->str == NULL) { /* NULL passed, use special string */ + formatBuf->str = strNullString; + } + strEnd = formatBuf->str; + for (textLen = 0; textLen < finalPrecision && *strEnd; textLen++) { + ++strEnd; + } + /* textLen now contains length in multibyte chars */ + } else { + if (formatBuf->wStr == NULL) { /* NULL passed, use special string */ + formatBuf->wStr = wStrNullString; + } + attr->bufferIsWide = 1; + wStrEnd = formatBuf->wStr; + while (finalPrecision-- && *wStrEnd) { + ++wStrEnd; + } + textLen = (int)(wStrEnd - formatBuf->wStr); /* in wchar_ts */ + /* textLen now contains length in wide chars */ + } +#else /* SECUREC_FOR_WCHAR */ + if (attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) { + if (formatBuf->wStr == NULL) { /* NULL passed, use special string */ + formatBuf->wStr = wStrNullString; + } + attr->bufferIsWide = 1; + wStrEnd = formatBuf->wStr; + while (finalPrecision-- && *wStrEnd) { + ++wStrEnd; + } + textLen = (int)(wStrEnd - formatBuf->wStr); + } else { + if (formatBuf->str == NULL) { /* meet NULL, use special string */ + formatBuf->str = strNullString; + } + + if (finalPrecision == SECUREC_INT_MAX) { + /* precision NOT assigned */ + /* The strlen performance is high when the string length is greater than 32 */ + textLen = (int)strlen(formatBuf->str); + } else { + /* precision assigned */ + strEnd = formatBuf->str; + while (finalPrecision-- && *strEnd) { + ++strEnd; + } + textLen = (int)(strEnd - formatBuf->str); /* length of the string */ + } + + } + +#endif /* SECUREC_FOR_WCHAR */ + return textLen; +} + +HILOG_LOCAL_API +int SecOutputPS(SecPrintfStream *stream, int priv, const char *cformat, va_list arglist) +{ + const SecChar *format = cformat; + + char *floatBuf = NULL; + SecFormatBuf formatBuf; + static const char *itoaUpperDigits = "0123456789ABCDEFX"; + static const char *itoaLowerDigits = "0123456789abcdefx"; + const char *digits = itoaUpperDigits; + int ii = 0; + + unsigned int radix; + int charsOut; /* characters written */ + + int prefixLen = 0; + int padding = 0; + + int textLen; /* length of the text */ + int bufferSize = 0; /* size of formatBuf.str */ + int noOutput = 0; + + SecFmtState state; + SecFmtState laststate; + + SecChar prefix[2] = { 0 }; + SecChar ch; /* currently read character */ + + static const unsigned char fmtCharTable[337] = { + /* type 0: nospecial meaning; + 1: '%'; + 2: '.' + 3: '*' + 4: '0' + 5: '1' ... '9' + 6: ' ', '+', '-', '#' + 7: 'h', 'l', 'L', 'F', 'w' , 'N','z','q','t','j' + 8: 'd','o','u','i','x','X','e','f','g' + */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x00, + 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x07, 0x00, 0x07, 0x00, 0x00, 0x08, + 0x08, 0x07, 0x00, 0x08, 0x07, 0x08, 0x00, 0x07, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + /* fill zero for normal char 128 byte for 0x80 - 0xff */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* state 0: normal + 1: percent + 2: flag + 3: width + 4: dot + 5: precis + 6: size + 7: type + 8: invalid + */ + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x01, 0x00, 0x00, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, 0x08, 0x05, + 0x08, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, + 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, + 0x00 + }; + + SecFormatAttr formatAttr; + SecBuffer buffer; + formatAttr.flags = 0; + formatAttr.bufferIsWide = 0; /* flag for buffer contains wide chars */ + formatAttr.fldWidth = 0; + formatAttr.precision = 0; + formatAttr.dynWidth = 0; + formatAttr.dynPrecision = 0; + + charsOut = 0; + textLen = 0; + state = STAT_NORMAL; /* starting state */ + formatBuf.str = NULL; + + int isPrivacy = 1; /*whether show private string*/ + + /* loop each format character */ + /* remove format != NULL */ + while ((ch = *format++) != SECUREC_CHAR('\0') && charsOut >= 0) { + laststate = state; + state = SECUREC_DECODE_STATE(ch, fmtCharTable, laststate); + + switch (state) { + case STAT_NORMAL: + +NORMAL_CHAR: + + /* normal state, write character */ + if (SECUREC_IS_REST_BUF_ENOUGH(1 /* only one char */ )) { + SECUREC_SAFE_WRITE_CHAR(ch, stream, &charsOut); /* char * cast to wchar * */ + } else { +#ifdef SECUREC_FOR_WCHAR + SECUREC_WRITE_CHAR(ch, stream, &charsOut); +#else + /* optimize function call to code */ + charsOut = -1; + stream->count = -1; +#endif + } + + continue; + + case STAT_PERCENT: + /* set default values */ + prefixLen = 0; + noOutput = 0; + formatAttr.flags = 0; + formatAttr.fldWidth = 0; + formatAttr.precision = -1; + formatAttr.bufferIsWide = 0; + if (*format == SECUREC_CHAR('{')) { + if (strncmp(format, PUBLIC_FLAG, PUBLIC_FLAG_LEN) == 0) { + isPrivacy = 0; + format += PUBLIC_FLAG_LEN; + } + else if (strncmp(format, PRIVATE_FLAG, PRIVATE_FLAG_LEN) == 0) { + isPrivacy = 1; + format += PRIVATE_FLAG_LEN; + } + } + else { + isPrivacy = 1; + } + + if (0 == priv) { + isPrivacy = 0; + } + + break; + + case STAT_FLAG: + /* set flag based on which flag character */ + SecDecodeFlags(ch, &formatAttr); + break; + + case STAT_WIDTH: + /* update width value */ + if (ch == SECUREC_CHAR('*')) { + /* get width */ + formatAttr.fldWidth = (int)va_arg(arglist, int); + if (formatAttr.fldWidth < 0) { + formatAttr.flags |= SECUREC_FLAG_LEFT; + formatAttr.fldWidth = -formatAttr.fldWidth; + } + formatAttr.dynWidth = 1; + } else { + if (laststate != STAT_WIDTH) { + formatAttr.fldWidth = 0; + } + if (SECUREC_MUL10_ADD_BEYOND_MAX(formatAttr.fldWidth)) { + return -1; + } + formatAttr.fldWidth = (int)SECUREC_MUL10((unsigned int)formatAttr.fldWidth) + (ch - SECUREC_CHAR('0')); + formatAttr.dynWidth = 0; + } + break; + + case STAT_DOT: + formatAttr.precision = 0; + break; + + case STAT_PRECIS: + /* update precision value */ + if (ch == SECUREC_CHAR('*')) { + /* get precision from arg list */ + formatAttr.precision = (int)va_arg(arglist, int); + if (formatAttr.precision < 0) { + formatAttr.precision = -1; + } + formatAttr.dynPrecision = 1; + } else { + /* add digit to current precision */ + if (SECUREC_MUL10_ADD_BEYOND_MAX(formatAttr.precision)) { + return -1; + } + formatAttr.precision = + (int)SECUREC_MUL10((unsigned int)formatAttr.precision) + (ch - SECUREC_CHAR('0')); + formatAttr.dynPrecision = 0; + } + break; + + case STAT_SIZE: + /* read a size specifier, set the formatAttr.flags based on it */ + if (SecDecodeSize(ch, &formatAttr, &format) != 0) { + /* Compatibility code for "%I" just print I */ + state = STAT_NORMAL; + goto NORMAL_CHAR; + } + break; + + case STAT_TYPE: + + switch (ch) { + + case SECUREC_CHAR('C'): + /* wide char */ + if (!(formatAttr.flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR))) { + +#ifdef SECUREC_FOR_WCHAR + formatAttr.flags |= SECUREC_FLAG_SHORT; +#else + formatAttr.flags |= SECUREC_FLAG_WIDECHAR; +#endif + } + [[fallthrough]]; + case SECUREC_CHAR('c'): + { + unsigned int cValue = (unsigned int)va_arg(arglist, int); + /*if it's a private arg, just write to stream*/ + if (isPrivacy == 1) { + break; + } + textLen = SecDecodeTypeC(&formatAttr, cValue, &formatBuf, &buffer); + if (textLen < 0) { + noOutput = 1; + } + } + break; + case SECUREC_CHAR('S'): /* wide char string */ +#ifndef SECUREC_FOR_WCHAR + if (!(formatAttr.flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR))) { + formatAttr.flags |= SECUREC_FLAG_WIDECHAR; + } +#else + if (!(formatAttr.flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR))) { + formatAttr.flags |= SECUREC_FLAG_SHORT; + } +#endif + [[fallthrough]]; + case SECUREC_CHAR('s'): + { + char *argPtr = (char *)va_arg(arglist, char *); + /*if it's a private arg, just write to stream*/ + if (isPrivacy == 1) { + break; + } + textLen = SecDecodeTypeS(&formatAttr, argPtr, &formatBuf); + } + break; + + case SECUREC_CHAR('n'): + /* higher risk disable it */ + return -1; + + case SECUREC_CHAR('E'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('G'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('A'): /* fall-through */ /* FALLTHRU */ + /* convert format char to lower , use Explicit conversion to clean up compilation warning */ + ch = (SecChar)(ch + ((SecChar)(SECUREC_CHAR('a')) - (SECUREC_CHAR('A')))); + [[fallthrough]]; + case SECUREC_CHAR('e'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('f'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('g'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('a'): + { + /*if it's a private arg, just write to stream*/ + if (isPrivacy == 1) { +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + if (formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) { + (void)va_arg(arglist, long double); + } else +#endif + { + (void)va_arg(arglist, double); + } + break; + } + + /* floating point conversion */ + formatBuf.str = buffer.str; /* output buffer for float string with default size */ + + /* compute the precision value */ + if (formatAttr.precision < 0) { + formatAttr.precision = 6; + } else if (formatAttr.precision == 0 && ch == SECUREC_CHAR('g')) { + formatAttr.precision = 1; + } + + /* calc buffer size to store long double value */ + if (formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) { + if (formatAttr.precision > (SECUREC_INT_MAX - SECUREC_FLOAT_BUFSIZE_LB)) { + noOutput = 1; + break; + } + bufferSize = SECUREC_FLOAT_BUFSIZE_LB + formatAttr.precision; + } else { + if (formatAttr.precision > (SECUREC_INT_MAX - SECUREC_FLOAT_BUFSIZE)) { + noOutput = 1; + break; + } + bufferSize = SECUREC_FLOAT_BUFSIZE + formatAttr.precision; + } + if (formatAttr.fldWidth > bufferSize) { + bufferSize = formatAttr.fldWidth; + } + + if (bufferSize >= SECUREC_BUFFER_SIZE) { + /* the current value of SECUREC_BUFFER_SIZE could NOT store the formatted float string */ + /* size include '+' and '\0' */ + floatBuf = (char *)SECUREC_MALLOC(((size_t)(unsigned int)bufferSize + (size_t)2)); + if (floatBuf != NULL) { + formatBuf.str = floatBuf; + } else { + noOutput = 1; + break; + } + } + + { + /* add following code to call system sprintf API for float number */ + const SecChar *pFltFmt = format - 2; /* point to the position before 'f' or 'g' */ + int k; + int fltFmtStrLen; + char fltFmtBuf[SECUREC_FMT_STR_LEN]; + char *fltFmtStr = fltFmtBuf; + char *fltFmtHeap = NULL; /* to clear warning */ + + /* must meet '%' (normal format) or '}'(with{private} or{public} format)*/ + while (SECUREC_CHAR('%') != *pFltFmt && SECUREC_CHAR('}') != *pFltFmt) { + --pFltFmt; + } + fltFmtStrLen = (int)((format - pFltFmt) + 1); /* with ending terminator */ + if (fltFmtStrLen > SECUREC_FMT_STR_LEN) { + /* if SECUREC_FMT_STR_LEN is NOT enough, alloc a new buffer */ + fltFmtHeap = (char *)SECUREC_MALLOC((size_t)((unsigned int)fltFmtStrLen)); + if (fltFmtHeap == NULL) { + noOutput = 1; + break; + } else { + fltFmtHeap[0] = '%'; + for (k = 1; k < fltFmtStrLen - 1; ++k) { + /* convert wchar to char */ + fltFmtHeap[k] = (char)(pFltFmt[k]); /* copy the format string */ + } + fltFmtHeap[k] = '\0'; + + fltFmtStr = fltFmtHeap; + } + } else { + /* purpose of the repeat code is to solve the tool alarm Redundant_Null_Check */ + fltFmtBuf[0] = '%'; + for (k = 1; k < fltFmtStrLen - 1; ++k) { + /* convert wchar to char */ + fltFmtBuf[k] = (char)(pFltFmt[k]); /* copy the format string */ + } + fltFmtBuf[k] = '\0'; + } + +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + if (formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) { + long double tmp = (long double)va_arg(arglist, long double); + /* call system sprintf to format float value */ + if (formatAttr.dynWidth && formatAttr.dynPrecision) { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, + formatAttr.fldWidth,formatAttr.precision, tmp); + } else if (formatAttr.dynWidth) { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, + formatAttr.fldWidth, tmp); + } else if (formatAttr.dynPrecision) { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, + formatAttr.precision, tmp); + } else { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, tmp); + } + } else +#endif + { + double tmp = (double)va_arg(arglist, double); + if (formatAttr.dynWidth && formatAttr.dynPrecision) { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, formatAttr.fldWidth, + formatAttr.precision, tmp); + } else if (formatAttr.dynWidth) { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, formatAttr.fldWidth, + tmp); + } else if (formatAttr.dynPrecision) { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, formatAttr.precision, + tmp); + } else { + textLen = SecIndirectSprintf(formatBuf.str, (char *)fltFmtStr, tmp); + } + } + + if (fltFmtHeap != NULL) { + /* if buffer is allocated on heap, free it */ + SECUREC_FREE(fltFmtHeap); + fltFmtHeap = NULL; + /* to clear e438 last value assigned not used , the compiler will optimize this code */ + (void)fltFmtHeap; + } + if (textLen < 0) { + /* bufferSize is large enough,just validation the return value */ + noOutput = 1; + break; + } + + formatAttr.fldWidth = textLen; /* no padding ,this variable to calculate amount of padding */ + prefixLen = 0; /* no padding ,this variable to calculate amount of padding */ + formatAttr.flags = 0; /* clear all internal formatAttr.flags */ + break; + } + } + + case SECUREC_CHAR('p'): + /* print a pointer */ +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + formatAttr.flags &= ~SECUREC_FLAG_LEADZERO; +#else + formatAttr.flags |= SECUREC_FLAG_POINTER; +#endif + +#ifdef SECUREC_ON_64BITS + formatAttr.flags |= SECUREC_FLAG_I64; /* converting an int64 */ +#else + formatAttr.flags |= SECUREC_FLAG_LONG; /* converting a long */ +#endif + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) && (!defined(SECUREC_ON_UNIX)) + +#if defined(SECUREC_VXWORKS_PLATFORM) + formatAttr.precision = 1; +#else + formatAttr.precision = 0; +#endif + formatAttr.flags |= SECUREC_FLAG_ALTERNATE; /* "0x" is not default prefix in UNIX */ + digits = itoaLowerDigits; + goto OUTPUT_HEX; +#else +/* not linux vxwoks */ +#if defined(_AIX) || defined(SECUREC_ON_SOLARIS) + formatAttr.precision = 1; +#else + formatAttr.precision = 2 * sizeof(void *); +#endif + +#endif + +#if defined(SECUREC_ON_UNIX) + digits = itoaLowerDigits; + goto OUTPUT_HEX; +#endif + + [[fallthrough]]; + case SECUREC_CHAR('X'): + /* unsigned upper hex output */ + digits = itoaUpperDigits; + goto OUTPUT_HEX; + case SECUREC_CHAR('x'): + /* unsigned lower hex output */ + digits = itoaLowerDigits; + +OUTPUT_HEX: + radix = 16; + if (formatAttr.flags & SECUREC_FLAG_ALTERNATE) { + /* alternate form means '0x' prefix */ + prefix[0] = SECUREC_CHAR('0'); + prefix[1] = (SecChar)(digits[16]); /* 'x' or 'X' */ + +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) + if (ch == 'p') { + prefix[1] = SECUREC_CHAR('x'); + } +#endif +#if defined(_AIX) || defined(SECUREC_ON_SOLARIS) + if (ch == 'p') { + prefixLen = 0; + } else { + prefixLen = 2; + } +#else + prefixLen = 2; +#endif + + } + goto OUTPUT_INT; + case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */ + case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */ + /* signed decimal output */ + formatAttr.flags |= SECUREC_FLAG_SIGNED; + [[fallthrough]]; + case SECUREC_CHAR('u'): + radix = 10; + goto OUTPUT_INT; + case SECUREC_CHAR('o'): + /* unsigned octal output */ + radix = 8; + if (formatAttr.flags & SECUREC_FLAG_ALTERNATE) { + /* alternate form means force a leading 0 */ + formatAttr.flags |= SECUREC_FLAG_FORCE_OCTAL; + } +OUTPUT_INT: + { + + SecUnsignedInt64 number = 0; /* number to convert */ + SecInt64 l; /* temp long value */ + unsigned char tch; +#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS) + SecUnsignedInt32 digit = 0; /* ascii value of digit */ + SecUnsignedInt32 quotientHigh = 0; + SecUnsignedInt32 quotientLow = 0; +#endif + + /* read argument into variable l */ + if (formatAttr.flags & SECUREC_FLAG_I64) { + l = (SecInt64)va_arg(arglist, SecInt64); + } else if (formatAttr.flags & SECUREC_FLAG_LONGLONG) { + l = (SecInt64)va_arg(arglist, SecInt64); + } else +#ifdef SECUREC_ON_64BITS + if (formatAttr.flags & SECUREC_FLAG_LONG) { + l = (long)va_arg(arglist, long); + } else +#endif /* SECUREC_ON_64BITS */ + if (formatAttr.flags & SECUREC_FLAG_CHAR) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + l = (char)va_arg(arglist, int); /* sign extend */ + if (l >= 128) { /* on some platform, char is always unsigned */ + SecUnsignedInt64 tmpL = (SecUnsignedInt64)l; + formatAttr.flags |= SECUREC_FLAG_NEGATIVE; + tch = (unsigned char)(~(tmpL)); + l = tch + 1; + } + } else { + l = (unsigned char)va_arg(arglist, int); /* zero-extend */ + } + + } else if (formatAttr.flags & SECUREC_FLAG_SHORT) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + l = (short)va_arg(arglist, int); /* sign extend */ + } else { + l = (unsigned short)va_arg(arglist, int); /* zero-extend */ + } + + } +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + else if (formatAttr.flags & SECUREC_FLAG_PTRDIFF) { + l = (ptrdiff_t)va_arg(arglist, ptrdiff_t); /* sign extend */ + } else if (formatAttr.flags & SECUREC_FLAG_SIZE) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + /* No suitable macros were found to handle the branch */ + if (SecIsSameSize(sizeof(size_t), sizeof(long))) { + l = va_arg(arglist, long); /* sign extend */ + } else if (SecIsSameSize(sizeof(size_t), sizeof(long long))) { + l = va_arg(arglist, long long); /* sign extend */ + } else { + l = va_arg(arglist, int); /* sign extend */ + } + } else { + l = (SecInt64)(size_t)va_arg(arglist, size_t); /* sign extend */ + } + } else if (formatAttr.flags & SECUREC_FLAG_INTMAX) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + l = va_arg(arglist, SecInt64); /* sign extend */ + } else { + l = (SecInt64)(SecUnsignedInt64)va_arg(arglist, SecUnsignedInt64); /* sign extend */ + } + } +#endif + else { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + l = va_arg(arglist, int); /* sign extend */ + } else { + l = (unsigned int)va_arg(arglist, int); /* zero-extend */ + } + + } + /*if it's a private arg, just write to stream*/ + if (isPrivacy == 1) { + break; + } + + /* check for negative; copy into number */ + if ((formatAttr.flags & SECUREC_FLAG_SIGNED) && l < 0) { + number = (SecUnsignedInt64)(-l); + formatAttr.flags |= SECUREC_FLAG_NEGATIVE; + } else { + number = (SecUnsignedInt64)l; + } + + if (((formatAttr.flags & SECUREC_FLAG_I64) == 0) && +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT + ((formatAttr.flags & SECUREC_FLAG_INTMAX) == 0) && +#endif +#ifdef SECUREC_ON_64BITS + ((formatAttr.flags & SECUREC_FLAG_PTRDIFF) == 0) && + ((formatAttr.flags & SECUREC_FLAG_SIZE) == 0) && +#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT) /* on window 64 system sizeof long is 32bit */ + ((formatAttr.flags & SECUREC_FLAG_LONG) == 0) && +#endif +#endif + ((formatAttr.flags & SECUREC_FLAG_LONGLONG) == 0)) { + + number &= 0xffffffff; + } + + /* check precision value for default */ + if (formatAttr.precision < 0) { + formatAttr.precision = 1; /* default precision */ + } else { +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) + formatAttr.flags &= ~SECUREC_FLAG_LEADZERO; +#else + if (!(formatAttr.flags & SECUREC_FLAG_POINTER)) { + formatAttr.flags &= ~SECUREC_FLAG_LEADZERO; + } +#endif + if (formatAttr.precision > SECUREC_MAX_PRECISION) { + formatAttr.precision = SECUREC_MAX_PRECISION; + } + } + + /* Check if data is 0; if so, turn off hex prefix,if 'p',add 0x prefix,else not add prefix */ + if (number == 0) { +#if !(defined(SECUREC_VXWORKS_PLATFORM)||defined(__hpux)) + prefixLen = 0; +#else + if ((ch == 'p') && (formatAttr.flags & SECUREC_FLAG_ALTERNATE)) + prefixLen = 2; + else + prefixLen = 0; +#endif + } + + /* Convert data to ASCII */ + formatBuf.str = &buffer.str[SECUREC_BUFFER_SIZE]; + + if (number > 0) { +#ifdef SECUREC_ON_64BITS + switch (radix) { + /* the compiler will optimize each one */ + SECUREC_SPECIAL(number, 10); + break; + SECUREC_SPECIAL(number, 16); + break; + SECUREC_SPECIAL(number, 8); + break; + default: + break; + } +#else /* for 32 bits system */ + if (number <= 0xFFFFFFFFUL) { + /* in most case, the value to be converted is small value */ + SecUnsignedInt32 n32Tmp = (SecUnsignedInt32)number; + switch (radix) { + SECUREC_SPECIAL(n32Tmp, 16); + break; + SECUREC_SPECIAL(n32Tmp, 8); + break; + +#ifdef _AIX + /* the compiler will optimize div 10 */ + SECUREC_SPECIAL(n32Tmp, 10); + break; +#else + case 10: + { + /* fast div 10 */ + SecUnsignedInt32 q; + SecUnsignedInt32 r; + do { + *--formatBuf.str = digits[n32Tmp % 10]; + q = (n32Tmp >> 1) + (n32Tmp >> 2); + q = q + (q >> 4); + q = q + (q >> 8); + q = q + (q >> 16); + q = q >> 3; + r = n32Tmp - (((q << 2) + q) << 1); + n32Tmp = (r > 9) ? (q + 1) : q; + } while (n32Tmp != 0); + } + break; +#endif + default: + break; + } /* end switch */ + } else { + /* the value to be converted is greater than 4G */ +#if defined(SECUREC_VXWORKS_VERSION_5_4) + do { + if (0 != SecU64Div32((SecUnsignedInt32)((number >> 16) >> 16), + (SecUnsignedInt32)number, + (SecUnsignedInt32)radix, "ientHigh, "ientLow, &digit)) { + noOutput = 1; + break; + } + *--formatBuf.str = digits[digit]; + + number = (SecUnsignedInt64)quotientHigh; + number = (number << 32) + quotientLow; + } while (number != 0); +#else + switch (radix) { + /* the compiler will optimize div 10 */ + SECUREC_SPECIAL(number, 10); + break; + SECUREC_SPECIAL(number, 16); + break; + SECUREC_SPECIAL(number, 8); + break; + default: + break; + } +#endif + } +#endif + } /* END if (number > 0) */ + /* compute length of number,.if textLen > 0, then formatBuf.str must be in buffer.str */ + textLen = (int)((char *)&buffer.str[SECUREC_BUFFER_SIZE] - formatBuf.str); + if (formatAttr.precision > textLen) { + for (ii = 0; ii < formatAttr.precision - textLen; ++ii) { + *--formatBuf.str = '0'; + } + textLen = formatAttr.precision; + } + + /* Force a leading zero if FORCEOCTAL flag set */ + if ((formatAttr.flags & SECUREC_FLAG_FORCE_OCTAL) && (textLen == 0 || formatBuf.str[0] != '0')) { + *--formatBuf.str = '0'; + ++textLen; /* add a zero */ + } + } + break; + default: + break; + } + /*if it's a private arg, just write to stream*/ + if (isPrivacy == 1) { + SecWritePrivateStr(stream, &charsOut); + break; + } + + if (noOutput == 0) { + if (formatAttr.flags & SECUREC_FLAG_SIGNED) { + if (formatAttr.flags & SECUREC_FLAG_NEGATIVE) { + /* prefix is a '-' */ + prefix[0] = SECUREC_CHAR('-'); + prefixLen = 1; + } else if (formatAttr.flags & SECUREC_FLAG_SIGN) { + /* prefix is '+' */ + prefix[0] = SECUREC_CHAR('+'); + prefixLen = 1; + } else if (formatAttr.flags & SECUREC_FLAG_SIGN_SPACE) { + /* prefix is ' ' */ + prefix[0] = SECUREC_CHAR(' '); + prefixLen = 1; + } + } + +#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && (!defined(SECUREC_ON_UNIX)) + if ((formatAttr.flags & SECUREC_FLAG_POINTER) && (0 == textLen)) { + formatAttr.flags &= ~SECUREC_FLAG_LEADZERO; + formatBuf.str = &buffer.str[SECUREC_BUFFER_SIZE - 1]; + *formatBuf.str-- = '\0'; + *formatBuf.str-- = ')'; + *formatBuf.str-- = 'l'; + *formatBuf.str-- = 'i'; + *formatBuf.str-- = 'n'; + *formatBuf.str = '('; + textLen = 5; + } +#endif + + /* calculate amount of padding */ + padding = (formatAttr.fldWidth - textLen) - prefixLen; + + /* put out the padding, prefix, and text, in the correct order */ + + if (!(formatAttr.flags & (SECUREC_FLAG_LEFT | SECUREC_FLAG_LEADZERO)) && padding > 0) { + /* pad on left with blanks */ + if (SECUREC_IS_REST_BUF_ENOUGH(padding)) { + /* char * cast to wchar * */ + SECUREC_SAFE_PADDING(SECUREC_CHAR(' '), padding, stream, &charsOut); + } else { + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), padding, stream, &charsOut); + } + } + + /* write prefix */ + if (prefixLen > 0) { + SecChar *pPrefix = prefix; + if (SECUREC_IS_REST_BUF_ENOUGH(prefixLen)) { + /* max prefix len is 2, use loop copy */ /* char * cast to wchar * */ + SECUREC_SAFE_WRITE_PREFIX(pPrefix, prefixLen, stream, &charsOut); + } else { + SECUREC_WRITE_STRING(prefix, prefixLen, stream, &charsOut); + } + } + + if ((formatAttr.flags & SECUREC_FLAG_LEADZERO) && !(formatAttr.flags & SECUREC_FLAG_LEFT) + && padding > 0) { + /* write leading zeros */ + if (SECUREC_IS_REST_BUF_ENOUGH(padding)) { + /* char * cast to wchar * */ + SECUREC_SAFE_PADDING(SECUREC_CHAR('0'), padding, stream, &charsOut); + } else { + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR('0'), padding, stream, &charsOut); + } + } + + /* write text */ +#ifndef SECUREC_FOR_WCHAR + if (formatAttr.bufferIsWide && (textLen > 0)) { + wchar_t *p = formatBuf.wStr; + int count = textLen; + while (count--) { + char tmpBuf[SECUREC_MB_LEN + 1]; + SECUREC_MASK_MSVC_CRT_WARNING + int retVal = wctomb(tmpBuf, *p++); + SECUREC_END_MASK_MSVC_CRT_WARNING + if (retVal <= 0) { + charsOut = -1; + break; + } + SECUREC_WRITE_STRING(tmpBuf, retVal, stream, &charsOut); + } + } else { + if (SECUREC_IS_REST_BUF_ENOUGH(textLen)) { + SECUREC_SAFE_WRITE_STR(formatBuf.str, textLen, stream, &charsOut); + } else { + SECUREC_WRITE_STRING(formatBuf.str, textLen, stream, &charsOut); + } + } +#else /* SECUREC_FOR_WCHAR */ + if (formatAttr.bufferIsWide == 0 && textLen > 0) { + int count = textLen; + char *p = formatBuf.str; + + while (count > 0) { + wchar_t wchar = L'\0'; + int retVal = mbtowc(&wchar, p, (size_t)MB_CUR_MAX); + if (retVal <= 0) { + charsOut = -1; + break; + } + SECUREC_WRITE_CHAR(wchar, stream, &charsOut); + p += retVal; + count -= retVal; + } + } else { + if (SECUREC_IS_REST_BUF_ENOUGH(textLen)) { + SECUREC_SAFE_WRITE_STR(formatBuf.wStr, textLen, stream, &charsOut); /* char * cast to wchar * */ + } else { + SECUREC_WRITE_STRING(formatBuf.wStr, textLen, stream, &charsOut); + } + } +#endif /* SECUREC_FOR_WCHAR */ + + if (charsOut >= 0 && (formatAttr.flags & SECUREC_FLAG_LEFT) && padding > 0) { + /* pad on right with blanks */ + if (SECUREC_IS_REST_BUF_ENOUGH(padding)) { + /* char * cast to wchar * */ + SECUREC_SAFE_PADDING(SECUREC_CHAR(' '), padding, stream, &charsOut); + } else { + SECUREC_WRITE_MULTI_CHAR(SECUREC_CHAR(' '), padding, stream, &charsOut); + } + } + + /* we're done! */ + } + if (floatBuf != NULL) { + SECUREC_FREE(floatBuf); + floatBuf = NULL; + } + break; + case STAT_INVALID: + return -1; + default: + return -1; /* input format is wrong, directly return */ + } + } + + if (state != STAT_NORMAL && state != STAT_TYPE) { + return -1; + } + + return charsOut; /* the number of characters written */ +} /* arglist must not be declare as const */ +#endif /* OUTPUT_P_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 */ diff --git a/hilog.gni b/hilog.gni index 116b058..bdd9393 100644 --- a/hilog.gni +++ b/hilog.gni @@ -12,9 +12,9 @@ # limitations under the License. platforms = [ - "ohos", - "windows", - "mac", + # "ohos", + # "windows", + # "mac", "linux", ] diff --git a/interfaces/bundle.json b/interfaces/bundle.json index f6b5cdf..330ffcb 100644 --- a/interfaces/bundle.json +++ b/interfaces/bundle.json @@ -39,10 +39,7 @@ "base_group": [ ], - "fwk_group": [ - "//base/hiviewdfx/hilog/frameworks/hilog_ndk:hilog_ndk", - "//base/hiviewdfx/hilog/interfaces/js:hilog_napi" - ], + "fwk_group": [], "service_group": [ "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_base", "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog" diff --git a/interfaces/native/innerkits/BUILD.gn b/interfaces/native/innerkits/BUILD.gn index 3666081..ee27551 100644 --- a/interfaces/native/innerkits/BUILD.gn +++ b/interfaces/native/innerkits/BUILD.gn @@ -19,40 +19,33 @@ config("libhilog_pub_config") { include_dirs = [ "include" ] } -template("libhilog") { - forward_variables_from(invoker, "*") - ohos_shared_library(target_name) { +ohos_shared_library("libhilog") { public_configs = [ ":libhilog_pub_config" ] - - deps = [ - "//base/hiviewdfx/hilog/frameworks/libhilog:libhilog_source_$platform", + sources = [ + "//base/hiviewdfx/hilog/libhilog/hilog.cpp", + "//base/hiviewdfx/hilog/libhilog/vsnprintf/vsnprintf_s_p.cpp", + "//base/hiviewdfx/hilog/libhilog/utils/log_utils.cpp", + "//base/hiviewdfx/hilog/libhilog/utils/log_print.cpp", ] - if (platform == "ohos") { - output_extension = "so" - } + include_dirs = [ + "//base/hiviewdfx/hilog/libhilog/include/", + "//base/hiviewdfx/hilog/libhilog/vsnprintf/include/", + "//base/hiviewdfx/hilog/libhilog/utils/include/", + ] + defines = [] + cflags_cc = [ "-std=c++17", "-fpermissive" ] + defines += [ "__LINUX__" ] + deps = [ + "//third_party/bounds_checking_function:libsec_shared" + ] install_enable = !hilog_native_feature_ohcore install_images = [ "system", - "updater", ] part_name = "hilog_native" subsystem_name = "hiviewdfx" - } -} - -foreach(item, platforms) { - if (item == "ohos") { - libhilog("libhilog") { - platform = item - } - } - if (item == "windows" || item == "mac" || item == "linux") { - libhilog("libhilog_" + item) { - platform = item - } - } } config("libhilog_base_pub_cfg") { diff --git a/interfaces/native/innerkits/include/hilog/log_c.h b/interfaces/native/innerkits/include/hilog/log_c.h index 2649f33..08aa937 100644 --- a/interfaces/native/innerkits/include/hilog/log_c.h +++ b/interfaces/native/innerkits/include/hilog/log_c.h @@ -57,8 +57,8 @@ typedef enum { const char* GetLastFatalMessage(void); -int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) - __attribute__((__format__(os_log, 5, 6))); +int HiLogPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...); + // __attribute__((__format__(os_log, 5, 6))); #define HILOG_DEBUG(type, ...) ((void)HiLogPrint((type), LOG_DEBUG, LOG_DOMAIN, LOG_TAG, __VA_ARGS__)) diff --git a/interfaces/native/innerkits/include/hilog/log_cpp.h b/interfaces/native/innerkits/include/hilog/log_cpp.h index ff48162..bc6077e 100644 --- a/interfaces/native/innerkits/include/hilog/log_cpp.h +++ b/interfaces/native/innerkits/include/hilog/log_cpp.h @@ -21,7 +21,7 @@ #ifdef __cplusplus namespace OHOS { namespace HiviewDFX { -using HiLogLabel = struct { +struct HiLogLabel { LogType type; unsigned int domain; const char *tag; @@ -29,11 +29,16 @@ using HiLogLabel = struct { class HiLog final { public: - static int Debug(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); - static int Info(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); - static int Warn(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); - static int Error(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); - static int Fatal(const HiLogLabel &label, const char *fmt, ...) __attribute__((__format__(os_log, 2, 3))); + static int Debug(const HiLogLabel &label, const char *fmt, ...); + // __attribute__((__format__(os_log, 2, 3))); + static int Info(const HiLogLabel &label, const char *fmt, ...); + // __attribute__((__format__(os_log, 2, 3))); + static int Warn(const HiLogLabel &label, const char *fmt, ...); + // __attribute__((__format__(os_log, 2, 3))); + static int Error(const HiLogLabel &label, const char *fmt, ...); + // __attribute__((__format__(os_log, 2, 3))); + static int Fatal(const HiLogLabel &label, const char *fmt, ...); + // __attribute__((__format__(os_log, 2, 3))); }; } // namespace HiviewDFX } // namespace OHOS -- 2.33.0