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 <malloc.h>
20 #include <sys/time.h>
21 #include "securec.h"
22
23 namespace {
24 constexpr int32_t FILE_MAX = 100;
25 constexpr int32_t FILE_LINE_MAX = 50000;
26 }
27 namespace OHOS {
28 namespace Media {
GetInstance()29 DfxLogDump &DfxLogDump::GetInstance()
30 {
31 static DfxLogDump dfxLogDump;
32 return dfxLogDump;
33 }
34
DfxLogDump()35 DfxLogDump::DfxLogDump()
36 {
37 thread_ = std::make_unique<std::thread>([this] () -> void { this->TaskProcessor(); });
38 }
39
~DfxLogDump()40 DfxLogDump::~DfxLogDump()
41 {
42 {
43 std::unique_lock<std::mutex> lock(mutex_);
44 isExit_ = true;
45 cond_.notify_all();
46 }
47 if (thread_ != nullptr && thread_->joinable()) {
48 thread_->join();
49 }
50 }
51
AddNewLog(const char * level,const OHOS::HiviewDFX::HiLogLabel & label,std::string & logStr)52 static void AddNewLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, std::string &logStr)
53 {
54 struct timeval time = {};
55 (void)gettimeofday(&time, nullptr);
56 int64_t second = time.tv_sec % 60;
57 int64_t allMinute = time.tv_sec / 60;
58 int64_t minute = allMinute % 60;
59 int64_t hour = allMinute / 60 % 24;
60 int64_t mSecond = time.tv_usec / 1000;
61
62 logStr += std::to_string(hour);
63 logStr += ":";
64 logStr += std::to_string(minute);
65 logStr += ":";
66 logStr += std::to_string(second);
67 logStr += ":";
68 logStr += std::to_string(mSecond);
69 logStr += " ";
70 logStr += level;
71 logStr += " pid:";
72 logStr += std::to_string(getpid());
73 logStr += " tid:";
74 logStr += std::to_string(gettid());
75 logStr += " ";
76 logStr += label.tag;
77 logStr += ":";
78 }
79
SaveLog(const char * level,const OHOS::HiviewDFX::HiLogLabel & label,const char * fmt,...)80 void DfxLogDump::SaveLog(const char *level, const OHOS::HiviewDFX::HiLogLabel &label, const char *fmt, ...)
81 {
82 std::unique_lock<std::mutex> lock(mutex_);
83 if (!isEnable_) {
84 return;
85 }
86 std::string temp = "";
87 std::string fmtStr = fmt;
88 int32_t srcPos = 0;
89 auto dtsPos = fmtStr.find("{public}", srcPos);
90 const int32_t pubLen = 8;
91 while (dtsPos != std::string::npos) {
92 temp += fmtStr.substr(srcPos, dtsPos - srcPos);
93 srcPos = static_cast<int32_t>(dtsPos) + pubLen;
94 dtsPos = fmtStr.find("{public}", srcPos);
95 }
96 temp += fmtStr.substr(srcPos);
97
98 va_list ap;
99 va_start(ap, fmt);
100 constexpr uint32_t maxLogLen = 1024;
101 char logBuf[maxLogLen];
102 auto ret = vsnprintf_s(logBuf, maxLogLen, maxLogLen - 1, temp.c_str(), ap);
103 va_end(ap);
104
105 AddNewLog(level, label, logString_);
106 if (ret < 0) {
107 logString_ += "dump log error";
108 } else {
109 logString_ += logBuf;
110 }
111 logString_ += "\n";
112 lineCount_++;
113 if (lineCount_ >= FILE_LINE_MAX) {
114 cond_.notify_all();
115 }
116 }
117
UpdateCheckEnable()118 void DfxLogDump::UpdateCheckEnable()
119 {
120 std::string file = "/data/test/log/check.config";
121 std::ofstream ofStream(file);
122 if (!ofStream.is_open()) {
123 isEnable_ = false;
124 return;
125 }
126 ofStream.close();
127 isEnable_ = true;
128 }
129
TaskProcessor()130 void DfxLogDump::TaskProcessor()
131 {
132 pthread_setname_np(pthread_self(), "DfxLogTask");
133 (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
134 (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
135 while (true) {
136 std::string temp;
137 int32_t lineCount = 0;
138 {
139 std::unique_lock<std::mutex> lock(mutex_);
140 if (isExit_) {
141 return;
142 }
143 static constexpr int32_t timeout = 60; // every 1 minute have a log
144 cond_.wait_for(lock, std::chrono::seconds(timeout),
145 [this] {
146 UpdateCheckEnable();
147 return isExit_ || isDump_ || lineCount_ >= FILE_LINE_MAX || !logString_.empty();
148 });
149 isDump_ = false;
150 lineCount = lineCount_;
151 lineCount_ = lineCount_ >= FILE_LINE_MAX ? 0 : lineCount_;
152 swap(logString_, temp);
153 }
154
155 std::string file = "/data/test/log/";
156 file += std::to_string(getpid());
157 file += "_hilog_media.log";
158 file += std::to_string(fileCount_);
159 std::ofstream ofStream;
160 if (isNewFile_) {
161 ofStream.open(file, std::ios::out | std::ios::trunc);
162 } else {
163 ofStream.open(file, std::ios::out | std::ios::app);
164 }
165 if (!ofStream.is_open()) {
166 continue;
167 }
168 isNewFile_ = false;
169 if (lineCount >= FILE_LINE_MAX) {
170 isNewFile_ = true;
171 fileCount_++;
172 fileCount_ = fileCount_ > FILE_MAX ? 0 : fileCount_;
173 }
174 ofStream.write(temp.c_str(), temp.size());
175 ofStream.close();
176 }
177 }
178 } // namespace Media
179 } // namespace OHOS
180