• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "log_file_writer.h"
17 
18 #include <algorithm>
19 #include <cerrno>
20 #include <chrono>
21 #include <iomanip>
22 #include <vector>
23 
24 #include "file_util.h"
25 #include "hiview_global.h"
26 #include "hiview_logger.h"
27 #include "parameter_ex.h"
28 #include "string_util.h"
29 #include "time_util.h"
30 
31 namespace OHOS {
32 namespace HiviewDFX {
33 DEFINE_LOG_TAG("HiView-LogFileWriter");
34 namespace {
35 constexpr size_t DEFAULT_FILE_INDEX = 1;
36 
GetLogFileDir()37 std::string GetLogFileDir()
38 {
39     auto& context = HiviewGlobal::GetInstance();
40     if (context == nullptr) {
41         HIVIEW_LOGE("hiview context is null");
42         return "";
43     }
44     std::string workPath = context->GetHiViewDirectory(HiviewContext::DirectoryType::WORK_DIRECTORY);
45     std::string logDir = FileUtil::IncludeTrailingPathDelimiter(workPath).append("sys_event_log");
46     if (!FileUtil::FileExists(logDir) && !FileUtil::ForceCreateDirectory(logDir, FileUtil::FILE_PERM_770)) {
47         HIVIEW_LOGE("failed to create log directory: %{public}s", logDir.c_str());
48         return "";
49     }
50     return logDir;
51 }
52 
GetOrderedLogFileList(const std::string & namePrefix,std::list<std::string> & logFileList)53 void GetOrderedLogFileList(const std::string& namePrefix, std::list<std::string>& logFileList)
54 {
55     std::vector<std::string> allFileList;
56     std::string logFileDir = GetLogFileDir();
57     FileUtil::GetDirFiles(logFileDir, allFileList);
58 
59     for (const auto& fileItem : allFileList) {
60         std::string fileName = FileUtil::ExtractFileName(fileItem);
61         if (StringUtil::StartWith(fileName, namePrefix)) {
62             logFileList.emplace_back(fileItem);
63         }
64     }
65 
66     // sort file list
67     logFileList.sort([] (const std::string& file, const std::string& nextFile) {
68         return file.size() < nextFile.size() || (file.size() == nextFile.size() && file < nextFile);
69     });
70 }
71 
BuildLogFilePath(const std::string & fileNamePrefix,size_t index)72 std::string BuildLogFilePath(const std::string& fileNamePrefix, size_t index)
73 {
74     std::string fileName = fileNamePrefix;
75     fileName.append("_").append(std::to_string(index));
76     std::string filePath = FileUtil::IncludeTrailingPathDelimiter(GetLogFileDir()) + fileName;
77     HIVIEW_LOGD("create new log file with name: %{public}s", fileName.c_str());
78     return filePath;
79 }
80 
CloseFileStream(std::ofstream & fileStream)81 void CloseFileStream(std::ofstream& fileStream)
82 {
83     if (fileStream.is_open()) {
84         fileStream.close();
85     }
86 }
87 
ParseLogFileIndexFromPath(const std::string & filePath)88 size_t ParseLogFileIndexFromPath(const std::string& filePath)
89 {
90     if (filePath.empty()) {
91         return DEFAULT_FILE_INDEX;
92     }
93     size_t lastUnderlineIndex = filePath.find_last_of("_");
94     if (lastUnderlineIndex == std::string::npos) {
95         HIVIEW_LOGE("name of %{public}s is invalid", FileUtil::ExtractFileName(filePath).c_str());
96         return DEFAULT_FILE_INDEX;
97     }
98     std::string indexStr = filePath.substr(++lastUnderlineIndex);
99     size_t index = DEFAULT_FILE_INDEX;
100     StringUtil::ConvertStringTo(indexStr, index);
101     return index;
102 }
103 }
104 
LogFileWriter(const LogStrategy & strategy)105 LogFileWriter::LogFileWriter(const LogStrategy& strategy)
106 {
107     InitByStrategy(strategy);
108 }
109 
~LogFileWriter()110 LogFileWriter::~LogFileWriter()
111 {
112     CloseFileStream(logFileStream_);
113 }
114 
ResetLogFileStreamByFileIndex(size_t fileIndex)115 void LogFileWriter::ResetLogFileStreamByFileIndex(size_t fileIndex)
116 {
117     curFileIndex_ = fileIndex;
118 
119     CloseFileStream(logFileStream_);
120     std::string logFilePath = BuildLogFilePath(logStrategy_.fileNamePrefix, curFileIndex_);
121     logFileStream_.open(logFilePath, std::ios::app);
122     if (logFileStream_.is_open()) {
123         curFileSize_ = FileUtil::GetFileSize(logFilePath);
124     }
125 }
126 
InitByStrategy(const LogStrategy & strategy)127 void LogFileWriter::InitByStrategy(const LogStrategy& strategy)
128 {
129     logStrategy_ = strategy;
130 
131     std::list<std::string> logFileList;
132     GetOrderedLogFileList(logStrategy_.fileNamePrefix, logFileList);
133     if (logFileList.empty()) {
134         ResetLogFileStreamByFileIndex(DEFAULT_FILE_INDEX);
135         return;
136     }
137 
138     ResetLogFileStreamByFileIndex(ParseLogFileIndexFromPath(logFileList.back()));
139 }
140 
DeleteOutNumberLogFiles()141 void LogFileWriter::DeleteOutNumberLogFiles()
142 {
143     std::list<std::string> logFileList;
144     GetOrderedLogFileList(logStrategy_.fileNamePrefix, logFileList);
145     while (logFileList.size() > logStrategy_.fileMaxCnt) {
146         auto logFilePath = logFileList.front();
147         if (!FileUtil::RemoveFile(logFilePath)) {
148             HIVIEW_LOGE("failed to delete log file: %{public}s", FileUtil::ExtractFileName(logFilePath).c_str());
149         }
150         logFileList.pop_front();
151     }
152 }
153 
Write(const std::string & content)154 void LogFileWriter::Write(const std::string& content)
155 {
156     // append formatted timestamp
157     std::string logContent = TimeUtil::TimestampFormatToDate(TimeUtil::GetSeconds(), "%Y/%m/%d %H:%M:%S");
158     logContent.append(" ").append(content);
159 
160     std::lock_guard<std::mutex> lock(writeMutex_);
161     uint64_t logContentSize = logContent.size();
162     if (curFileSize_ + logContentSize > logStrategy_.singleFileMaxSize) {
163         // exceed single file size limit
164         ResetLogFileStreamByFileIndex(curFileIndex_ + 1); // index from n to n + 1
165         DeleteOutNumberLogFiles();
166     }
167 
168     if (!logFileStream_.is_open()) {
169         HIVIEW_LOGE("%{public}s isn't opened", BuildLogFilePath(logStrategy_.fileNamePrefix, curFileIndex_).c_str());
170         return;
171     }
172     logFileStream_ << logContent << std::endl;
173     curFileSize_ += logContentSize;
174 }
175 } // namespace HiviewDFX
176 } // namespace OHOS