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
35 #include "event_log_action.h"
36 #include "event_logger_config.h"
37 namespace OHOS {
38 namespace HiviewDFX {
39 REGISTER(EventLogger);
40 DEFINE_LOG_LABEL(0xD002D01, "EventLogger");
41
OnEvent(std::shared_ptr<Event> & onEvent)42 bool EventLogger::OnEvent(std::shared_ptr<Event> &onEvent)
43 {
44 if (onEvent == nullptr) {
45 HIVIEW_LOGE("event == nullptr");
46 return false;
47 }
48
49 auto sysEvent = Event::DownCastTo<SysEvent>(onEvent);
50 HIVIEW_LOGI("event coming! id:0x%{public}x, eventName:%{public}s",
51 sysEvent->eventId_, sysEvent->eventName_.c_str());
52 HIVIEW_LOGI("event jsonExtraInfo is %{public}s", sysEvent->jsonExtraInfo_.c_str());
53
54 EventLoggerConfig::EventLoggerConfigData configOut;
55 auto logConfig = std::make_unique<EventLoggerConfig>();
56 bool existence = logConfig->FindConfigLine(sysEvent->eventId_, sysEvent->eventName_, configOut);
57 if (!existence) {
58 HIVIEW_LOGE("event: id:0x%{public}x, eventName:%{public}s does not exist in the EventLoggerConfig",
59 sysEvent->eventId_, sysEvent->eventName_.c_str());
60 PostEvent(sysEvent);
61 return false;
62 }
63
64 sysEvent->eventName_ = configOut.name;
65 sysEvent->SetValue("eventLog_action", configOut.action);
66 sysEvent->SetValue("eventLog_interval", configOut.interval);
67 StartLogCollect(sysEvent);
68
69 PostEvent(sysEvent);
70 return true;
71 }
72
StartLogCollect(std::shared_ptr<SysEvent> event)73 void EventLogger::StartLogCollect(std::shared_ptr<SysEvent> event)
74 {
75 HIVIEW_LOGI("event: id:0x%{public}x, eventName:%{public}s called.",
76 event->eventId_, event->eventName_.c_str());
77 if (!JudgmentRateLimiting(event)) {
78 return;
79 }
80
81 std::string idStr = event->eventName_.empty() ? std::to_string(event->eventId_) : event->eventName_;
82 auto timeStr = std::to_string(event->happenTime_);
83 uint64_t logTime = std::time(nullptr);
84 std::string logFile = idStr + "-" + GetFormatTime(logTime) + ".log";
85
86 int fd = logStore_->CreateLogFile(logFile);
87 if (fd < 0) {
88 HIVIEW_LOGE("create log file %{public}s failed, %{public}d", logFile.c_str(), fd);
89 return;
90 }
91 WriteCommonHead(fd, event);
92 auto eventLogAction = std::make_unique<EventLogAction>(fd, event);
93 eventLogAction->Init();
94 eventLogAction->CaptureAction();
95 close(fd);
96 UpdateDB(event, logFile);
97 }
98
PostEvent(std::shared_ptr<SysEvent> event)99 bool EventLogger::PostEvent(std::shared_ptr<SysEvent> event)
100 {
101 auto eventPtr = std::make_shared<SysEvent>(*(event.get()));
102 GetHiviewContext()->PostUnorderedEvent(shared_from_this(), eventPtr);
103 return true;
104 }
105
WriteCommonHead(int fd,std::shared_ptr<SysEvent> event)106 bool EventLogger::WriteCommonHead(int fd, std::shared_ptr<SysEvent> event)
107 {
108 long pid = event->GetEventIntValue("PID");
109 pid = pid ? pid : event->GetPid();
110 long uid = event->GetEventIntValue("UID");
111 uid = uid ? uid : event->GetUid();
112 FileUtil::SaveStringToFd(fd, event->eventName_ + "\n");
113 std::string str = "PID = " + std::to_string(pid);
114 FileUtil::SaveStringToFd(fd, str + "\n");
115 str = "UID = " + std::to_string(uid);
116 FileUtil::SaveStringToFd(fd, str + "\n");
117 event->GetEventValue("PACKAGE_NAME");
118 event->GetEventValue("PROCESS_NAME");
119 event->GetEventValue("PLATFORM");
120 event->SetEventValue("MSG", StringUtil::ReplaceStr(event->GetEventValue("MSG"), "\\n", "\n"));
121 event->GetEventValue("MSG");
122
123 std::map<std::string, std::string> eventPairs = event->GetKeyValuePairs();
124 HIVIEW_LOGD("KeyValuePairs num is %{public}d", eventPairs.size());
125 for (auto tmp : eventPairs) {
126 HIVIEW_LOGD("KeyValuePairs %{public}s , %{public}s", tmp.first.c_str(), tmp.second.c_str());
127 std::string str = tmp.first + " = " + tmp.second + "\n";
128 FileUtil::SaveStringToFd(fd, str);
129 }
130 return true;
131 }
132
JudgmentRateLimiting(std::shared_ptr<SysEvent> event)133 bool EventLogger::JudgmentRateLimiting(std::shared_ptr<SysEvent> event)
134 {
135 auto interval = event->GetIntValue("eventLog_interval");
136 if (interval == 0) {
137 return true;
138 }
139
140 long pid = event->GetEventIntValue("PID");
141 pid = pid ? pid : event->GetPid();
142 std::string eventName = event->eventName_;
143 std::string eventPid = std::to_string(pid);
144
145 std::time_t now = std::time(0);
146 for (auto it = eventTagTime_.begin(); it != eventTagTime_.end();) {
147 if (it->first.find(eventName) != it->first.npos) {
148 if ((now - it->second) >= interval) {
149 it = eventTagTime_.erase(it);
150 continue;
151 }
152 }
153 ++it;
154 }
155
156 std::string tagTimeName = eventName + eventPid;
157 auto it = eventTagTime_.find(tagTimeName);
158 if (it != eventTagTime_.end()) {
159 if ((now - it->second) < interval) {
160 HIVIEW_LOGE("event: id:0x%{public}d, eventName:%{public}s pid:%{public}s. \
161 interval:%{public}ld There's not enough interval",
162 event->eventId_, eventName.c_str(), eventPid.c_str(), interval);
163 return false;
164 }
165 }
166 eventTagTime_[tagTimeName] = now;
167 HIVIEW_LOGI("event: id:0x%{public}d, eventName:%{public}s pid:%{public}s. \
168 interval:%{public}ld normal interval",
169 event->eventId_, eventName.c_str(), eventPid.c_str(), interval);
170 return true;
171 }
172
GetFormatTime(uint64_t timestamp) const173 std::string EventLogger::GetFormatTime(uint64_t timestamp) const
174 {
175 struct tm tm;
176 time_t ts;
177 /* 20: the length of 'YYYYmmddHHMMSS' */
178 int strLen = 20;
179 ts = timestamp;
180 localtime_r(&ts, &tm);
181 char buf[strLen];
182
183 (void)memset_s(buf, strLen, 0, strLen);
184 strftime(buf, strLen - 1, "%Y%m%d%H%M%S", &tm);
185 return std::string(buf, strlen(buf));
186 }
187
UpdateDB(std::shared_ptr<SysEvent> event,std::string logFile)188 bool EventLogger::UpdateDB(std::shared_ptr<SysEvent> event, std::string logFile)
189 {
190 HIVIEW_LOGI("call");
191 EventStore::SysEventQuery eventQuery = EventStore::SysEventDao::BuildQuery();
192 EventStore::ResultSet set = eventQuery.Select( {EventStore::EventCol::TS} )
193 .Where(EventStore::EventCol::TS, EventStore::Op::EQ, static_cast<int64_t>(event->happenTime_))
194 .And(EventStore::EventCol::DOMAIN, EventStore::Op::EQ, event->domain_)
195 .And(EventStore::EventCol::NAME, EventStore::Op::EQ, event->eventName_)
196 .Execute();
197 if (set.GetErrCode() != 0) {
198 HIVIEW_LOGE("failed to get db, error:%{public}d.", set.GetErrCode());
199 return false;
200 }
201 if (set.HasNext()) {
202 auto record = set.Next();
203 if (record->GetSeq() == event->GetSeq()) {
204 HIVIEW_LOGI("Seq match success.");
205 if (logFile == "nolog") {
206 HIVIEW_LOGI("set info_ with nolog into db.");
207 event->SetEventValue(EventStore::EventCol::INFO, "nolog", false);
208 } else {
209 auto logPath = R"~(logPath:)~" + LOGGER_EVENT_LOG_PATH + "/" + logFile;
210 event->SetEventValue(EventStore::EventCol::INFO, logPath, true);
211 }
212
213 auto retCode = EventStore::SysEventDao::Update(event, false);
214 if (retCode == 0) {
215 return true;
216 }
217 }
218 }
219 HIVIEW_LOGE("eventLog LogPath update to DB failed!");
220 return false;
221 }
222
OnLoad()223 void EventLogger::OnLoad()
224 {
225 HIVIEW_LOGI("EventLogger OnLoad.");
226 SetName("EventLogger");
227 SetVersion("1.0");
228 logStore_->SetMaxSize(MAX_FOLDER_SIZE);
229 logStore_->SetMinKeepingFileNumber(MAX_FILE_NUM);
230 logStore_->Init();
231 std::shared_ptr<EventLoop> tmp = GetWorkLoop();
232 tmp->AddFileDescriptorEventCallback("EventLoggerFd",
233 std::static_pointer_cast<EventLogger>(shared_from_this()));
234 }
235
OnUnload()236 void EventLogger::OnUnload()
237 {
238 HIVIEW_LOGD("called");
239 }
240
CanProcessEvent(std::shared_ptr<Event> event)241 bool EventLogger::CanProcessEvent(std::shared_ptr<Event> event)
242 {
243 if (event == nullptr) {
244 return false;
245 }
246 if (event->eventId_ > EVENT_MAX_ID) {
247 return false;
248 }
249 return true;
250 }
251
CreateAndPublishEvent(std::string & dirPath,std::string & fileName)252 void EventLogger::CreateAndPublishEvent(std::string& dirPath, std::string& fileName)
253 {
254 HIVIEW_LOGD("called");
255 std::shared_ptr<Plugin> sysEventSourcePlugin = GetHiviewContext()->GetPluginByName("SysEventSource");
256 std::shared_ptr<EventSource> sysEventSource = std::static_pointer_cast<EventSource>(sysEventSourcePlugin);
257 if (dirPath == MONITOR_STACK_LOG_PATH) {
258 uint8_t count = 0;
259 for (auto& i : MONITOR_STACK_FLIE_NAME) {
260 if (fileName.find(i) != fileName.npos) {
261 ++count;
262 break;
263 }
264 }
265
266 if (count == 0) {
267 return;
268 }
269
270 SysEventCreator eventCreator("RELIABILITY", "STACK", SysEventCreator::FAULT);
271 std::shared_ptr<SysEvent> event = std::make_shared<SysEvent>("eventLogger",
272 static_cast<PipelineEventProducer *>(sysEventSource.get()), eventCreator);
273 event->domain_ = "RELIABILITY";
274 event->SetEventValue("domain_", "RELIABILITY");
275 event->eventName_ = "STACK";
276 event->SetEventValue("name_", "STACK");
277
278 std::string logPath = dirPath + "/" + fileName;
279 if (!FileUtil::FileExists(logPath)) {
280 HIVIEW_LOGE("file %{public}s not exist", logPath.c_str());
281 }
282 std::string tmpStr = R"~(logPath:)~" + logPath;
283 event->SetEventValue(EventStore::EventCol::INFO, tmpStr);
284 sysEventSource->PublishPipelineEvent(event);
285 }
286 }
287
OnFileDescriptorEvent(int fd,int type)288 bool EventLogger::OnFileDescriptorEvent(int fd, int type)
289 {
290 HIVIEW_LOGD("fd:%{public}d, type:%{public}d, inotifyFd_:%{public}d.\n", fd, type, inotifyFd_);
291 const int bufSize = 2048;
292 char buffer[bufSize] = {0};
293 char *offset = nullptr;
294 struct inotify_event *event = nullptr;
295 if (inotifyFd_ < 0) {
296 HIVIEW_LOGE("Invalid inotify fd:%{public}d", inotifyFd_);
297 return false;
298 }
299 int len = read(inotifyFd_, buffer, bufSize);
300 if (len < 0) {
301 HIVIEW_LOGE("failed to read event");
302 return false;
303 }
304
305 offset = buffer;
306 event = (struct inotify_event *)buffer;
307 while ((reinterpret_cast<char *>(event) - buffer) < len) {
308 const auto& it = fileMap_.find(event->wd);
309 if (it == fileMap_.end()) {
310 continue;
311 }
312
313 if (event->name[event->len - 1] != '\0') {
314 event->name[event->len - 1] = '\0';
315 }
316 std::string fileName = std::string(event->name);
317 CreateAndPublishEvent(it->second, fileName);
318
319 int tmpLen = sizeof(struct inotify_event) + event->len;
320 event = (struct inotify_event *)(offset + tmpLen);
321 offset += tmpLen;
322 }
323 return true;
324 }
325
GetPollFd()326 int32_t EventLogger::GetPollFd()
327 {
328 HIVIEW_LOGD("call");
329 if (inotifyFd_ > 0) {
330 return inotifyFd_;
331 }
332
333 inotifyFd_ = inotify_init();
334 if (inotifyFd_ == -1) {
335 HIVIEW_LOGE("failed to init inotify: %s.\n", strerror(errno));
336 return -1;
337 }
338
339 for (const std::string& i : MONITOR_LOG_PATH) {
340 int wd = inotify_add_watch(inotifyFd_, i.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO);
341 if (wd < 0) {
342 HIVIEW_LOGE("failed to add watch entry : %s(%s).\n", strerror(errno), i.c_str());
343 continue;
344 }
345 fileMap_[wd] = i;
346 }
347
348 if (fileMap_.empty()) {
349 close(inotifyFd_);
350 inotifyFd_ = -1;
351 }
352 return inotifyFd_;
353 }
354
GetPollType()355 int32_t EventLogger::GetPollType()
356 {
357 return EPOLLIN;
358 }
359 } // namesapce HiviewDFX
360 } // namespace OHOS
361