• 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 <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