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