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 "running_status_logger.h"
17
18 #include <algorithm>
19 #include <cerrno>
20 #include <chrono>
21 #include <vector>
22
23 #include "file_util.h"
24 #include "hiview_global.h"
25 #include "logger.h"
26 #include "time_util.h"
27
28 namespace OHOS {
29 namespace HiviewDFX {
30 DEFINE_LOG_TAG("HiView-RunningStatusLogger");
31 namespace {
32 constexpr size_t BUF_SIZE = 2000;
33 char errMsg[BUF_SIZE] = { 0 };
34 }
35
Log(const std::string & logInfo)36 void RunningStatusLogger::Log(const std::string& logInfo)
37 {
38 {
39 std::lock_guard<std::mutex> lock(writingMutex);
40 logWritingTasks.emplace(logInfo, [this] (const std::string& logInfo) {
41 std::string destFile = this->GetLogWroteDestFile(logInfo);
42 HIVIEW_LOGD("writing \"%{public}s\" into %{public}s.", logInfo.c_str(), destFile.c_str());
43 if (!FileUtil::SaveStringToFile(destFile, logInfo + "\n", false)) {
44 strerror_r(errno, errMsg, BUF_SIZE);
45 HIVIEW_LOGE("failed to persist log to file, error=%{public}d, msg=%{public}s",
46 errno, errMsg);
47 }
48 this->ImmediateWrite(true);
49 });
50 if (inWriting.load(std::memory_order_acquire)) {
51 return;
52 }
53 }
54 ImmediateWrite();
55 }
56
FormatTimeStamp(bool simpleMode)57 std::string RunningStatusLogger::FormatTimeStamp(bool simpleMode)
58 {
59 time_t lt;
60 (void)time(<);
61 std::string format { simpleMode ? "%Y%m%d" : "%Y/%m/%d %H:%M:%S" };
62 return TimeUtil::TimestampFormatToDate(lt, format);
63 }
64
GenerateNewestFileName(const std::string & suffix)65 std::string RunningStatusLogger::GenerateNewestFileName(const std::string& suffix)
66 {
67 std::string newFileName = GetLogDir() + "runningstatus_" + FormatTimeStamp(true) + suffix;
68 HIVIEW_LOGD("create new log file: %{public}s.", newFileName.c_str());
69 return newFileName;
70 }
71
GetLogDir()72 std::string RunningStatusLogger::GetLogDir()
73 {
74 std::string workPath = HiviewGlobal::GetInstance()->GetHiViewDirectory(
75 HiviewContext::DirectoryType::WORK_DIRECTORY);
76 if (workPath.back() != '/') {
77 workPath = workPath + "/";
78 }
79 std::string logDestDir = workPath + "sys_event/";
80 if (!FileUtil::FileExists(logDestDir)) {
81 if (FileUtil::ForceCreateDirectory(logDestDir, FileUtil::FILE_PERM_770)) {
82 HIVIEW_LOGD("create listener log directory %{public}s succeed.", logDestDir.c_str());
83 } else {
84 logDestDir = workPath;
85 HIVIEW_LOGW("create listener log directory %{public}s failed, use default directory %{public}s.",
86 logDestDir.c_str(), workPath.c_str());
87 }
88 }
89 return logDestDir;
90 }
91
GetLogWroteDestFile(const std::string & content)92 std::string RunningStatusLogger::GetLogWroteDestFile(const std::string& content)
93 {
94 std::vector<std::string> allLogFiles;
95 FileUtil::GetDirFiles(GetLogDir(), allLogFiles);
96 if (allLogFiles.empty()) {
97 return GenerateNewestFileName("_01");
98 }
99 sort(allLogFiles.begin(), allLogFiles.end());
100 std::vector<std::string>::size_type logFileCntLimit = 10; // max count of log file exist is limited to be 10
101 if (allLogFiles.back().find(FormatTimeStamp(true)) == std::string::npos) {
102 if ((allLogFiles.size() == logFileCntLimit) && !FileUtil::RemoveFile(allLogFiles.front())) {
103 strerror_r(errno, errMsg, BUF_SIZE);
104 HIVIEW_LOGE("failed to delete oldest log file, error=%{public}d, msg=%{public}s",
105 errno, errMsg);
106 }
107 return GenerateNewestFileName("_01");
108 }
109 std::uintmax_t singleLogFileSizeLimit = 2 * 1024 * 1024; // size of each log file is limited to 2M
110 if (FileUtil::GetFileSize(allLogFiles.back()) + content.size() < singleLogFileSizeLimit) {
111 return allLogFiles.back();
112 }
113 std::string newestFileName = allLogFiles.back();
114 auto lastUnderLinePos = newestFileName.find_last_of("_");
115 int index = 0;
116 int decimal = 10;
117 while (++lastUnderLinePos < newestFileName.size()) {
118 index *= decimal;
119 index += static_cast<int>(newestFileName.at(lastUnderLinePos) - '0');
120 }
121 index += 1;
122 if ((allLogFiles.size() == logFileCntLimit) && !FileUtil::RemoveFile(allLogFiles.front())) {
123 strerror_r(errno, errMsg, BUF_SIZE);
124 HIVIEW_LOGE("failed to delete oldest log file, error=%{public}d, msg=%{public}s",
125 errno, errMsg);
126 }
127 return GenerateNewestFileName(std::string(((index < decimal) ? "_0" : "_")).append(std::to_string(index)));
128 }
129
ImmediateWrite(bool needPop)130 void RunningStatusLogger::ImmediateWrite(bool needPop)
131 {
132 this->inWriting = true;
133 LogWritingTask curTask;
134 {
135 std::lock_guard<std::mutex> lock(writingMutex);
136 if (needPop && !logWritingTasks.empty()) {
137 logWritingTasks.pop();
138 }
139 if (logWritingTasks.empty()) {
140 this->inWriting = false;
141 return;
142 }
143 curTask = logWritingTasks.front();
144 }
145 curTask.second(curTask.first);
146 }
147 } // namespace HiviewDFX
148 } // namespace OHOS