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 "event_logger.h"
16
17 #include "securec.h"
18
19 #include <sys/epoll.h>
20 #include <sys/inotify.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25
26 #include "common_utils.h"
27 #include "event_source.h"
28 #include "file_util.h"
29 #include "parameter_ex.h"
30 #include "plugin_factory.h"
31 #include "string_util.h"
32 #include "sys_event.h"
33 #include "sys_event_dao.h"
34 #include "time_util.h"
35
36 #include "event_log_action.h"
37 #include "event_logger_config.h"
38 #include "freeze_common.h"
39 namespace OHOS {
40 namespace HiviewDFX {
41 REGISTER(EventLogger);
42 DEFINE_LOG_LABEL(0xD002D01, "EventLogger");
IsInterestedPipelineEvent(std::shared_ptr<Event> event)43 bool EventLogger::IsInterestedPipelineEvent(std::shared_ptr<Event> event)
44 {
45 if (event == nullptr) {
46 return false;
47 }
48 if (event->eventId_ > EVENT_MAX_ID) {
49 return false;
50 }
51
52 auto sysEvent = Event::DownCastTo<SysEvent>(event);
53 if (eventLoggerConfig_.find(sysEvent->eventName_) == eventLoggerConfig_.end()) {
54 return false;
55 }
56 HIVIEW_LOGD("event time:%{public}llu jsonExtraInfo is %{public}s", TimeUtil::GetMilliseconds(),
57 sysEvent->jsonExtraInfo_.c_str());
58
59 long pid = sysEvent->GetEventIntValue("PID");
60 pid = pid ? pid : sysEvent->GetPid();
61
62 if (!CommonUtils::IsTheProcessExist(pid)) {
63 HIVIEW_LOGW("event: eventName:%{public}s, pid:%{public}d is invalid, errno:%{public}d:%{public}s",
64 sysEvent->eventName_.c_str(), pid, errno, strerror(errno));
65 return false;
66 }
67
68 EventLoggerConfig::EventLoggerConfigData& configOut = eventLoggerConfig_[sysEvent->eventName_];
69 sysEvent->eventName_ = configOut.name;
70 sysEvent->SetValue("eventLog_action", configOut.action);
71 sysEvent->SetValue("eventLog_interval", configOut.interval);
72 return true;
73 }
74
OnEvent(std::shared_ptr<Event> & onEvent)75 bool EventLogger::OnEvent(std::shared_ptr<Event> &onEvent)
76 {
77 if (onEvent == nullptr) {
78 HIVIEW_LOGE("event == nullptr");
79 return false;
80 }
81
82 auto sysEvent = Event::DownCastTo<SysEvent>(onEvent);
83 if (sysEvent->GetValue("eventLog_action").empty()) {
84 UpdateDB(sysEvent, "nolog");
85 PostEvent(sysEvent);
86 return true;
87 }
88
89 auto task = [this, sysEvent]() {
90 HIVIEW_LOGD("event time:%{public}llu jsonExtraInfo is %{public}s", TimeUtil::GetMilliseconds(),
91 sysEvent->jsonExtraInfo_.c_str());
92
93 long pid = sysEvent->GetEventIntValue("PID");
94 pid = pid ? pid : sysEvent->GetPid();
95 if (!CommonUtils::IsTheProcessExist(pid)) {
96 HIVIEW_LOGW("event: eventName:%{public}s, pid:%{public}d is invalid, errno:%{public}d:%{public}s",
97 sysEvent->eventName_.c_str(), pid, errno, strerror(errno));
98 return;
99 }
100 this->StartLogCollect(sysEvent);
101 this->PostEvent(sysEvent);
102 };
103 eventPool_->AddTask(task, "eventlogger");
104 // finish pipeline
105 onEvent->OnFinish();
106 return true;
107 }
108
StartLogCollect(std::shared_ptr<SysEvent> event)109 void EventLogger::StartLogCollect(std::shared_ptr<SysEvent> event)
110 {
111 if (!JudgmentRateLimiting(event)) {
112 return;
113 }
114
115 std::string idStr = event->eventName_.empty() ? std::to_string(event->eventId_) : event->eventName_;
116 uint64_t logTime = event->happenTime_ / TimeUtil::SEC_TO_MILLISEC;
117 int32_t pid = static_cast<int32_t>(event->GetEventIntValue("PID"));
118 pid = pid ? pid : event->GetPid();
119 std::string logFile = idStr + "-" + std::to_string(pid) + "-"
120 + TimeUtil::TimestampFormatToDate(logTime, "%Y%m%d%H%M%S") + ".log";
121 if (FileUtil::FileExists(LOGGER_EVENT_LOG_PATH + "/" + logFile)) {
122 HIVIEW_LOGW("filename: %{public}s is existed, direct use.", logFile.c_str());
123 UpdateDB(event, logFile);
124 return;
125 }
126
127 int fd = logStore_->CreateLogFile(logFile);
128 if (fd < 0) {
129 HIVIEW_LOGE("create log file %{public}s failed, %{public}d", logFile.c_str(), fd);
130 return;
131 }
132
133 auto start = TimeUtil::GetMilliseconds();
134 uint64_t startTime = start / TimeUtil::SEC_TO_MILLISEC;
135 std::string startTimeStr = TimeUtil::TimestampFormatToDate(startTime, "%Y/%m/%d-%H:%M:%S");
136 startTimeStr += ":" + std::to_string(start % TimeUtil::SEC_TO_MILLISEC);
137 FileUtil::SaveStringToFd(fd, "start time: " + startTimeStr + "\n");
138 WriteCommonHead(fd, event);
139 auto eventLogAction = std::make_unique<EventLogAction>(fd, event);
140 eventLogAction->Init();
141 eventLogAction->CaptureAction();
142 auto end = TimeUtil::GetMilliseconds();
143 std::string totalTime = "\n\nCatcher log total time is " + std::to_string(end - start) + "ms\n";
144 FileUtil::SaveStringToFd(fd, totalTime);
145 close(fd);
146 UpdateDB(event, logFile);
147 }
148
PostEvent(std::shared_ptr<SysEvent> event)149 bool EventLogger::PostEvent(std::shared_ptr<SysEvent> event)
150 {
151 auto eventPtr = std::make_shared<SysEvent>(*(event.get()));
152 GetHiviewContext()->PostUnorderedEvent(shared_from_this(), eventPtr);
153 return true;
154 }
155
WriteCommonHead(int fd,std::shared_ptr<SysEvent> event)156 bool EventLogger::WriteCommonHead(int fd, std::shared_ptr<SysEvent> event)
157 {
158 std::ostringstream headerStream;
159
160 headerStream << "DOMAIN = " << event->domain_ << std::endl;
161 headerStream << "EVENTNAME = " << event->eventName_ << std::endl;
162 uint64_t logTime = event->happenTime_ / TimeUtil::SEC_TO_MILLISEC;
163 uint64_t logTimeMs = event->happenTime_ % TimeUtil::SEC_TO_MILLISEC;
164 std::string happenTime = TimeUtil::TimestampFormatToDate(logTime, "%Y/%m/%d-%H:%M:%S");
165 headerStream << "TIMESTAMP = " << happenTime << ":" << logTimeMs << std::endl;
166 long pid = event->GetEventIntValue("PID");
167 pid = pid ? pid : event->GetPid();
168 headerStream << "PID = " << pid << std::endl;
169 long uid = event->GetEventIntValue("UID");
170 uid = uid ? uid : event->GetUid();
171 headerStream << "UID = " << uid << std::endl;
172 long tid = event->GetTid();
173 headerStream << "TID = " << tid << std::endl;
174 if (event->GetEventValue("MODULE_NAME") != "") {
175 headerStream << "MODULE_NAME = " << event->GetEventValue("MODULE_NAME") << std::endl;
176 } else {
177 headerStream << "PACKAGE_NAME = " << event->GetEventValue("PACKAGE_NAME") << std::endl;
178 }
179 headerStream << "PROCESS_NAME = " << event->GetEventValue("PROCESS_NAME") << std::endl;
180 headerStream << "eventLog_action = " << event->GetValue("eventLog_action") << std::endl;
181 headerStream << "eventLog_interval = " << event->GetValue("eventLog_interval") << std::endl;
182 event->SetEventValue("MSG", StringUtil::ReplaceStr(event->GetEventValue("MSG"), "\\n", "\n"));
183 std::string msg = event->GetEventValue("MSG");
184 headerStream << "MSG = " << msg << std::endl;
185
186 FileUtil::SaveStringToFd(fd, headerStream.str());
187 return true;
188 }
189
JudgmentRateLimiting(std::shared_ptr<SysEvent> event)190 bool EventLogger::JudgmentRateLimiting(std::shared_ptr<SysEvent> event)
191 {
192 auto interval = event->GetIntValue("eventLog_interval");
193 if (interval == 0) {
194 return true;
195 }
196
197 long pid = event->GetEventIntValue("PID");
198 pid = pid ? pid : event->GetPid();
199 std::string eventName = event->eventName_;
200 std::string eventPid = std::to_string(pid);
201
202 std::time_t now = std::time(0);
203 for (auto it = eventTagTime_.begin(); it != eventTagTime_.end();) {
204 if (it->first.find(eventName) != it->first.npos) {
205 if ((now - it->second) >= interval) {
206 it = eventTagTime_.erase(it);
207 continue;
208 }
209 }
210 ++it;
211 }
212
213 std::string tagTimeName = eventName + eventPid;
214 auto it = eventTagTime_.find(tagTimeName);
215 if (it != eventTagTime_.end()) {
216 if ((now - it->second) < interval) {
217 HIVIEW_LOGE("event: id:0x%{public}d, eventName:%{public}s pid:%{public}s. \
218 interval:%{public}ld There's not enough interval",
219 event->eventId_, eventName.c_str(), eventPid.c_str(), interval);
220 return false;
221 }
222 }
223 eventTagTime_[tagTimeName] = now;
224 HIVIEW_LOGI("event: id:0x%{public}d, eventName:%{public}s pid:%{public}s. \
225 interval:%{public}ld normal interval",
226 event->eventId_, eventName.c_str(), eventPid.c_str(), interval);
227 return true;
228 }
229
UpdateDB(std::shared_ptr<SysEvent> event,std::string logFile)230 bool EventLogger::UpdateDB(std::shared_ptr<SysEvent> event, std::string logFile)
231 {
232 auto eventQuery = EventStore::SysEventDao::BuildQuery(event->what_);
233 std::vector<std::string> selections { EventStore::EventCol::TS };
234 EventStore::ResultSet set = (*eventQuery).Select(selections)
235 .Where(EventStore::EventCol::TS, EventStore::Op::EQ, static_cast<int64_t>(event->happenTime_))
236 .And(EventStore::EventCol::DOMAIN, EventStore::Op::EQ, event->domain_)
237 .And(EventStore::EventCol::NAME, EventStore::Op::EQ, event->eventName_)
238 .Execute();
239 if (set.GetErrCode() != 0) {
240 HIVIEW_LOGE("failed to get db, error:%{public}d.", set.GetErrCode());
241 return false;
242 }
243 if (set.HasNext()) {
244 auto record = set.Next();
245 if (record->GetSeq() == event->GetSeq()) {
246 HIVIEW_LOGI("Seq match success.");
247 if (logFile == "nolog") {
248 HIVIEW_LOGI("set info_ with nolog into db.");
249 event->SetEventValue(EventStore::EventCol::INFO, "nolog", false);
250 } else {
251 auto logPath = R"~(logPath:)~" + LOGGER_EVENT_LOG_PATH + "/" + logFile;
252 event->SetEventValue(EventStore::EventCol::INFO, logPath, true);
253 }
254
255 auto retCode = EventStore::SysEventDao::Update(event, false);
256 if (retCode == 0) {
257 return true;
258 }
259 }
260 }
261 HIVIEW_LOGE("eventLog LogPath update to DB failed!");
262 return false;
263 }
264
OnLoad()265 void EventLogger::OnLoad()
266 {
267 HIVIEW_LOGI("EventLogger OnLoad.");
268 SetName("EventLogger");
269 SetVersion("1.0");
270 logStore_->SetMaxSize(MAX_FOLDER_SIZE);
271 logStore_->SetMinKeepingFileNumber(MAX_FILE_NUM);
272 logStore_->Init();
273 std::shared_ptr<EventLoop> tmp = GetWorkLoop();
274 tmp->AddFileDescriptorEventCallback("EventLoggerFd",
275 std::static_pointer_cast<EventLogger>(shared_from_this()));
276
277 EventLoggerConfig logConfig;
278 eventLoggerConfig_ = logConfig.GetConfig();
279
280 eventPool_ = std::make_unique<EventThreadPool>(maxEventPoolCount, "EventLog");
281 eventPool_->Start();
282
283 FreezeCommon freezeCommon;
284 if (!freezeCommon.Init()) {
285 HIVIEW_LOGE("FreezeCommon filed.");
286 return;
287 }
288 std::set<EventListener::EventIdRange> listenerInfo;
289 std::set<std::string> eventNames = freezeCommon.GetPrincipalStringIds();
290 auto context = GetHiviewContext();
291 if (context != nullptr) {
292 auto plugin = context->GetPluginByName("FreezeDetectorPlugin");
293 context->AddListenerInfo(Event::MessageType::SYS_EVENT, plugin, eventNames, listenerInfo);
294 context->RegisterDynamicListenerInfo(plugin);
295 }
296 }
297
OnUnload()298 void EventLogger::OnUnload()
299 {
300 HIVIEW_LOGD("called");
301 eventPool_->Stop();
302 }
303
CreateAndPublishEvent(std::string & dirPath,std::string & fileName)304 void EventLogger::CreateAndPublishEvent(std::string& dirPath, std::string& fileName)
305 {
306 uint8_t count = 0;
307 for (auto& i : MONITOR_STACK_FLIE_NAME) {
308 if (fileName.find(i) != fileName.npos) {
309 ++count;
310 break;
311 }
312 }
313
314 if (count == 0) {
315 return;
316 }
317 std::string logPath = dirPath + "/" + fileName;
318 if (!FileUtil::FileExists(logPath)) {
319 HIVIEW_LOGW("file %{public}s not exist. exit!", logPath.c_str());
320 return;
321 }
322 std::vector<std::string> values;
323 StringUtil::SplitStr(fileName, "-", values, false, false);
324 if (values.size() != 3) { // 3: type-pid-timestamp
325 HIVIEW_LOGE("failed to split stack file name %{public}s.", fileName.c_str());
326 return;
327 }
328 int32_t pid = 0;
329 StringUtil::ConvertStringTo<int32_t>(values[1], pid); // 1: pid
330
331 auto jsonStr = "{\"domain_\":\"RELIABILITY\"}";
332 auto sysEvent = std::make_shared<SysEvent>("EventLogger", nullptr, jsonStr);
333 sysEvent->SetEventValue("name_", "STACK");
334 sysEvent->SetEventValue("type_", 1);
335 sysEvent->SetEventValue("time_", TimeUtil::GetMilliseconds());
336 sysEvent->SetEventValue("pid_", getpid());
337 sysEvent->SetEventValue("tid_", gettid());
338 sysEvent->SetEventValue("uid_", getuid());
339 sysEvent->SetEventValue("tz_", TimeUtil::GetTimeZone());
340 sysEvent->SetEventValue("PID", pid);
341 sysEvent->SetEventValue("MSG", "application stack");
342 std::string tmpStr = R"~(logPath:)~" + logPath;
343 sysEvent->SetEventValue(EventStore::EventCol::INFO, tmpStr);
344 if (sysEvent->ParseJson() < 0) {
345 HIVIEW_LOGW("Failed to parse EventLogger from queryResult file name %{public}s.", fileName.c_str());
346 return;
347 }
348 auto context = GetHiviewContext();
349 if (context != nullptr) {
350 auto seq = context->GetPipelineSequenceByName("SysEventPipeline");
351 sysEvent->SetPipelineInfo("SysEventPipeline", seq);
352 sysEvent->OnContinue();
353 }
354 }
355
OnFileDescriptorEvent(int fd,int type)356 bool EventLogger::OnFileDescriptorEvent(int fd, int type)
357 {
358 HIVIEW_LOGD("fd:%{public}d, type:%{public}d, inotifyFd_:%{public}d.\n", fd, type, inotifyFd_);
359 const int bufSize = 2048;
360 char buffer[bufSize] = {0};
361 char *offset = nullptr;
362 struct inotify_event *event = nullptr;
363 if (inotifyFd_ < 0) {
364 HIVIEW_LOGE("Invalid inotify fd:%{public}d", inotifyFd_);
365 return false;
366 }
367 int len = read(inotifyFd_, buffer, bufSize);
368 if (len <= 0) {
369 HIVIEW_LOGE("failed to read event");
370 return false;
371 }
372
373 offset = buffer;
374 event = (struct inotify_event *)buffer;
375 while ((reinterpret_cast<char *>(event) - buffer + sizeof(struct inotify_event)) <
376 static_cast<uintptr_t>(len)) {
377 if ((reinterpret_cast<char *>(event) - buffer + sizeof(struct inotify_event) + event->len) >
378 static_cast<uintptr_t>(len)) {
379 break;
380 }
381
382 if (event->len != 0) {
383 const auto& it = fileMap_.find(event->wd);
384 if (it == fileMap_.end()) {
385 continue;
386 }
387
388 std::string fileName = std::string(event->name);
389 HIVIEW_LOGI("fileName: %{public}s event->mask: 0x%{public}x, event->len: %{public}d",
390 fileName.c_str(), event->mask, event->len);
391
392 if (it->second != MONITOR_STACK_LOG_PATH) {
393 return false;
394 }
395 CreateAndPublishEvent(it->second, fileName);
396 }
397
398 int tmpLen = sizeof(struct inotify_event) + event->len;
399 event = (struct inotify_event *)(offset + tmpLen);
400 offset += tmpLen;
401 }
402 return true;
403 }
404
GetPollFd()405 int32_t EventLogger::GetPollFd()
406 {
407 HIVIEW_LOGD("call");
408 if (inotifyFd_ > 0) {
409 return inotifyFd_;
410 }
411
412 inotifyFd_ = inotify_init();
413 if (inotifyFd_ == -1) {
414 HIVIEW_LOGE("failed to init inotify: %s.\n", strerror(errno));
415 return -1;
416 }
417
418 for (const std::string& i : MONITOR_LOG_PATH) {
419 int wd = inotify_add_watch(inotifyFd_, i.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO);
420 if (wd < 0) {
421 HIVIEW_LOGE("failed to add watch entry : %s(%s).\n", strerror(errno), i.c_str());
422 continue;
423 }
424 fileMap_[wd] = i;
425 }
426
427 if (fileMap_.empty()) {
428 close(inotifyFd_);
429 inotifyFd_ = -1;
430 }
431 return inotifyFd_;
432 }
433
GetPollType()434 int32_t EventLogger::GetPollType()
435 {
436 return EPOLLIN;
437 }
438 } // namesapce HiviewDFX
439 } // namespace OHOS
440