148f512ceSopenharmony_ci/* 248f512ceSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 448f512ceSopenharmony_ci * you may not use this file except in compliance with the License. 548f512ceSopenharmony_ci * You may obtain a copy of the License at 648f512ceSopenharmony_ci * 748f512ceSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 848f512ceSopenharmony_ci * 948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and 1348f512ceSopenharmony_ci * limitations under the License. 1448f512ceSopenharmony_ci */ 1548f512ceSopenharmony_ci 1648f512ceSopenharmony_ci#include "debug_logger.h" 1748f512ceSopenharmony_ci 1848f512ceSopenharmony_ci#include <ratio> 1948f512ceSopenharmony_ci 2048f512ceSopenharmony_ci#include "option.h" 2148f512ceSopenharmony_ci#if defined(is_ohos) && is_ohos 2248f512ceSopenharmony_ci#include "hiperf_hilog.h" 2348f512ceSopenharmony_ci#endif 2448f512ceSopenharmony_ci 2548f512ceSopenharmony_ciusing namespace std::literals::chrono_literals; 2648f512ceSopenharmony_ciusing namespace std::chrono; 2748f512ceSopenharmony_cinamespace OHOS { 2848f512ceSopenharmony_cinamespace Developtools { 2948f512ceSopenharmony_cinamespace HiPerf { 3048f512ceSopenharmony_ciDebugLogger::DebugLogger() : timeStamp_(steady_clock::now()), logPath_(DEFAULT_LOG_PATH) 3148f512ceSopenharmony_ci{ 3248f512ceSopenharmony_ci OpenLog(); 3348f512ceSopenharmony_ci} 3448f512ceSopenharmony_ci 3548f512ceSopenharmony_ciScopeDebugLevel::ScopeDebugLevel(DebugLevel level, bool mix) 3648f512ceSopenharmony_ci{ 3748f512ceSopenharmony_ci savedDebugLevel_ = DebugLogger::GetInstance()->SetLogLevel(level); 3848f512ceSopenharmony_ci savedMixOutput_ = DebugLogger::GetInstance()->SetMixLogOutput(mix); 3948f512ceSopenharmony_ci} 4048f512ceSopenharmony_ci 4148f512ceSopenharmony_ciScopeDebugLevel::~ScopeDebugLevel() 4248f512ceSopenharmony_ci{ 4348f512ceSopenharmony_ci DebugLogger::GetInstance()->SetLogLevel(savedDebugLevel_); 4448f512ceSopenharmony_ci DebugLogger::GetInstance()->SetMixLogOutput(savedMixOutput_); 4548f512ceSopenharmony_ci} 4648f512ceSopenharmony_ci 4748f512ceSopenharmony_ciDebugLogger::~DebugLogger() 4848f512ceSopenharmony_ci{ 4948f512ceSopenharmony_ci Disable(); 5048f512ceSopenharmony_ci if (file_ != nullptr) { 5148f512ceSopenharmony_ci fclose(file_); 5248f512ceSopenharmony_ci file_ = nullptr; 5348f512ceSopenharmony_ci } 5448f512ceSopenharmony_ci} 5548f512ceSopenharmony_ci 5648f512ceSopenharmony_civoid DebugLogger::Disable(bool disable) 5748f512ceSopenharmony_ci{ 5848f512ceSopenharmony_ci if (logDisabled_ != disable) { 5948f512ceSopenharmony_ci logDisabled_ = disable; 6048f512ceSopenharmony_ci if (!disable) { 6148f512ceSopenharmony_ci // reopen the log file 6248f512ceSopenharmony_ci OpenLog(); 6348f512ceSopenharmony_ci } 6448f512ceSopenharmony_ci } 6548f512ceSopenharmony_ci} 6648f512ceSopenharmony_ci 6748f512ceSopenharmony_ci#if is_ohos 6848f512ceSopenharmony_ci#ifndef CONFIG_NO_HILOG 6948f512ceSopenharmony_ciint DebugLogger::HiLog(std::string &buffer) const 7048f512ceSopenharmony_ci{ 7148f512ceSopenharmony_ci size_t lastLF = buffer.find_last_of('\n'); 7248f512ceSopenharmony_ci if (lastLF != std::string::npos) { 7348f512ceSopenharmony_ci buffer.erase(lastLF, 1); 7448f512ceSopenharmony_ci } 7548f512ceSopenharmony_ci return OHOS::HiviewDFX::HiLog::Info(HIPERF_HILOG_LABLE[MODULE_DEFAULT], "%{public}s", 7648f512ceSopenharmony_ci buffer.c_str()); 7748f512ceSopenharmony_ci} 7848f512ceSopenharmony_ci#endif 7948f512ceSopenharmony_ci#endif 8048f512ceSopenharmony_ci 8148f512ceSopenharmony_ciint DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fmt, ...) const 8248f512ceSopenharmony_ci{ 8348f512ceSopenharmony_ci constexpr const int DEFAULT_STRING_BUF_SIZE = 4096; 8448f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME 8548f512ceSopenharmony_ci const auto startSprintf = steady_clock::now(); 8648f512ceSopenharmony_ci#endif 8748f512ceSopenharmony_ci const auto startTime = steady_clock::now(); 8848f512ceSopenharmony_ci if (!ShouldLog(level, logTag) or logDisabled_ or fmt == nullptr) { 8948f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME 9048f512ceSopenharmony_ci logTimes_ += duration_cast<microseconds>(steady_clock::now() - startSprintf); 9148f512ceSopenharmony_ci#endif 9248f512ceSopenharmony_ci return 0; 9348f512ceSopenharmony_ci } 9448f512ceSopenharmony_ci va_list va; 9548f512ceSopenharmony_ci int ret = 0; 9648f512ceSopenharmony_ci 9748f512ceSopenharmony_ci std::string buffer(DEFAULT_STRING_BUF_SIZE, '\0'); 9848f512ceSopenharmony_ci va_start(va, fmt); 9948f512ceSopenharmony_ci ret = vsnprintf_s(buffer.data(), buffer.size(), buffer.size() >= 1 ? buffer.size() - 1 : 0, fmt, va); 10048f512ceSopenharmony_ci va_end(va); 10148f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME 10248f512ceSopenharmony_ci logSprintfTimes_ += duration_cast<microseconds>(steady_clock::now() - startSprintf); 10348f512ceSopenharmony_ci#endif 10448f512ceSopenharmony_ci if ((mixLogOutput_ and level < LEVEL_FATAL) or level == LEVEL_FATAL) { 10548f512ceSopenharmony_ci ret = fprintf(stdout, "%s", buffer.data()); // to the stdout 10648f512ceSopenharmony_ci } 10748f512ceSopenharmony_ci 10848f512ceSopenharmony_ci if (enableHilog_) { 10948f512ceSopenharmony_ci#if is_ohos && !defined(CONFIG_NO_HILOG) 11048f512ceSopenharmony_ci std::lock_guard<std::recursive_mutex> lock(logMutex_); 11148f512ceSopenharmony_ci ret = HiLog(buffer); // to the hilog 11248f512ceSopenharmony_ci#endif 11348f512ceSopenharmony_ci } else if (file_ != nullptr) { 11448f512ceSopenharmony_ci std::lock_guard<std::recursive_mutex> lock(logMutex_); 11548f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME 11648f512ceSopenharmony_ci const auto startWriteTime = steady_clock::now(); 11748f512ceSopenharmony_ci#endif 11848f512ceSopenharmony_ci milliseconds timeStamp = duration_cast<milliseconds>(startTime - timeStamp_); 11948f512ceSopenharmony_ci fprintf(file_, "%05" PRId64 "ms %s", (int64_t)timeStamp.count(), buffer.data()); // to the file 12048f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME 12148f512ceSopenharmony_ci logWriteTimes_ += duration_cast<microseconds>(steady_clock::now() - startWriteTime); 12248f512ceSopenharmony_ci#endif 12348f512ceSopenharmony_ci } 12448f512ceSopenharmony_ci 12548f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME 12648f512ceSopenharmony_ci logTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime); 12748f512ceSopenharmony_ci logCount_++; 12848f512ceSopenharmony_ci#endif 12948f512ceSopenharmony_ci if (level == LEVEL_FATAL && exitOnFatal_) { 13048f512ceSopenharmony_ci fflush(file_); 13148f512ceSopenharmony_ci logDisabled_ = true; 13248f512ceSopenharmony_ci exit(-1); 13348f512ceSopenharmony_ci } 13448f512ceSopenharmony_ci return ret; 13548f512ceSopenharmony_ci} 13648f512ceSopenharmony_ci 13748f512ceSopenharmony_cibool DebugLogger::EnableHiLog(bool enable) 13848f512ceSopenharmony_ci{ 13948f512ceSopenharmony_ci enableHilog_ = enable; 14048f512ceSopenharmony_ci if (enable) { 14148f512ceSopenharmony_ci if (fprintf(stdout, "change to use hilog\n") < 0) { 14248f512ceSopenharmony_ci // what can we do here ??? 14348f512ceSopenharmony_ci } 14448f512ceSopenharmony_ci } 14548f512ceSopenharmony_ci return enableHilog_; 14648f512ceSopenharmony_ci} 14748f512ceSopenharmony_ci 14848f512ceSopenharmony_cibool DebugLogger::ShouldLog(DebugLevel level, const std::string &logtag) const 14948f512ceSopenharmony_ci{ 15048f512ceSopenharmony_ci return GetLogLevelByTag(logtag) <= level; 15148f512ceSopenharmony_ci} 15248f512ceSopenharmony_ci 15348f512ceSopenharmony_ciDebugLevel DebugLogger::SetLogLevel(DebugLevel debugLevel) 15448f512ceSopenharmony_ci{ 15548f512ceSopenharmony_ci DebugLevel lastLevel = DebugLogger::GetInstance()->debugLevel_; 15648f512ceSopenharmony_ci debugLevel_ = debugLevel; 15748f512ceSopenharmony_ci // force print 15848f512ceSopenharmony_ci printf("setLogLevel %d\n", debugLevel); 15948f512ceSopenharmony_ci return lastLevel; 16048f512ceSopenharmony_ci} 16148f512ceSopenharmony_ci 16248f512ceSopenharmony_cibool DebugLogger::SetMixLogOutput(bool enable) 16348f512ceSopenharmony_ci{ 16448f512ceSopenharmony_ci bool lastMixLogOutput = mixLogOutput_; 16548f512ceSopenharmony_ci mixLogOutput_ = enable; 16648f512ceSopenharmony_ci return lastMixLogOutput; 16748f512ceSopenharmony_ci} 16848f512ceSopenharmony_ci 16948f512ceSopenharmony_cibool DebugLogger::SetLogPath(const std::string &newLogPath) 17048f512ceSopenharmony_ci{ 17148f512ceSopenharmony_ci // make sure not write happend when rename 17248f512ceSopenharmony_ci std::lock_guard<std::recursive_mutex> lock(logMutex_); 17348f512ceSopenharmony_ci if (newLogPath.empty() and newLogPath != logPath_) { 17448f512ceSopenharmony_ci return false; 17548f512ceSopenharmony_ci } 17648f512ceSopenharmony_ci if (file_ != nullptr) { 17748f512ceSopenharmony_ci fclose(file_); 17848f512ceSopenharmony_ci file_ = nullptr; 17948f512ceSopenharmony_ci if (rename(logPath_.c_str(), newLogPath.c_str()) != 0) { 18048f512ceSopenharmony_ci // reopen the old log file path 18148f512ceSopenharmony_ci OpenLog(); 18248f512ceSopenharmony_ci return false; 18348f512ceSopenharmony_ci } 18448f512ceSopenharmony_ci } 18548f512ceSopenharmony_ci logPath_ = newLogPath; 18648f512ceSopenharmony_ci return OpenLog(); 18748f512ceSopenharmony_ci} 18848f512ceSopenharmony_ci 18948f512ceSopenharmony_civoid DebugLogger::SetLogTags(const std::string &tags) 19048f512ceSopenharmony_ci{ 19148f512ceSopenharmony_ci HLOGI(" tags is '%s'", tags.c_str()); 19248f512ceSopenharmony_ci auto tagLevels = StringSplit(tags, ","); 19348f512ceSopenharmony_ci logTagLevelmap_.clear(); 19448f512ceSopenharmony_ci for (auto tagLevel : tagLevels) { 19548f512ceSopenharmony_ci auto tagLevelPair = StringSplit(tagLevel, ":"); 19648f512ceSopenharmony_ci if (tagLevelPair.size() == 1) { // only tag 19748f512ceSopenharmony_ci logTagLevelmap_[tagLevelPair[0]] = LEVEL_MUCH; 19848f512ceSopenharmony_ci } else { // tag:level 19948f512ceSopenharmony_ci logTagLevelmap_[tagLevelPair[0]] = GetLogLevelByName(tagLevelPair[1].c_str()); 20048f512ceSopenharmony_ci } 20148f512ceSopenharmony_ci } 20248f512ceSopenharmony_ci for (auto it = logTagLevelmap_.begin(); it != logTagLevelmap_.end(); it++) { 20348f512ceSopenharmony_ci HLOGD(" '%s'='%s'", it->first.c_str(), GetLogLevelName(it->second).c_str()); 20448f512ceSopenharmony_ci } 20548f512ceSopenharmony_ci} 20648f512ceSopenharmony_ci 20748f512ceSopenharmony_ciDebugLevel DebugLogger::GetLogLevelByTag(const std::string &tag) const 20848f512ceSopenharmony_ci{ 20948f512ceSopenharmony_ci if (logTagLevelmap_.count(tag) > 0) { 21048f512ceSopenharmony_ci return logTagLevelmap_.at(tag); 21148f512ceSopenharmony_ci } else { 21248f512ceSopenharmony_ci return GetLogLevel(); 21348f512ceSopenharmony_ci } 21448f512ceSopenharmony_ci} 21548f512ceSopenharmony_ci 21648f512ceSopenharmony_ciconst std::string DebugLogger::GetLogLevelName(DebugLevel level) const 21748f512ceSopenharmony_ci{ 21848f512ceSopenharmony_ci return DebugLevelMap.at(level); 21948f512ceSopenharmony_ci} 22048f512ceSopenharmony_ci 22148f512ceSopenharmony_ciDebugLevel DebugLogger::GetLogLevelByName(const std::string &name) const 22248f512ceSopenharmony_ci{ 22348f512ceSopenharmony_ci for (auto it = DebugLevelMap.begin(); it != DebugLevelMap.end(); it++) { 22448f512ceSopenharmony_ci if (it->second == name) { 22548f512ceSopenharmony_ci return it->first; 22648f512ceSopenharmony_ci } 22748f512ceSopenharmony_ci } 22848f512ceSopenharmony_ci // not found ? 22948f512ceSopenharmony_ci return LEVEL_MUCH; 23048f512ceSopenharmony_ci} 23148f512ceSopenharmony_ci 23248f512ceSopenharmony_ci// only use for UT 23348f512ceSopenharmony_civoid DebugLogger::Reset() 23448f512ceSopenharmony_ci{ 23548f512ceSopenharmony_ci EnableHiLog(false); 23648f512ceSopenharmony_ci SetLogLevel(LEVEL_VERBOSE); 23748f512ceSopenharmony_ci Disable(false); 23848f512ceSopenharmony_ci SetLogPath(DEFAULT_LOG_PATH); 23948f512ceSopenharmony_ci SetLogTags(""); 24048f512ceSopenharmony_ci} 24148f512ceSopenharmony_ci 24248f512ceSopenharmony_cibool DebugLogger::RestoreLog() 24348f512ceSopenharmony_ci{ 24448f512ceSopenharmony_ci // use append not write for continually write 24548f512ceSopenharmony_ci return OpenLog(logPath_, "a"); 24648f512ceSopenharmony_ci} 24748f512ceSopenharmony_ci 24848f512ceSopenharmony_cibool DebugLogger::OpenLog(const std::string &tempLogPath, const std::string &flags) 24948f512ceSopenharmony_ci{ 25048f512ceSopenharmony_ci std::lock_guard<std::recursive_mutex> lock(logMutex_); 25148f512ceSopenharmony_ci 25248f512ceSopenharmony_ci if (logDisabled_) { 25348f512ceSopenharmony_ci // don't reopen it when we crash or something else. 25448f512ceSopenharmony_ci return false; 25548f512ceSopenharmony_ci } 25648f512ceSopenharmony_ci if (!tempLogPath.empty()) { 25748f512ceSopenharmony_ci if (file_ != nullptr) { 25848f512ceSopenharmony_ci fclose(file_); 25948f512ceSopenharmony_ci } 26048f512ceSopenharmony_ci std::string resolvedPath = CanonicalizeSpecPath(tempLogPath.c_str()); 26148f512ceSopenharmony_ci file_ = fopen(resolvedPath.c_str(), flags.c_str()); 26248f512ceSopenharmony_ci } 26348f512ceSopenharmony_ci if (file_ != nullptr) { 26448f512ceSopenharmony_ci // already open 26548f512ceSopenharmony_ci return true; 26648f512ceSopenharmony_ci } else { 26748f512ceSopenharmony_ci std::string resolvedPath = CanonicalizeSpecPath(logPath_.c_str()); 26848f512ceSopenharmony_ci file_ = fopen(resolvedPath.c_str(), "w"); 26948f512ceSopenharmony_ci } 27048f512ceSopenharmony_ci if (file_ == nullptr) { 27148f512ceSopenharmony_ci fprintf(stdout, "unable save log file to '%s' because '%d'\n", logPath_.c_str(), errno); 27248f512ceSopenharmony_ci return false; 27348f512ceSopenharmony_ci } else { 27448f512ceSopenharmony_ci fseek(file_, 0, SEEK_SET); 27548f512ceSopenharmony_ci // ecach log can save 6ms (29ms -> 23ms) 27648f512ceSopenharmony_ci fprintf(stdout, "log will save at '%s'\n", logPath_.c_str()); 27748f512ceSopenharmony_ci return true; 27848f512ceSopenharmony_ci } 27948f512ceSopenharmony_ci} 28048f512ceSopenharmony_ci 28148f512ceSopenharmony_ci__attribute__((weak)) DebugLevel DebugLogger::debugLevel_ = LEVEL_DEBUG; 28248f512ceSopenharmony_ci__attribute__((weak)) bool DebugLogger::logDisabled_ = true; 28348f512ceSopenharmony_cistd::unique_ptr<DebugLogger> DebugLogger::logInstance_; 28448f512ceSopenharmony_ci 28548f512ceSopenharmony_ciDebugLogger *DebugLogger::GetInstance() 28648f512ceSopenharmony_ci{ 28748f512ceSopenharmony_ci if (logInstance_ == nullptr) { 28848f512ceSopenharmony_ci logInstance_ = std::make_unique<DebugLogger>(); 28948f512ceSopenharmony_ci } 29048f512ceSopenharmony_ci return logInstance_.get(); 29148f512ceSopenharmony_ci} 29248f512ceSopenharmony_ci} // namespace HiPerf 29348f512ceSopenharmony_ci} // namespace Developtools 29448f512ceSopenharmony_ci} // namespace OHOS 295