1 /*
2 * Copyright (c) 2021 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 #include "log_persister_rotator.h"
16 #include <cstdio>
17 #include <dirent.h>
18 #include <fstream>
19 #include <iostream>
20 #include <securec.h>
21 #include <sstream>
22 #include <sys/stat.h>
23 #include <sys/time.h>
24 #include <unistd.h>
25
26 constexpr uint8_t MAX_TIME_BUF_SIZE = 32;
27 constexpr uint8_t MAX_LOG_INDEX_LEN = 4;
28
29 namespace OHOS {
30 namespace HiviewDFX {
GenerateHash(const PersistRecoveryInfo & info)31 uint64_t GenerateHash(const PersistRecoveryInfo &info)
32 {
33 uint64_t ret {BASIS};
34 const char *p = (char *)&info;
35 unsigned long i = 0;
36 while (i < sizeof(PersistRecoveryInfo)) {
37 ret ^= *(p + i);
38 ret *= PRIME;
39 i++;
40 }
41 return ret;
42 }
43
GetFileNameIndex(const int index)44 std::string GetFileNameIndex(const int index)
45 {
46 char res[MAX_LOG_INDEX_LEN];
47 (void)snprintf_s(res, sizeof(res), sizeof(res) - 1, "%03d", index % MAX_LOG_FILE_NUM);
48 std::string fileNameIndex(res);
49 return fileNameIndex;
50 }
51
IsOldFile(const std::string & logName,const int index)52 bool LogPersisterRotator::IsOldFile(const std::string& logName, const int index)
53 {
54 std::string fileNameHead = m_logsPath.substr(strlen(HILOG_FILE_DIR), m_logsPath.size());
55 fileNameHead = fileNameHead + "." + GetFileNameIndex(index + 1 - m_maxLogFileNum);
56 if (logName.find(fileNameHead) == std::string::npos) {
57 return false;
58 }
59 return true;
60 }
61
62
LogPersisterRotator(const std::string & logsPath,uint32_t id,uint32_t maxFiles,const std::string & fileNameSuffix)63 LogPersisterRotator::LogPersisterRotator(const std::string& logsPath, uint32_t id, uint32_t maxFiles,
64 const std::string& fileNameSuffix)
65 : m_maxLogFileNum(maxFiles)
66 , m_logsPath(logsPath)
67 , m_fileNameSuffix(fileNameSuffix)
68 , m_id(id)
69 {
70 }
71
~LogPersisterRotator()72 LogPersisterRotator::~LogPersisterRotator()
73 {
74 m_infoFile.close();
75 remove(m_infoFilePath.c_str());
76 }
77
Init(const PersistRecoveryInfo & info,bool restore)78 int LogPersisterRotator::Init(const PersistRecoveryInfo& info, bool restore)
79 {
80 if (!m_infoFile.is_open()) {
81 if (int result = OpenInfoFile(); result != RET_SUCCESS) {
82 return result;
83 }
84 }
85
86 m_info = info;
87 SetFileIndex(m_info.index, restore);
88 UpdateRotateNumber();
89 return RET_SUCCESS;
90 }
91
OpenInfoFile()92 int LogPersisterRotator::OpenInfoFile()
93 {
94 auto lastSeparatorIdx = m_logsPath.find_last_of('/');
95 std::string parentDirPath = m_logsPath.substr(0, lastSeparatorIdx);
96 if (access(parentDirPath.c_str(), F_OK) != 0) {
97 if (errno == ENOENT) {
98 mkdir(parentDirPath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRWXG | S_IRWXO);
99 }
100 }
101 std::string infoFileName = std::string(".") + AUXILLARY_PERSISTER_PREFIX + std::to_string(m_id) + ".info";
102 m_infoFilePath = parentDirPath + "/" + infoFileName;
103 m_infoFile.open(m_infoFilePath, std::ios::binary | std::ios::out | std::ios::trunc);
104 return m_infoFile.is_open() ? RET_SUCCESS : RET_FAIL;
105 }
106
Input(const char * buf,uint32_t length)107 int LogPersisterRotator::Input(const char *buf, uint32_t length)
108 {
109 std::cout << __PRETTY_FUNCTION__
110 << " Log location: " << m_logsPath
111 << " idx: " << m_currentLogFileIdx << "/" << m_maxLogFileNum
112 << " buf: " << (void*) buf << " len: " << length
113 << " needRotate: " << (m_needRotate ? 'T' : 'F') << "\n";
114 if (length <= 0 || buf == nullptr) {
115 return ERR_LOG_PERSIST_COMPRESS_BUFFER_EXP;
116 }
117 if (m_needRotate) {
118 Rotate();
119 m_needRotate = false;
120 } else if (!m_currentLogOutput.is_open()) {
121 CreateLogFile();
122 }
123 m_currentLogOutput.write(buf, length);
124 m_currentLogOutput.flush();
125 return 0;
126 }
127
RemoveOldFile()128 void LogPersisterRotator::RemoveOldFile()
129 {
130 DIR *dir;
131 struct dirent *ent = nullptr;
132 if ((dir = opendir(HILOG_FILE_DIR)) != NULL) {
133 while ((ent = readdir(dir)) != NULL) {
134 size_t length = strlen(ent->d_name);
135 std::string pPath(ent->d_name, length);
136 if (IsOldFile(pPath, m_currentLogFileIdx)) {
137 remove((HILOG_FILE_DIR + pPath).c_str());
138 break;
139 }
140 }
141 }
142 closedir(dir);
143 }
144
Rotate()145 void LogPersisterRotator::Rotate()
146 {
147 std::cout << __PRETTY_FUNCTION__ << "\n";
148 if (m_currentLogFileIdx + 1 >= m_maxLogFileNum) {
149 RemoveOldFile();
150 }
151 m_currentLogFileIdx++;
152 CreateLogFile();
153 UpdateRotateNumber();
154 }
155
CreateLogFile()156 void LogPersisterRotator::CreateLogFile()
157 {
158 std::cout << __PRETTY_FUNCTION__ << "\n";
159 time_t tnow = time(nullptr);
160 struct tm *tmNow = localtime(&tnow);
161 char timeBuf[MAX_TIME_BUF_SIZE] = {0};
162 if (tmNow != nullptr) {
163 strftime(timeBuf, sizeof(timeBuf), "%Y%m%d-%H%M%S", tmNow);
164 }
165 std::stringstream newFile;
166 newFile << m_logsPath << "." << GetFileNameIndex(m_currentLogFileIdx) << "." << timeBuf << m_fileNameSuffix;
167 std::cout << "THE FILE NAME !!!!!!! " << newFile.str() << std::endl;
168 m_currentLogOutput.open(newFile.str(), std::ios::out | std::ios::trunc);
169 }
170
UpdateRotateNumber()171 void LogPersisterRotator::UpdateRotateNumber()
172 {
173 m_info.index = static_cast<uint32_t>(m_currentLogFileIdx);
174 WriteRecoveryInfo();
175 }
176
FinishInput()177 void LogPersisterRotator::FinishInput()
178 {
179 std::cout << __PRETTY_FUNCTION__ << "\n";
180
181 m_currentLogOutput.close();
182 m_needRotate = true;
183 }
184
SetFileIndex(uint32_t index,bool forceRotate)185 void LogPersisterRotator::SetFileIndex(uint32_t index, bool forceRotate)
186 {
187 m_currentLogOutput.close();
188 m_currentLogFileIdx = index;
189 if (forceRotate) {
190 m_needRotate = true;
191 }
192 }
193
SetInfo(const LogPersistStartMsg & pMsg,uint16_t logType,uint8_t logLevel)194 int LogPersisterRotator::SetInfo(const LogPersistStartMsg& pMsg, uint16_t logType, uint8_t logLevel)
195 {
196 m_info.msg = pMsg;
197 m_info.types = logType;
198 m_info.levels = logLevel;
199 if (strcpy_s(m_info.msg.filePath, FILE_PATH_MAX_LEN, pMsg.filePath) != 0) {
200 std::cout << "Failed to copy persister file path\n";
201 return RET_FAIL;
202 }
203 std::cout << "Saving info path=" << m_info.msg.filePath << "\n";
204 return RET_SUCCESS;
205 }
206
WriteRecoveryInfo()207 void LogPersisterRotator::WriteRecoveryInfo()
208 {
209 if (!m_infoFile.is_open()) {
210 std::cerr << "LogPersisterRotator has not been initialized!\n";
211 return;
212 }
213
214 std::cout << "Save Info file!\n";
215 uint64_t hash = GenerateHash(m_info);
216
217 m_infoFile.seekp(0);
218 m_infoFile.write(reinterpret_cast<const char*>(&m_info), sizeof(m_info));
219 m_infoFile.write(reinterpret_cast<const char*>(&hash), sizeof(hash));
220 m_infoFile.flush();
221 m_infoFile.sync();
222 }
223 } // namespace HiviewDFX
224 } // namespace OHOS
225