• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 
16 #include "hiappevent_read.h"
17 
18 #include <algorithm>
19 #include <ctime>
20 #include <dirent.h>
21 #include <fstream>
22 
23 #include "hiappevent_base.h"
24 #include "hilog/log.h"
25 
26 using namespace std;
27 
28 namespace OHOS {
29 namespace HiviewDFX {
30 namespace {
31     constexpr HiLogLabel LABEL = {LOG_CORE, HIAPPEVENT_DOMAIN, "HiAppEvent_read"};
32     constexpr int FORMAT_TZ_SIZE = 9;
33     constexpr int MAX_LOG_COUNT = 1000;
34     constexpr int MILLI_TO_MICRO = 1000;
35     // same as definition in hiappevent_write.cpp
36     constexpr char APP_EVENT_DIR[] = "/hiappevent/";
37     // Date format of time stamp: YYYYmmdd, eg. 20140510
38     constexpr char DATE_FORMAT[] = "%Y%m%d";
39     // the default value of the beginTimestamp/endTimeStamp
40     // is -1LL
41     constexpr TimeStampVarType INVALID_TIMESTAMP = -1LL;
42     // The count of the regex matched results is always more
43     // than one and all results except the first one are the matched
44     // results we want, so the total count is 2 and 1 is the right
45     // index
46     constexpr smatch::size_type REGEX_MATCHED_RESULTS_COUNT = 2;
47     constexpr smatch::size_type REGEX_MATCHED_RESULT_INDEX = 1;
48     // Pattern for parsing the timestamp in the name of log files
49     // eg. 20140510
50     const regex TIME_STAMP_REGEX_PATTERN(".*_(.{8})\\..*");
51     // Pattern for reading the timestamp from the
52     // persisted log record, eg. 1626266996728
53     const regex MATCHED_LOG_REGEX_PATTERN(".*\"time_\":([0-9]{13}).*");
54 } // __UNIQUE_NAME_
55 
Instance()56 LogAssistant& LogAssistant::Instance()
57 {
58     static LogAssistant assistant;
59     return assistant;
60 }
61 
LogAssistant()62 LogAssistant::LogAssistant()
63     : logPersistDir(""),
64     realTimeLogUpdateListener(nullptr),
65     historyLogPulledListener(nullptr)
66 {}
67 
~LogAssistant()68 LogAssistant::~LogAssistant()
69 {
70     this->RemoveAllListeners();
71 }
72 
73 // A util method to find the matched result by the input
74 // pattern
FindMatchedRegex(const string & origin,const regex & regex)75 string LogAssistant::FindMatchedRegex(const string& origin, const regex& regex)
76 {
77     smatch regexMatchedResult;
78     if (std::regex_match(origin, regexMatchedResult, regex)) {
79         if (regexMatchedResult.size() == REGEX_MATCHED_RESULTS_COUNT) {
80             return regexMatchedResult[REGEX_MATCHED_RESULT_INDEX].str();
81         }
82     }
83     return string();
84 }
85 
86 // Use regex to parse the timestamp from each persisted event log record
ParseLogLineTime(const string & line)87 string LogAssistant::ParseLogLineTime(const string& line)
88 {
89     return FindMatchedRegex(line, MATCHED_LOG_REGEX_PATTERN);
90 }
91 
CheckMatchedLogLine(const string & logTimeStamp,TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp)92 bool LogAssistant::CheckMatchedLogLine(const string& logTimeStamp,
93     TimeStampVarType beginTimeStamp, TimeStampVarType endTimeStamp)
94 {
95     // Comparing the timestamp value in the persited log record with
96     // the timestamp from libjvmtiagent calling
97     return ((beginTimeStamp == INVALID_TIMESTAMP) ||
98         logTimeStamp >= to_string(beginTimeStamp)) &&
99         ((endTimeStamp == INVALID_TIMESTAMP) ||
100         logTimeStamp <= to_string(endTimeStamp));
101 }
102 
103 // Read the single log file and then find out all matched event record
ParseSingFileLogs(vector<string> & logs,const string & fileName,TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp,int count)104 void LogAssistant::ParseSingFileLogs(vector<string>& logs,
105     const string& fileName, TimeStampVarType beginTimeStamp,
106     TimeStampVarType endTimeStamp, int count)
107 {
108     ifstream fin(logPersistDir + string(APP_EVENT_DIR) + fileName);
109     if (!fin) {
110         HiLog::Error(LABEL, "single log file read failed.");
111         return;
112     }
113     string currentLine;
114     vector<string> currentFileLogs;
115     while (fin >> currentLine) {
116         string currentTimeStamp = ParseLogLineTime(currentLine);
117         if (CheckMatchedLogLine(currentTimeStamp, beginTimeStamp, endTimeStamp)) {
118             currentFileLogs.emplace_back(currentLine);
119         }
120     }
121     int logsSize = static_cast<int>(logs.size());
122     int currentFileLogSize = static_cast<int>(currentFileLogs.size());
123     if ((logsSize + currentFileLogSize) > count) {
124         logs.insert(logs.end(), currentFileLogs.rbegin(), currentFileLogs.rbegin() +
125             count - logsSize);
126     } else {
127         logs.insert(logs.end(), currentFileLogs.rbegin(), currentFileLogs.rend());
128     }
129 }
130 
ParseAllHistoryLogs(vector<string> & logs,const vector<string> & logFiles,TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp,int count)131 void LogAssistant::ParseAllHistoryLogs(vector<string>& logs,
132     const vector<string>& logFiles, TimeStampVarType beginTimeStamp,
133     TimeStampVarType endTimeStamp, int count)
134 {
135     logs.clear();
136     // Read the matched log files one by one
137     for (auto &logFileName : logFiles) {
138         ParseSingFileLogs(logs, logFileName, beginTimeStamp,
139             endTimeStamp, count);
140         int logSize = static_cast<int>(logs.size());
141         if (logSize >= count) {
142             break;
143         }
144     }
145 }
146 
ParseLogFileTimeStamp(const string & fileName)147 string LogAssistant::ParseLogFileTimeStamp(const string& fileName)
148 {
149     return FindMatchedRegex(fileName, TIME_STAMP_REGEX_PATTERN);
150 }
151 
TranslateLongToFormattedTimeStamp(TimeStampVarType timeStamp)152 string LogAssistant::TranslateLongToFormattedTimeStamp(TimeStampVarType timeStamp)
153 {
154     time_t ftt = (time_t)(timeStamp / MILLI_TO_MICRO);
155     struct tm tmLocal;
156     if (localtime_r(&ftt, &tmLocal) == nullptr) {
157         HiLog::Error(LABEL, "failed to get local time.");
158         return string();
159     }
160     char formatTz[FORMAT_TZ_SIZE] = {0};
161     if (strftime(formatTz, sizeof(formatTz), DATE_FORMAT, &tmLocal) == 0) {
162         return string();
163     }
164     return string(formatTz);
165 }
166 
167 /**
168  * Check whether the log file contains logs whose timestamp is between beginTimeStamp
169  * and endTimeStamp or not
170  */
IsMatchedLogFile(const string & fileName,TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp)171 bool LogAssistant::IsMatchedLogFile(const string& fileName, TimeStampVarType beginTimeStamp,
172     TimeStampVarType endTimeStamp)
173 {
174     string logFileTimeStamp = ParseLogFileTimeStamp(fileName);
175     if (logFileTimeStamp.empty()) {
176         // The name of this log file isn't standard, so we ignore it directly
177         return false;
178     }
179     if (beginTimeStamp == INVALID_TIMESTAMP && endTimeStamp == INVALID_TIMESTAMP) {
180         return true;
181     } else if (beginTimeStamp == INVALID_TIMESTAMP) {
182         return logFileTimeStamp <= TranslateLongToFormattedTimeStamp(endTimeStamp);
183     } else if (endTimeStamp == INVALID_TIMESTAMP) {
184         return logFileTimeStamp >= TranslateLongToFormattedTimeStamp(beginTimeStamp);
185     } else {
186         return logFileTimeStamp >= TranslateLongToFormattedTimeStamp(beginTimeStamp) &&
187             logFileTimeStamp <= TranslateLongToFormattedTimeStamp(endTimeStamp);
188     }
189 }
190 
191 /**
192  * Find out all macthed log files by comparing the parsed timestamp from file name with
193  * the beginTimeStamp/endTimeStamp
194  */
AllMatchedLogFiles(vector<string> & logFiles,TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp)195 void LogAssistant::AllMatchedLogFiles(vector<string>& logFiles, TimeStampVarType beginTimeStamp,
196     TimeStampVarType endTimeStamp)
197 {
198     logFiles.clear();
199     DIR* dir = opendir((logPersistDir + APP_EVENT_DIR).c_str());
200     if (dir == nullptr) {
201         HiLog::Error(LABEL, "log persisted directory opened failed.");
202         return;
203     }
204     struct dirent* ent;
205     while ((ent = readdir(dir))) {
206         if (IsMatchedLogFile(std::string(ent->d_name), beginTimeStamp, endTimeStamp)) {
207             logFiles.emplace_back(ent->d_name);
208         }
209     }
210     if (!logFiles.empty()) {
211         // Sort all the matched log files in descending order
212         sort(logFiles.begin(),
213             logFiles.end(),
214             [] (const string& file1, const string& file2)->bool {
215                 return file1 > file2;
216             });
217     }
218     closedir(dir);
219 }
220 
ReadHistoryLogFromPersistFile(vector<string> & historyLogs,TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp,int count)221 void LogAssistant::ReadHistoryLogFromPersistFile(vector<string>& historyLogs,
222     TimeStampVarType beginTimeStamp, TimeStampVarType endTimeStamp,
223     int count)
224 {
225     historyLogs.clear();
226     if (!logPersistDir.empty()) {
227         vector<string> logFiles;
228         AllMatchedLogFiles(logFiles, beginTimeStamp, endTimeStamp);
229         if (logFiles.size() > 0) {
230             ParseAllHistoryLogs(historyLogs, logFiles, beginTimeStamp,
231                 endTimeStamp, count);
232         }
233     }
234 }
235 
UpdateHiAppEventLogDir(const std::string & dir)236 void LogAssistant::UpdateHiAppEventLogDir(const std::string& dir)
237 {
238     logPersistDir = dir;
239 }
240 
PullEventHistoryLog(TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp,int count)241 void LogAssistant::PullEventHistoryLog(TimeStampVarType beginTimeStamp,
242     TimeStampVarType endTimeStamp, int count)
243 {
244     if (count < 0) {
245         count = MAX_LOG_COUNT;
246     }
247     vector<string> historyLogs;
248     historyLogs.reserve(static_cast<unsigned int>(count));
249     HiLog::Debug(LABEL, "log capacity set to %{public}d", count);
250     ReadHistoryLogFromPersistFile(historyLogs, beginTimeStamp, endTimeStamp, count);
251     // Sort all the matched logs in ascending order
252     sort(historyLogs.begin(),
253         historyLogs.end(),
254         [] (const string& log1, const string& log2)->bool {
255             return log1 < log2;
256         });
257     if (historyLogPulledListener != nullptr) {
258         historyLogPulledListener(historyLogs);
259     }
260 }
261 
RegRealTimeAppLogListener(RealTimeEventLogListener listener)262 void LogAssistant::RegRealTimeAppLogListener(RealTimeEventLogListener listener)
263 {
264     realTimeLogUpdateListener = listener;
265 }
266 
RegHistoryAppLogListener(HistoryEventLogListener listener)267 void LogAssistant::RegHistoryAppLogListener(HistoryEventLogListener listener)
268 {
269     historyLogPulledListener = listener;
270 }
271 
RemoveAllListeners()272 void LogAssistant::RemoveAllListeners()
273 {
274     realTimeLogUpdateListener = nullptr;
275     historyLogPulledListener = nullptr;
276 }
277 
RealTimeAppLogUpdate(const string & realTimeLog)278 void LogAssistant::RealTimeAppLogUpdate(const string& realTimeLog)
279 {
280     if (realTimeLogUpdateListener != nullptr) {
281         realTimeLogUpdateListener(realTimeLog);
282     }
283 }
284 } // namespace HiviewDFX
285 } // namespace OHOS
286 
RegRealTimeAppLogListener(RealTimeEventLogListener listener)287 void RegRealTimeAppLogListener(RealTimeEventLogListener listener)
288 {
289     OHOS::HiviewDFX::LogAssistant::Instance().RegRealTimeAppLogListener(listener);
290 }
291 
RegHistoryAppLogListener(HistoryEventLogListener listener)292 void RegHistoryAppLogListener(HistoryEventLogListener listener)
293 {
294     OHOS::HiviewDFX::LogAssistant::Instance().RegHistoryAppLogListener(listener);
295 }
296 
RemoveAllListeners()297 void RemoveAllListeners()
298 {
299     OHOS::HiviewDFX::LogAssistant::Instance().RemoveAllListeners();
300 }
301 
RealTimeAppLogUpdate(const string & realTimeLog)302 void RealTimeAppLogUpdate(const string& realTimeLog)
303 {
304     OHOS::HiviewDFX::LogAssistant::Instance().RealTimeAppLogUpdate(realTimeLog);
305 }
306 
UpdateHiAppEventLogDir(const string & path)307 void UpdateHiAppEventLogDir(const string& path)
308 {
309     OHOS::HiviewDFX::LogAssistant::Instance().UpdateHiAppEventLogDir(path);
310 }
311 
PullEventHistoryLog(TimeStampVarType beginTimeStamp,TimeStampVarType endTimeStamp,int count)312 void PullEventHistoryLog(TimeStampVarType beginTimeStamp,
313     TimeStampVarType endTimeStamp, int count)
314 {
315     OHOS::HiviewDFX::LogAssistant::Instance().PullEventHistoryLog(beginTimeStamp,
316         endTimeStamp, count);
317 }
318