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 27constexpr uint8_t MAX_TIME_BUF_SIZE = 32; 28constexpr uint8_t MAX_LOG_INDEX_LEN = 4; 29 30namespace OHOS { 31namespace HiviewDFX { 32std::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 40bool 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 51LogPersisterRotator::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 57LogPersisterRotator::~LogPersisterRotator() 58{ 59 m_infoFile.close(); 60 remove(m_infoFilePath.c_str()); 61} 62 63int 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 77int 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 92int 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 ((access(m_currentLogFileName.c_str(), F_OK) != 0) || !m_currentLogOutput.is_open()) { 101 CreateLogFile(); 102 } 103 m_currentLogOutput.write(buf, length); 104 m_currentLogOutput.flush(); 105 return 0; 106} 107 108void 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 127void 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 138void 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_currentLogFileName = newFile.str(); 151 if (m_currentLogOutput.is_open()) { 152 m_currentLogOutput.close(); 153 } 154 m_currentLogOutput.open(newFile.str(), std::ios::out | std::ios::trunc); 155} 156 157void LogPersisterRotator::UpdateRotateNumber() 158{ 159 m_info.index = static_cast<uint32_t>(m_currentLogFileIdx); 160 WriteRecoveryInfo(); 161} 162 163void LogPersisterRotator::FinishInput() 164{ 165 std::cout << __PRETTY_FUNCTION__ << "\n"; 166 167 m_currentLogOutput.close(); 168 m_needRotate = true; 169} 170 171void LogPersisterRotator::SetFileIndex(uint32_t index, bool forceRotate) 172{ 173 m_currentLogOutput.close(); 174 m_currentLogFileIdx = index; 175 if (forceRotate) { 176 m_needRotate = true; 177 } 178} 179 180void LogPersisterRotator::WriteRecoveryInfo() 181{ 182 if (!m_infoFile.is_open()) { 183 std::cerr << "LogPersisterRotator has not been initialized!\n"; 184 return; 185 } 186 187 std::cout << "Save Info file!\n"; 188 uint64_t hash = GenerateHash(reinterpret_cast<char *>(&m_info), sizeof(PersistRecoveryInfo)); 189 190 m_infoFile.seekp(0); 191 m_infoFile.write(reinterpret_cast<const char*>(&m_info), sizeof(m_info)); 192 m_infoFile.write(reinterpret_cast<const char*>(&hash), sizeof(hash)); 193 m_infoFile.flush(); 194 m_infoFile.sync(); 195} 196} // namespace HiviewDFX 197} // namespace OHOS 198