1049e185fSopenharmony_ci/* 2049e185fSopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd. 3049e185fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4049e185fSopenharmony_ci * you may not use this file except in compliance with the License. 5049e185fSopenharmony_ci * You may obtain a copy of the License at 6049e185fSopenharmony_ci * 7049e185fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8049e185fSopenharmony_ci * 9049e185fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10049e185fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11049e185fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12049e185fSopenharmony_ci * See the License for the specific language governing permissions and 13049e185fSopenharmony_ci * limitations under the License. 14049e185fSopenharmony_ci */ 15049e185fSopenharmony_ci 16049e185fSopenharmony_ci#include "dfx_log_dump.h" 17049e185fSopenharmony_ci#include <fstream> 18049e185fSopenharmony_ci#include <unistd.h> 19049e185fSopenharmony_ci#include <malloc.h> 20049e185fSopenharmony_ci#include <sys/time.h> 21049e185fSopenharmony_ci#include "securec.h" 22049e185fSopenharmony_ci 23049e185fSopenharmony_cinamespace { 24049e185fSopenharmony_ciconstexpr int32_t FILE_MAX = 100; 25049e185fSopenharmony_ciconstexpr int32_t FILE_LINE_MAX = 50000; 26049e185fSopenharmony_ci} 27049e185fSopenharmony_cinamespace OHOS { 28049e185fSopenharmony_cinamespace Media { 29049e185fSopenharmony_ciDfxLogDump &DfxLogDump::GetInstance() 30049e185fSopenharmony_ci{ 31049e185fSopenharmony_ci static DfxLogDump dfxLogDump; 32049e185fSopenharmony_ci return dfxLogDump; 33049e185fSopenharmony_ci} 34049e185fSopenharmony_ci 35049e185fSopenharmony_ciDfxLogDump::DfxLogDump() 36049e185fSopenharmony_ci{ 37049e185fSopenharmony_ci thread_ = std::make_unique<std::thread>([this] () -> void { this->TaskProcessor(); }); 38049e185fSopenharmony_ci} 39049e185fSopenharmony_ci 40049e185fSopenharmony_ciDfxLogDump::~DfxLogDump() 41049e185fSopenharmony_ci{ 42049e185fSopenharmony_ci { 43049e185fSopenharmony_ci std::unique_lock<std::mutex> lock(mutex_); 44049e185fSopenharmony_ci isExit_ = true; 45049e185fSopenharmony_ci cond_.notify_all(); 46049e185fSopenharmony_ci } 47049e185fSopenharmony_ci if (thread_ != nullptr && thread_->joinable()) { 48049e185fSopenharmony_ci thread_->join(); 49049e185fSopenharmony_ci } 50049e185fSopenharmony_ci} 51049e185fSopenharmony_ci 52049e185fSopenharmony_cistatic void AddNewLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, std::string &logStr) 53049e185fSopenharmony_ci{ 54049e185fSopenharmony_ci struct timeval time = {}; 55049e185fSopenharmony_ci (void)gettimeofday(&time, nullptr); 56049e185fSopenharmony_ci int64_t second = time.tv_sec % 60; 57049e185fSopenharmony_ci int64_t allMinute = time.tv_sec / 60; 58049e185fSopenharmony_ci int64_t minute = allMinute % 60; 59049e185fSopenharmony_ci int64_t hour = allMinute / 60 % 24; 60049e185fSopenharmony_ci int64_t mSecond = time.tv_usec / 1000; 61049e185fSopenharmony_ci 62049e185fSopenharmony_ci logStr += std::to_string(hour); 63049e185fSopenharmony_ci logStr += ":"; 64049e185fSopenharmony_ci logStr += std::to_string(minute); 65049e185fSopenharmony_ci logStr += ":"; 66049e185fSopenharmony_ci logStr += std::to_string(second); 67049e185fSopenharmony_ci logStr += ":"; 68049e185fSopenharmony_ci logStr += std::to_string(mSecond); 69049e185fSopenharmony_ci logStr += " "; 70049e185fSopenharmony_ci logStr += level; 71049e185fSopenharmony_ci logStr += " pid:"; 72049e185fSopenharmony_ci logStr += std::to_string(getpid()); 73049e185fSopenharmony_ci logStr += " tid:"; 74049e185fSopenharmony_ci logStr += std::to_string(gettid()); 75049e185fSopenharmony_ci logStr += " "; 76049e185fSopenharmony_ci logStr += label.tag; 77049e185fSopenharmony_ci logStr += ":"; 78049e185fSopenharmony_ci} 79049e185fSopenharmony_ci 80049e185fSopenharmony_civoid DfxLogDump::SaveLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, const char *fmt, ...) 81049e185fSopenharmony_ci{ 82049e185fSopenharmony_ci std::unique_lock<std::mutex> lock(mutex_); 83049e185fSopenharmony_ci if (!isEnable_) { 84049e185fSopenharmony_ci return; 85049e185fSopenharmony_ci } 86049e185fSopenharmony_ci std::string temp = ""; 87049e185fSopenharmony_ci std::string fmtStr = fmt; 88049e185fSopenharmony_ci int32_t srcPos = 0; 89049e185fSopenharmony_ci auto dtsPos = fmtStr.find("{public}", srcPos); 90049e185fSopenharmony_ci const int32_t pubLen = 8; 91049e185fSopenharmony_ci while (dtsPos != std::string::npos) { 92049e185fSopenharmony_ci temp += fmtStr.substr(srcPos, dtsPos - srcPos); 93049e185fSopenharmony_ci srcPos = static_cast<int32_t>(dtsPos) + pubLen; 94049e185fSopenharmony_ci dtsPos = fmtStr.find("{public}", srcPos); 95049e185fSopenharmony_ci } 96049e185fSopenharmony_ci temp += fmtStr.substr(srcPos); 97049e185fSopenharmony_ci 98049e185fSopenharmony_ci va_list ap; 99049e185fSopenharmony_ci va_start(ap, fmt); 100049e185fSopenharmony_ci constexpr uint32_t maxLogLen = 1024; 101049e185fSopenharmony_ci char logBuf[maxLogLen]; 102049e185fSopenharmony_ci auto ret = vsnprintf_s(logBuf, maxLogLen, maxLogLen - 1, temp.c_str(), ap); 103049e185fSopenharmony_ci va_end(ap); 104049e185fSopenharmony_ci 105049e185fSopenharmony_ci AddNewLog(level, label, logString_); 106049e185fSopenharmony_ci if (ret < 0) { 107049e185fSopenharmony_ci logString_ += "dump log error"; 108049e185fSopenharmony_ci } else { 109049e185fSopenharmony_ci logString_ += logBuf; 110049e185fSopenharmony_ci } 111049e185fSopenharmony_ci logString_ += "\n"; 112049e185fSopenharmony_ci lineCount_++; 113049e185fSopenharmony_ci if (lineCount_ >= FILE_LINE_MAX) { 114049e185fSopenharmony_ci cond_.notify_all(); 115049e185fSopenharmony_ci } 116049e185fSopenharmony_ci} 117049e185fSopenharmony_ci 118049e185fSopenharmony_civoid DfxLogDump::UpdateCheckEnable() 119049e185fSopenharmony_ci{ 120049e185fSopenharmony_ci std::string file = "/data/media/log/check.config"; 121049e185fSopenharmony_ci std::ofstream ofStream(file); 122049e185fSopenharmony_ci if (!ofStream.is_open()) { 123049e185fSopenharmony_ci isEnable_ = false; 124049e185fSopenharmony_ci return; 125049e185fSopenharmony_ci } 126049e185fSopenharmony_ci ofStream.close(); 127049e185fSopenharmony_ci isEnable_ = true; 128049e185fSopenharmony_ci} 129049e185fSopenharmony_ci 130049e185fSopenharmony_civoid DfxLogDump::TaskProcessor() 131049e185fSopenharmony_ci{ 132049e185fSopenharmony_ci pthread_setname_np(pthread_self(), "DfxLogTask"); 133049e185fSopenharmony_ci (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE); 134049e185fSopenharmony_ci (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE); 135049e185fSopenharmony_ci while (true) { 136049e185fSopenharmony_ci std::string temp; 137049e185fSopenharmony_ci int32_t lineCount = 0; 138049e185fSopenharmony_ci { 139049e185fSopenharmony_ci std::unique_lock<std::mutex> lock(mutex_); 140049e185fSopenharmony_ci if (isExit_) { 141049e185fSopenharmony_ci return; 142049e185fSopenharmony_ci } 143049e185fSopenharmony_ci static constexpr int32_t timeout = 60; // every 1 minute have a log 144049e185fSopenharmony_ci cond_.wait_for(lock, std::chrono::seconds(timeout), 145049e185fSopenharmony_ci [this] { 146049e185fSopenharmony_ci UpdateCheckEnable(); 147049e185fSopenharmony_ci return isExit_ || isDump_ || lineCount_ >= FILE_LINE_MAX || !logString_.empty(); 148049e185fSopenharmony_ci }); 149049e185fSopenharmony_ci isDump_ = false; 150049e185fSopenharmony_ci lineCount = lineCount_; 151049e185fSopenharmony_ci lineCount_ = lineCount_ >= FILE_LINE_MAX ? 0 : lineCount_; 152049e185fSopenharmony_ci swap(logString_, temp); 153049e185fSopenharmony_ci } 154049e185fSopenharmony_ci 155049e185fSopenharmony_ci std::string file = "/data/media/log/"; 156049e185fSopenharmony_ci file += std::to_string(getpid()); 157049e185fSopenharmony_ci file += "_hilog_media.log"; 158049e185fSopenharmony_ci file += std::to_string(fileCount_); 159049e185fSopenharmony_ci std::ofstream ofStream; 160049e185fSopenharmony_ci if (isNewFile_) { 161049e185fSopenharmony_ci ofStream.open(file, std::ios::out | std::ios::trunc); 162049e185fSopenharmony_ci } else { 163049e185fSopenharmony_ci ofStream.open(file, std::ios::out | std::ios::app); 164049e185fSopenharmony_ci } 165049e185fSopenharmony_ci if (!ofStream.is_open()) { 166049e185fSopenharmony_ci continue; 167049e185fSopenharmony_ci } 168049e185fSopenharmony_ci isNewFile_ = false; 169049e185fSopenharmony_ci if (lineCount >= FILE_LINE_MAX) { 170049e185fSopenharmony_ci isNewFile_ = true; 171049e185fSopenharmony_ci fileCount_++; 172049e185fSopenharmony_ci fileCount_ = fileCount_ > FILE_MAX ? 0 : fileCount_; 173049e185fSopenharmony_ci } 174049e185fSopenharmony_ci ofStream.write(temp.c_str(), temp.size()); 175049e185fSopenharmony_ci ofStream.close(); 176049e185fSopenharmony_ci } 177049e185fSopenharmony_ci} 178049e185fSopenharmony_ci} // namespace Media 179049e185fSopenharmony_ci} // namespace OHOS