1 /*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dfx_log_dump.h"
17 #include <fstream>
18 #include <unistd.h>
19 #include <sys/time.h>
20 #include "securec.h"
21
22 namespace {
23 constexpr int32_t FILE_MAX = 100;
24 constexpr int32_t FILE_LINE_MAX = 50000;
25 }
26 namespace OHOS {
27 namespace Media {
GetInstance()28 DfxLogDump &DfxLogDump::GetInstance()
29 {
30 static DfxLogDump dfxLogDump;
31 return dfxLogDump;
32 }
33
DfxLogDump()34 DfxLogDump::DfxLogDump()
35 {
36 thread_ = std::make_unique<std::thread>(&DfxLogDump::TaskProcessor, this);
37 }
38
~DfxLogDump()39 DfxLogDump::~DfxLogDump()
40 {
41 {
42 std::unique_lock<std::mutex> lock(mutex_);
43 isExit_ = true;
44 cond_.notify_all();
45 }
46 if (thread_ != nullptr && thread_->joinable()) {
47 thread_->join();
48 }
49 }
50
AddNewLog(const char * level,const OHOS::HiviewDFX::HiLogLabel & label,std::string & logStr)51 static void AddNewLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, std::string &logStr)
52 {
53 struct timeval time = {};
54 (void)gettimeofday(&time, nullptr);
55 int64_t second = time.tv_sec % 60;
56 int64_t allMinute = time.tv_sec / 60;
57 int64_t minute = allMinute % 60;
58 int64_t hour = allMinute / 60 % 24;
59 int64_t mSecond = time.tv_usec / 1000;
60
61 logStr += std::to_string(hour);
62 logStr += ":";
63 logStr += std::to_string(minute);
64 logStr += ":";
65 logStr += std::to_string(second);
66 logStr += ":";
67 logStr += std::to_string(mSecond);
68 logStr += " ";
69 logStr += level;
70 logStr += " pid:";
71 logStr += std::to_string(getpid());
72 logStr += " tid:";
73 logStr += std::to_string(gettid());
74 logStr += " ";
75 logStr += label.tag;
76 logStr += ":";
77 }
78
SaveLog(const char * level,const OHOS::HiviewDFX::HiLogLabel & label,const char * fmt,...)79 void DfxLogDump::SaveLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, const char *fmt, ...)
80 {
81 std::unique_lock<std::mutex> lock(mutex_);
82 if (!isEnable_) {
83 return;
84 }
85 std::string temp = "";
86 std::string fmtStr = fmt;
87 int32_t srcPos = 0;
88 auto dtsPos = fmtStr.find("{public}", srcPos);
89 const int32_t pubLen = 8;
90 while (dtsPos != std::string::npos) {
91 temp += fmtStr.substr(srcPos, dtsPos - srcPos);
92 srcPos = static_cast<int32_t>(dtsPos) + pubLen;
93 dtsPos = fmtStr.find("{public}", srcPos);
94 }
95 temp += fmtStr.substr(srcPos);
96
97 va_list ap;
98 va_start(ap, fmt);
99 constexpr uint8_t maxLogLen = 255;
100 char logBuf[maxLogLen];
101 auto ret = vsnprintf_s(logBuf, maxLogLen, maxLogLen - 1, temp.c_str(), ap);
102 va_end(ap);
103
104 AddNewLog(level, label, logString_);
105 if (ret < 0) {
106 logString_ += "dump log error";
107 } else {
108 logString_ += logBuf;
109 }
110 logString_ += "\n";
111 lineCount_++;
112 if (lineCount_ >= FILE_LINE_MAX) {
113 cond_.notify_all();
114 }
115 }
116
UpdateCheckEnable()117 void DfxLogDump::UpdateCheckEnable()
118 {
119 std::string file = "/data/media/log/check.config";
120 std::ofstream ofStream(file);
121 if (!ofStream.is_open()) {
122 isEnable_ = false;
123 return;
124 }
125 ofStream.close();
126 isEnable_ = true;
127 }
128
TaskProcessor()129 void DfxLogDump::TaskProcessor()
130 {
131 while (true) {
132 std::string temp;
133 int32_t lineCount = 0;
134 {
135 std::unique_lock<std::mutex> lock(mutex_);
136 if (isExit_) {
137 return;
138 }
139 static constexpr int32_t timeout = 60; // every 1 minute have a log
140 cond_.wait_for(lock, std::chrono::seconds(timeout),
141 [this] {
142 UpdateCheckEnable();
143 return isExit_ || isDump_ || lineCount_ >= FILE_LINE_MAX || !logString_.empty();
144 });
145 isDump_ = false;
146 lineCount = lineCount_;
147 lineCount_ = lineCount_ >= FILE_LINE_MAX ? 0 : lineCount_;
148 swap(logString_, temp);
149 }
150
151 std::string file = "/data/media/log/";
152 file += std::to_string(getpid());
153 file += "_hilog_media.log";
154 file += std::to_string(fileCount_);
155 std::ofstream ofStream;
156 if (isNewFile_) {
157 ofStream.open(file, std::ios::out | std::ios::trunc);
158 } else {
159 ofStream.open(file, std::ios::out | std::ios::app);
160 }
161 if (!ofStream.is_open()) {
162 continue;
163 }
164 isNewFile_ = false;
165 if (lineCount >= FILE_LINE_MAX) {
166 isNewFile_ = true;
167 fileCount_++;
168 fileCount_ = fileCount_ > FILE_MAX ? 0 : fileCount_;
169 }
170 ofStream.write(temp.c_str(), temp.size());
171 ofStream.close();
172 }
173 }
174 } // namespace Media
175 } // namespace OHOS