106f6ba60Sopenharmony_ci/* 206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License. 506f6ba60Sopenharmony_ci * You may obtain a copy of the License at 606f6ba60Sopenharmony_ci * 706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 806f6ba60Sopenharmony_ci * 906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and 1306f6ba60Sopenharmony_ci * limitations under the License. 1406f6ba60Sopenharmony_ci */ 1506f6ba60Sopenharmony_ci 1606f6ba60Sopenharmony_ci#include "debug_logger.h" 1706f6ba60Sopenharmony_ci 1806f6ba60Sopenharmony_ci#include <ratio> 1906f6ba60Sopenharmony_ci 2006f6ba60Sopenharmony_ci#include "option.h" 2106f6ba60Sopenharmony_ci#if is_ohos 2206f6ba60Sopenharmony_ci#include "hiperf_hilog.h" 2306f6ba60Sopenharmony_ci#endif 2406f6ba60Sopenharmony_ci 2506f6ba60Sopenharmony_ciusing namespace std::literals::chrono_literals; 2606f6ba60Sopenharmony_ciusing namespace std::chrono; 2706f6ba60Sopenharmony_cinamespace OHOS { 2806f6ba60Sopenharmony_cinamespace Developtools { 2906f6ba60Sopenharmony_cinamespace NativeDaemon { 3006f6ba60Sopenharmony_ciDebugLogger::DebugLogger() : timeStamp_(steady_clock::now()), logPath_(DEFAULT_LOG_PATH) 3106f6ba60Sopenharmony_ci{ 3206f6ba60Sopenharmony_ci logFileBuffer_.resize(LOG_BUFFER_SIZE); 3306f6ba60Sopenharmony_ci OpenLog(); 3406f6ba60Sopenharmony_ci} 3506f6ba60Sopenharmony_ci 3606f6ba60Sopenharmony_ciScopeDebugLevel::ScopeDebugLevel(DebugLevel level, bool mix) 3706f6ba60Sopenharmony_ci{ 3806f6ba60Sopenharmony_ci savedDebugLevel_ = DebugLogger::GetInstance()->SetLogLevel(level); 3906f6ba60Sopenharmony_ci savedMixOutput_ = DebugLogger::GetInstance()->SetMixLogOutput(mix); 4006f6ba60Sopenharmony_ci} 4106f6ba60Sopenharmony_ci 4206f6ba60Sopenharmony_ciScopeDebugLevel::~ScopeDebugLevel() 4306f6ba60Sopenharmony_ci{ 4406f6ba60Sopenharmony_ci DebugLogger::GetInstance()->SetLogLevel(savedDebugLevel_); 4506f6ba60Sopenharmony_ci DebugLogger::GetInstance()->SetMixLogOutput(savedMixOutput_); 4606f6ba60Sopenharmony_ci} 4706f6ba60Sopenharmony_ci 4806f6ba60Sopenharmony_ciDebugLogger::~DebugLogger() 4906f6ba60Sopenharmony_ci{ 5006f6ba60Sopenharmony_ci Disable(); 5106f6ba60Sopenharmony_ci if (file_ != nullptr) { 5206f6ba60Sopenharmony_ci fclose(file_); 5306f6ba60Sopenharmony_ci file_ = nullptr; 5406f6ba60Sopenharmony_ci } 5506f6ba60Sopenharmony_ci} 5606f6ba60Sopenharmony_ci 5706f6ba60Sopenharmony_civoid DebugLogger::Disable(bool disable) 5806f6ba60Sopenharmony_ci{ 5906f6ba60Sopenharmony_ci if (logDisabled_ != disable) { 6006f6ba60Sopenharmony_ci logDisabled_ = disable; 6106f6ba60Sopenharmony_ci if (!disable) { 6206f6ba60Sopenharmony_ci // reopen the log file 6306f6ba60Sopenharmony_ci OpenLog(); 6406f6ba60Sopenharmony_ci } 6506f6ba60Sopenharmony_ci } 6606f6ba60Sopenharmony_ci} 6706f6ba60Sopenharmony_ci 6806f6ba60Sopenharmony_ci#if is_ohos 6906f6ba60Sopenharmony_ci#ifndef CONFIG_NO_HILOG 7006f6ba60Sopenharmony_civoid DebugLogger::HiLog(std::string &buffer) const 7106f6ba60Sopenharmony_ci{ 7206f6ba60Sopenharmony_ci size_t lastLF = buffer.find_last_of('\n'); 7306f6ba60Sopenharmony_ci if (lastLF != std::string::npos) { 7406f6ba60Sopenharmony_ci buffer.erase(lastLF, 1); 7506f6ba60Sopenharmony_ci } 7606f6ba60Sopenharmony_ci HILOG_BASE_DEBUG(LOG_CORE, "%{public}s", buffer.c_str()); 7706f6ba60Sopenharmony_ci} 7806f6ba60Sopenharmony_ci#endif 7906f6ba60Sopenharmony_ci#endif 8006f6ba60Sopenharmony_ci 8106f6ba60Sopenharmony_ciint DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fmt, ...) const 8206f6ba60Sopenharmony_ci{ 8306f6ba60Sopenharmony_ci constexpr const int DEFAULT_STRING_BUF_SIZE = 4096; 8406f6ba60Sopenharmony_ci#ifdef HIPERF_DEBUG_TIME 8506f6ba60Sopenharmony_ci const auto startSprintf = steady_clock::now(); 8606f6ba60Sopenharmony_ci#endif 8706f6ba60Sopenharmony_ci const auto startTime = steady_clock::now(); 8806f6ba60Sopenharmony_ci if (!ShouldLog(level, logTag) or logDisabled_ or fmt == nullptr) { 8906f6ba60Sopenharmony_ci#ifdef HIPERF_DEBUG_TIME 9006f6ba60Sopenharmony_ci logTimes_ += duration_cast<microseconds>(steady_clock::now() - startSprintf); 9106f6ba60Sopenharmony_ci#endif 9206f6ba60Sopenharmony_ci return 0; 9306f6ba60Sopenharmony_ci } 9406f6ba60Sopenharmony_ci va_list va; 9506f6ba60Sopenharmony_ci int ret = 0; 9606f6ba60Sopenharmony_ci 9706f6ba60Sopenharmony_ci std::string buffer(DEFAULT_STRING_BUF_SIZE, '\0'); 9806f6ba60Sopenharmony_ci va_start(va, fmt); 9906f6ba60Sopenharmony_ci ret = vsnprintf_s(buffer.data(), buffer.size(), buffer.size() - 1, fmt, va); 10006f6ba60Sopenharmony_ci va_end(va); 10106f6ba60Sopenharmony_ci#ifdef HIPERF_DEBUG_TIME 10206f6ba60Sopenharmony_ci logSprintfTimes_ += duration_cast<microseconds>(steady_clock::now() - startSprintf); 10306f6ba60Sopenharmony_ci#endif 10406f6ba60Sopenharmony_ci if ((mixLogOutput_ and level < LEVEL_FATAL) or level == LEVEL_FATAL) { 10506f6ba60Sopenharmony_ci ret = fprintf(stdout, "%s", buffer.data()); // to the stdout 10606f6ba60Sopenharmony_ci } 10706f6ba60Sopenharmony_ci 10806f6ba60Sopenharmony_ci if (enableHilog_) { 10906f6ba60Sopenharmony_ci#if is_ohos && !defined(CONFIG_NO_HILOG) 11006f6ba60Sopenharmony_ci std::lock_guard<std::mutex> lock(logMutex_); 11106f6ba60Sopenharmony_ci HiLog(buffer); // to the hilog 11206f6ba60Sopenharmony_ci#endif 11306f6ba60Sopenharmony_ci } else if (file_ != nullptr) { 11406f6ba60Sopenharmony_ci std::lock_guard<std::mutex> lock(logMutex_); 11506f6ba60Sopenharmony_ci#ifdef HIPERF_DEBUG_TIME 11606f6ba60Sopenharmony_ci const auto startWriteTime = steady_clock::now(); 11706f6ba60Sopenharmony_ci#endif 11806f6ba60Sopenharmony_ci milliseconds timeStamp = duration_cast<milliseconds>(startTime - timeStamp_); 11906f6ba60Sopenharmony_ci fprintf(file_, "%05" PRId64 " ms %s", (int64_t)timeStamp.count(), buffer.data()); // to the file 12006f6ba60Sopenharmony_ci#ifdef HIPERF_DEBUG_TIME 12106f6ba60Sopenharmony_ci logWriteTimes_ += duration_cast<microseconds>(steady_clock::now() - startWriteTime); 12206f6ba60Sopenharmony_ci#endif 12306f6ba60Sopenharmony_ci } 12406f6ba60Sopenharmony_ci 12506f6ba60Sopenharmony_ci#ifdef HIPERF_DEBUG_TIME 12606f6ba60Sopenharmony_ci logTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime); 12706f6ba60Sopenharmony_ci logCount_++; 12806f6ba60Sopenharmony_ci#endif 12906f6ba60Sopenharmony_ci if (level == LEVEL_FATAL && exitOnFatal_) { 13006f6ba60Sopenharmony_ci fflush(file_); 13106f6ba60Sopenharmony_ci logDisabled_ = true; 13206f6ba60Sopenharmony_ci exit(-1); 13306f6ba60Sopenharmony_ci } 13406f6ba60Sopenharmony_ci return ret; 13506f6ba60Sopenharmony_ci} 13606f6ba60Sopenharmony_ci 13706f6ba60Sopenharmony_cibool DebugLogger::EnableHiLog(bool enable) 13806f6ba60Sopenharmony_ci{ 13906f6ba60Sopenharmony_ci enableHilog_ = enable; 14006f6ba60Sopenharmony_ci if (fprintf(stdout, "change to use hilog\n") < 0) { 14106f6ba60Sopenharmony_ci // what can we do here ??? 14206f6ba60Sopenharmony_ci } 14306f6ba60Sopenharmony_ci return enableHilog_; 14406f6ba60Sopenharmony_ci} 14506f6ba60Sopenharmony_ci 14606f6ba60Sopenharmony_cibool DebugLogger::ShouldLog(DebugLevel level, const std::string &logtag) const 14706f6ba60Sopenharmony_ci{ 14806f6ba60Sopenharmony_ci return GetLogLevelByTag(logtag) <= level; 14906f6ba60Sopenharmony_ci} 15006f6ba60Sopenharmony_ci 15106f6ba60Sopenharmony_ciDebugLevel DebugLogger::SetLogLevel(DebugLevel debugLevel) 15206f6ba60Sopenharmony_ci{ 15306f6ba60Sopenharmony_ci DebugLevel lastLevel = DebugLogger::GetInstance()->debugLevel_; 15406f6ba60Sopenharmony_ci debugLevel_ = debugLevel; 15506f6ba60Sopenharmony_ci // force print 15606f6ba60Sopenharmony_ci printf("setLogLevel %d\n", debugLevel); 15706f6ba60Sopenharmony_ci return lastLevel; 15806f6ba60Sopenharmony_ci} 15906f6ba60Sopenharmony_ci 16006f6ba60Sopenharmony_cibool DebugLogger::SetMixLogOutput(bool enable) 16106f6ba60Sopenharmony_ci{ 16206f6ba60Sopenharmony_ci bool lastMixLogOutput = mixLogOutput_; 16306f6ba60Sopenharmony_ci mixLogOutput_ = enable; 16406f6ba60Sopenharmony_ci return lastMixLogOutput; 16506f6ba60Sopenharmony_ci} 16606f6ba60Sopenharmony_ci 16706f6ba60Sopenharmony_cibool DebugLogger::SetLogPath(const std::string &newLogPath) 16806f6ba60Sopenharmony_ci{ 16906f6ba60Sopenharmony_ci // make sure not write happend when rename 17006f6ba60Sopenharmony_ci std::lock_guard<std::mutex> lock(logMutex_); 17106f6ba60Sopenharmony_ci if (newLogPath.empty()) { 17206f6ba60Sopenharmony_ci return false; 17306f6ba60Sopenharmony_ci } 17406f6ba60Sopenharmony_ci if (file_ != nullptr) { 17506f6ba60Sopenharmony_ci fclose(file_); 17606f6ba60Sopenharmony_ci file_ = nullptr; 17706f6ba60Sopenharmony_ci if (rename(logPath_.c_str(), newLogPath.c_str()) != 0) { 17806f6ba60Sopenharmony_ci // reopen the old log file path 17906f6ba60Sopenharmony_ci OpenLog(); 18006f6ba60Sopenharmony_ci return false; 18106f6ba60Sopenharmony_ci } 18206f6ba60Sopenharmony_ci } 18306f6ba60Sopenharmony_ci logPath_ = newLogPath; 18406f6ba60Sopenharmony_ci return OpenLog(); 18506f6ba60Sopenharmony_ci} 18606f6ba60Sopenharmony_ci 18706f6ba60Sopenharmony_civoid DebugLogger::SetLogTags(const std::string &tags) 18806f6ba60Sopenharmony_ci{ 18906f6ba60Sopenharmony_ci HLOGI(" tags is '%s'", tags.c_str()); 19006f6ba60Sopenharmony_ci auto tagLevels = StringSplit(tags, ","); 19106f6ba60Sopenharmony_ci logTagLevelmap_.clear(); 19206f6ba60Sopenharmony_ci for (auto tagLevel : tagLevels) { 19306f6ba60Sopenharmony_ci auto tagLevelPair = StringSplit(tagLevel, ":"); 19406f6ba60Sopenharmony_ci if (tagLevelPair.size() == 1) { // only tag 19506f6ba60Sopenharmony_ci logTagLevelmap_[tagLevelPair[0]] = LEVEL_MUCH; 19606f6ba60Sopenharmony_ci } else { // tag:level 19706f6ba60Sopenharmony_ci logTagLevelmap_[tagLevelPair[0]] = GetLogLevelByName(tagLevelPair[1].c_str()); 19806f6ba60Sopenharmony_ci } 19906f6ba60Sopenharmony_ci } 20006f6ba60Sopenharmony_ci for (auto it = logTagLevelmap_.begin(); it != logTagLevelmap_.end(); it++) { 20106f6ba60Sopenharmony_ci HLOGD(" '%s'='%s'", it->first.c_str(), GetLogLevelName(it->second).c_str()); 20206f6ba60Sopenharmony_ci } 20306f6ba60Sopenharmony_ci} 20406f6ba60Sopenharmony_ci 20506f6ba60Sopenharmony_ciDebugLevel DebugLogger::GetLogLevelByTag(const std::string &tag) const 20606f6ba60Sopenharmony_ci{ 20706f6ba60Sopenharmony_ci if (logTagLevelmap_.count(tag) > 0) { 20806f6ba60Sopenharmony_ci return logTagLevelmap_.at(tag); 20906f6ba60Sopenharmony_ci } else { 21006f6ba60Sopenharmony_ci return GetLogLevel(); 21106f6ba60Sopenharmony_ci } 21206f6ba60Sopenharmony_ci} 21306f6ba60Sopenharmony_ci 21406f6ba60Sopenharmony_ciconst std::string DebugLogger::GetLogLevelName(DebugLevel level) const 21506f6ba60Sopenharmony_ci{ 21606f6ba60Sopenharmony_ci return DebugLevelMap.at(level); 21706f6ba60Sopenharmony_ci} 21806f6ba60Sopenharmony_ci 21906f6ba60Sopenharmony_ciDebugLevel DebugLogger::GetLogLevelByName(const std::string &name) const 22006f6ba60Sopenharmony_ci{ 22106f6ba60Sopenharmony_ci for (auto it = DebugLevelMap.begin(); it != DebugLevelMap.end(); it++) { 22206f6ba60Sopenharmony_ci if (it->second == name) { 22306f6ba60Sopenharmony_ci return it->first; 22406f6ba60Sopenharmony_ci } 22506f6ba60Sopenharmony_ci } 22606f6ba60Sopenharmony_ci // not found ? 22706f6ba60Sopenharmony_ci return LEVEL_MUCH; 22806f6ba60Sopenharmony_ci} 22906f6ba60Sopenharmony_ci 23006f6ba60Sopenharmony_cibool DebugLogger::OpenLog() 23106f6ba60Sopenharmony_ci{ 23206f6ba60Sopenharmony_ci if (logDisabled_) { 23306f6ba60Sopenharmony_ci // don't reopen it when we crash or soemthing else. 23406f6ba60Sopenharmony_ci return false; 23506f6ba60Sopenharmony_ci } 23606f6ba60Sopenharmony_ci if (file_ != nullptr) { 23706f6ba60Sopenharmony_ci // already open 23806f6ba60Sopenharmony_ci return true; 23906f6ba60Sopenharmony_ci } else { 24006f6ba60Sopenharmony_ci file_ = fopen(logPath_.c_str(), "w"); 24106f6ba60Sopenharmony_ci } 24206f6ba60Sopenharmony_ci if (file_ == nullptr) { 24306f6ba60Sopenharmony_ci const int bufSize = 256; 24406f6ba60Sopenharmony_ci char buf[bufSize] = { 0 }; 24506f6ba60Sopenharmony_ci strerror_r(errno, buf, bufSize); 24606f6ba60Sopenharmony_ci fprintf(stdout, "unable save log file to '%s' because '%d:%s'\n", logPath_.c_str(), errno, buf); 24706f6ba60Sopenharmony_ci return false; 24806f6ba60Sopenharmony_ci } else { 24906f6ba60Sopenharmony_ci fseek(file_, 0, SEEK_SET); 25006f6ba60Sopenharmony_ci // ecach log can save 6ms (29ms -> 23ms) 25106f6ba60Sopenharmony_ci setvbuf(file_, logFileBuffer_.data(), _IOFBF, logFileBuffer_.size()); 25206f6ba60Sopenharmony_ci fprintf(stdout, "log will save at '%s'\n", logPath_.c_str()); 25306f6ba60Sopenharmony_ci return true; 25406f6ba60Sopenharmony_ci } 25506f6ba60Sopenharmony_ci} 25606f6ba60Sopenharmony_ci 25706f6ba60Sopenharmony_ci__attribute__((weak)) DebugLevel DebugLogger::debugLevel_ = LEVEL_DEBUG; 25806f6ba60Sopenharmony_ci__attribute__((weak)) bool DebugLogger::logDisabled_ = true; 25906f6ba60Sopenharmony_cistd::unique_ptr<DebugLogger> DebugLogger::logInstance_; 26006f6ba60Sopenharmony_ci 26106f6ba60Sopenharmony_ciDebugLogger *DebugLogger::GetInstance() 26206f6ba60Sopenharmony_ci{ 26306f6ba60Sopenharmony_ci if (logInstance_ == nullptr) { 26406f6ba60Sopenharmony_ci logInstance_ = std::make_unique<DebugLogger>(); 26506f6ba60Sopenharmony_ci } 26606f6ba60Sopenharmony_ci return logInstance_.get(); 26706f6ba60Sopenharmony_ci} 26806f6ba60Sopenharmony_ci} // namespace NativeDaemon 26906f6ba60Sopenharmony_ci} // namespace Developtools 27006f6ba60Sopenharmony_ci} // namespace OHOS 271