• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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