blob: ecf0e0e53cda3840924738b8e060a8ed7bae1533 [file] [log] [blame]
Jason M. Bills5e049d32018-10-19 12:59:38 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include <systemd/sd-journal.h>
17
Jason M. Bills4c099f42025-10-07 09:14:35 -070018#include <boost/algorithm/string/classification.hpp>
19#include <boost/algorithm/string/split.hpp>
Ed Tanousc3526342023-03-06 13:37:53 -080020#include <boost/asio/io_context.hpp>
Jason M. Bills5e049d32018-10-19 12:59:38 -070021#include <boost/container/flat_map.hpp>
22#include <boost/container/flat_set.hpp>
Zhikui Ren672bdfc2020-07-14 11:37:01 -070023#include <pulse_event_monitor.hpp>
24#include <sdbusplus/asio/object_server.hpp>
25#include <sel_logger.hpp>
26#include <threshold_event_monitor.hpp>
Charles Hsudbd77b92020-10-29 11:20:34 +080027#include <watchdog_event_monitor.hpp>
Jonico Eustaquio9c495c62024-07-02 16:35:14 -050028#ifdef SEL_LOGGER_ENABLE_SEL_DELETE
29#include <xyz/openbmc_project/Common/error.hpp>
30#endif
George Hung486e42e2021-04-14 20:20:42 +080031#ifdef SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS
32#include <threshold_alarm_event_monitor.hpp>
33#endif
JinFuLin7c2810b2022-12-02 13:55:28 +080034#ifdef SEL_LOGGER_MONITOR_HOST_ERROR_EVENTS
35#include <host_error_event_monitor.hpp>
36#endif
Zhikui Ren672bdfc2020-07-14 11:37:01 -070037
Jason M. Billsc4a336f2019-04-23 10:43:10 -070038#include <filesystem>
39#include <fstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070040#include <iomanip>
41#include <iostream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070042#include <sstream>
Jason M. Bills5e049d32018-10-19 12:59:38 -070043
44struct DBusInternalError final : public sdbusplus::exception_t
45{
Zhikui Ren672bdfc2020-07-14 11:37:01 -070046 const char* name() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070047 {
48 return "org.freedesktop.DBus.Error.Failed";
Patrick Williamsa138ebd2021-09-08 15:46:34 -050049 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -070050 const char* description() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070051 {
52 return "internal error";
Patrick Williamsa138ebd2021-09-08 15:46:34 -050053 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -070054 const char* what() const noexcept override
Jason M. Bills5e049d32018-10-19 12:59:38 -070055 {
56 return "org.freedesktop.DBus.Error.Failed: "
57 "internal error";
Patrick Williamsa138ebd2021-09-08 15:46:34 -050058 }
59
60 int get_errno() const noexcept override
61 {
62 return EACCES;
63 }
Jason M. Bills5e049d32018-10-19 12:59:38 -070064};
65
Lei YUe526b862020-12-03 15:41:59 +080066#ifndef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
Zhikui Ren672bdfc2020-07-14 11:37:01 -070067static bool getSELLogFiles(std::vector<std::filesystem::path>& selLogFiles)
Jason M. Billsc4a336f2019-04-23 10:43:10 -070068{
69 // Loop through the directory looking for ipmi_sel log files
Zhikui Ren672bdfc2020-07-14 11:37:01 -070070 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Billsc4a336f2019-04-23 10:43:10 -070071 std::filesystem::directory_iterator(selLogDir))
72 {
73 std::string filename = dirEnt.path().filename();
George Liu27bfd422025-08-25 14:11:32 +080074 if (filename.starts_with(selLogFilename))
Jason M. Billsc4a336f2019-04-23 10:43:10 -070075 {
76 // If we find an ipmi_sel log file, save the path
77 selLogFiles.emplace_back(selLogDir / filename);
78 }
79 }
80 // As the log files rotate, they are appended with a ".#" that is higher for
81 // the older logs. Since we don't expect more than 10 log files, we
82 // can just sort the list to get them in order from newest to oldest
83 std::sort(selLogFiles.begin(), selLogFiles.end());
84
85 return !selLogFiles.empty();
86}
87
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -060088static void saveClearSelTimestamp()
89{
90 int fd = open("/var/lib/ipmi/sel_erase_time",
91 O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
92 if (fd < 0)
93 {
94 std::cerr << "Failed to open file\n";
95 return;
96 }
97
98 if (futimens(fd, NULL) < 0)
99 {
100 std::cerr << "Failed to update SEL cleared timestamp: "
101 << std::string(strerror(errno));
102 }
103 close(fd);
104}
105
106#ifdef SEL_LOGGER_ENABLE_SEL_DELETE
107std::vector<uint16_t> nextRecordsCache;
108
109static void backupCacheToFile()
110{
111 std::ofstream nextRecordStream(selLogDir / nextRecordFilename);
112 for (auto recordIds : nextRecordsCache)
113 {
114 nextRecordStream << recordIds << '\n';
115 }
116}
117
Lei YUb07851c2025-03-13 02:36:19 +0000118uint16_t getNewRecordId()
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600119{
120 uint16_t nextRecordId = nextRecordsCache.back();
121 // Check if SEL is full
122 if (nextRecordId == selInvalidRecID)
123 {
124 return nextRecordId;
125 }
126 nextRecordsCache.pop_back();
127 if (nextRecordsCache.empty())
128 {
129 nextRecordsCache.push_back(nextRecordId + 1);
130 }
131 backupCacheToFile();
132 return nextRecordId;
133}
134
135static void initializeRecordId()
136{
137 std::ifstream nextRecordStream(selLogDir / nextRecordFilename);
138 if (!nextRecordStream.is_open())
139 {
140 std::ofstream newStream(selLogDir / nextRecordFilename);
141 newStream << '1' << '\n';
142 newStream.close();
143 nextRecordStream.open(selLogDir / nextRecordFilename);
144 }
145 std::string line;
146 while (std::getline(nextRecordStream, line))
147 {
148 nextRecordsCache.push_back(std::stoi(line));
149 }
150}
151
152void clearSelLogFiles()
153{
154 saveClearSelTimestamp();
155
156 // Clear the SEL by deleting the log files
157 std::vector<std::filesystem::path> selLogFiles;
158 if (getSELLogFiles(selLogFiles))
159 {
160 for (const std::filesystem::path& file : selLogFiles)
161 {
162 std::error_code ec;
163 std::filesystem::remove(file, ec);
164 }
165 }
166 // Reload rsyslog so it knows to start new log files
167 boost::asio::io_context io;
168 auto dbus = std::make_shared<sdbusplus::asio::connection>(io);
169 sdbusplus::message_t rsyslogReload = dbus->new_method_call(
170 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
171 "org.freedesktop.systemd1.Manager", "ReloadUnit");
172 rsyslogReload.append("rsyslog.service", "replace");
173 try
174 {
175 sdbusplus::message_t reloadResponse = dbus->call(rsyslogReload);
176 }
177 catch (const sdbusplus::exception_t& e)
178 {
179 std::cerr << e.what() << "\n";
180 }
181 // Set next record to 1
182 nextRecordsCache.clear();
183 nextRecordsCache.push_back(1);
184 // Update backup file as well
185 std::ofstream nextRecordStream(selLogDir / nextRecordFilename);
186 nextRecordStream << '1' << '\n';
187}
188
189static bool selDeleteTargetRecord(const uint16_t& targetId)
190{
191 bool targetEntryFound = false;
192 // Check if the ipmi_sel exist and save the path
193 std::vector<std::filesystem::path> selLogFiles;
194 if (!getSELLogFiles(selLogFiles))
195 {
196 return targetEntryFound;
197 }
198
199 // Go over all the ipmi_sel files to remove the entry with the target ID
200 for (const std::filesystem::path& file : selLogFiles)
201 {
202 std::fstream logStream(file, std::ios::in);
203 std::fstream tempFile(selLogDir / "temp", std::ios::out);
204 if (!logStream.is_open())
205 {
206 return targetEntryFound;
207 }
208 std::string line;
209 while (std::getline(logStream, line))
210 {
211 // Get the recordId of the current entry
212 int left = line.find(" ");
213 int right = line.find(",");
214 int recordLen = right - left;
215 std::string recordId = line.substr(left, recordLen);
216 int newRecordId = std::stoi(recordId);
217
218 if (newRecordId != targetId)
219 {
220 // Copy the entry from the original ipmi_sel to the temp file
221 tempFile << line << '\n';
222 }
223 else
224 {
225 // Skip copying the target entry
226 targetEntryFound = true;
227 }
228 }
229 logStream.close();
230 tempFile.close();
231 if (targetEntryFound)
232 {
233 std::fstream logStream(file, std::ios::out);
234 std::fstream tempFile(selLogDir / "temp", std::ios::in);
235 while (std::getline(tempFile, line))
236 {
237 logStream << line << '\n';
238 }
239 logStream.close();
240 tempFile.close();
241 std::error_code ec;
242 if (!std::filesystem::remove(selLogDir / "temp", ec))
243 {
244 std::cerr << ec.message() << std::endl;
245 }
246 break;
247 }
248 }
249 return targetEntryFound;
250}
251
Jonico Eustaquio9c495c62024-07-02 16:35:14 -0500252static void selDeleteRecord(const uint16_t& recordId)
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600253{
254 std::filesystem::file_time_type prevAddTime =
255 std::filesystem::last_write_time(selLogDir / selLogFilename);
256 bool targetEntryFound = selDeleteTargetRecord(recordId);
257
258 // Check if the Record Id was found
259 if (!targetEntryFound)
260 {
Jonico Eustaquio9c495c62024-07-02 16:35:14 -0500261 throw sdbusplus::xyz::openbmc_project::Common::Error::
262 ResourceNotFound();
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600263 }
264 // Add to next record cache for reuse
265 nextRecordsCache.push_back(recordId);
266 // Add to backup file
267 std::ofstream nextRecordStream(selLogDir / nextRecordFilename,
268 std::ios::app);
269 nextRecordStream << recordId << '\n';
270 // Keep Last Add Time the same
271 std::filesystem::last_write_time(selLogDir / selLogFilename, prevAddTime);
272 // Update Last Del Time
273 saveClearSelTimestamp();
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600274}
275#else
Jonico Eustaquio0acff272024-04-23 15:12:06 -0500276static unsigned int initializeRecordId()
Jason M. Bills5e049d32018-10-19 12:59:38 -0700277{
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700278 std::vector<std::filesystem::path> selLogFiles;
279 if (!getSELLogFiles(selLogFiles))
Jason M. Bills5e049d32018-10-19 12:59:38 -0700280 {
Jonico Eustaquio0acff272024-04-23 15:12:06 -0500281 return 0;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700282 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700283 std::ifstream logStream(selLogFiles.front());
284 if (!logStream.is_open())
Jason M. Bills5e049d32018-10-19 12:59:38 -0700285 {
Jonico Eustaquio0acff272024-04-23 15:12:06 -0500286 return 0;
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700287 }
288 std::string line;
289 std::string newestEntry;
290 while (std::getline(logStream, line))
291 {
292 newestEntry = line;
293 }
Jason M. Bills5e049d32018-10-19 12:59:38 -0700294
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700295 std::vector<std::string> newestEntryFields;
296 boost::split(newestEntryFields, newestEntry, boost::is_any_of(" ,"),
297 boost::token_compress_on);
298 if (newestEntryFields.size() < 4)
299 {
Jonico Eustaquio0acff272024-04-23 15:12:06 -0500300 return 0;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700301 }
Jason M. Billsc4a336f2019-04-23 10:43:10 -0700302
303 return std::stoul(newestEntryFields[1]);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700304}
305
Charles Boyer9f476e82021-07-29 16:33:01 -0500306static unsigned int recordId = initializeRecordId();
307
Lei YU3abf2b02025-03-21 05:51:37 +0000308unsigned int getNewRecordId()
Alexander Hansen8c023192023-09-26 09:15:18 +0200309{
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600310 if (++recordId >= selInvalidRecID)
Alexander Hansen8c023192023-09-26 09:15:18 +0200311 {
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600312 recordId = selInvalidRecID;
Alexander Hansen8c023192023-09-26 09:15:18 +0200313 }
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600314 return recordId;
Alexander Hansen8c023192023-09-26 09:15:18 +0200315}
316
Charles Boyer9f476e82021-07-29 16:33:01 -0500317void clearSelLogFiles()
318{
Alexander Hansen8c023192023-09-26 09:15:18 +0200319 saveClearSelTimestamp();
320
Charles Boyer9f476e82021-07-29 16:33:01 -0500321 // Clear the SEL by deleting the log files
322 std::vector<std::filesystem::path> selLogFiles;
323 if (getSELLogFiles(selLogFiles))
324 {
325 for (const std::filesystem::path& file : selLogFiles)
326 {
327 std::error_code ec;
328 std::filesystem::remove(file, ec);
329 }
330 }
331
Jonico Eustaquio0acff272024-04-23 15:12:06 -0500332 recordId = 0;
Charles Boyer9f476e82021-07-29 16:33:01 -0500333
334 // Reload rsyslog so it knows to start new log files
Ed Tanousc3526342023-03-06 13:37:53 -0800335 boost::asio::io_context io;
Charles Boyer9f476e82021-07-29 16:33:01 -0500336 auto dbus = std::make_shared<sdbusplus::asio::connection>(io);
Patrick Williamsccef2272022-07-22 19:26:54 -0500337 sdbusplus::message_t rsyslogReload = dbus->new_method_call(
Charles Boyer9f476e82021-07-29 16:33:01 -0500338 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
339 "org.freedesktop.systemd1.Manager", "ReloadUnit");
340 rsyslogReload.append("rsyslog.service", "replace");
341 try
342 {
Patrick Williamsccef2272022-07-22 19:26:54 -0500343 sdbusplus::message_t reloadResponse = dbus->call(rsyslogReload);
Charles Boyer9f476e82021-07-29 16:33:01 -0500344 }
Patrick Williams3f4cd972021-10-06 12:42:50 -0500345 catch (const sdbusplus::exception_t& e)
Charles Boyer9f476e82021-07-29 16:33:01 -0500346 {
347 std::cerr << e.what() << "\n";
348 }
349}
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600350#endif
Lei YUe526b862020-12-03 15:41:59 +0800351#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700352
Lei YU9916d412025-02-06 11:51:18 +0000353void toHexStr(const std::vector<uint8_t>& data, std::string& hexStr)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700354{
355 std::stringstream stream;
356 stream << std::hex << std::uppercase << std::setfill('0');
William A. Kennington III2e437262021-07-30 12:04:19 -0700357 for (int v : data)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700358 {
359 stream << std::setw(2) << v;
360 }
361 hexStr = stream.str();
362}
363
Vincent Chou92721502024-01-24 15:09:24 -0600364static uint16_t selAddOemRecord(
Konstantin Aladyshev6f5342d2023-04-19 09:23:11 +0000365 [[maybe_unused]] std::shared_ptr<sdbusplus::asio::connection> conn,
366 [[maybe_unused]] const std::string& message,
367 const std::vector<uint8_t>& selData, const uint8_t& recordType)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700368{
369 // A maximum of 13 bytes of SEL event data are allowed in an OEM record
370 if (selData.size() > selOemDataMaxSize)
371 {
372 throw std::invalid_argument("Event data too large");
373 }
374 std::string selDataStr;
375 toHexStr(selData, selDataStr);
376
Lei YUe526b862020-12-03 15:41:59 +0800377#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
Konstantin Aladyshev6f5342d2023-04-19 09:23:11 +0000378 sdbusplus::message_t AddToLog = conn->new_method_call(
379 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
380 "xyz.openbmc_project.Logging.Create", "Create");
381
382 std::string journalMsg(
383 message + ": " + " RecordType=" + std::to_string(recordType) +
384 ", GeneratorID=" + std::to_string(0) +
385 ", EventDir=" + std::to_string(0) + ", EventData=" + selDataStr);
386
Patrick Williams5a18f102024-08-16 15:20:38 -0400387 AddToLog.append(
388 journalMsg, "xyz.openbmc_project.Logging.Entry.Level.Informational",
389 std::map<std::string, std::string>(
390 {{"SENSOR_PATH", ""},
391 {"GENERATOR_ID", std::to_string(0)},
392 {"RECORD_TYPE", std::to_string(recordType)},
393 {"EVENT_DIR", std::to_string(0)},
394 {"SENSOR_DATA", selDataStr}}));
Konstantin Aladyshev6f5342d2023-04-19 09:23:11 +0000395 conn->call(AddToLog);
Vincent Chou92721502024-01-24 15:09:24 -0600396 return 0;
Lei YUe526b862020-12-03 15:41:59 +0800397#else
Jason M. Bills5e049d32018-10-19 12:59:38 -0700398 unsigned int recordId = getNewRecordId();
Jonico Eustaquio0acff272024-04-23 15:12:06 -0500399 if (recordId < selInvalidRecID)
400 {
401 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i",
402 selPriority, "MESSAGE_ID=%s", selMessageId,
403 "IPMI_SEL_RECORD_ID=%d", recordId,
404 "IPMI_SEL_RECORD_TYPE=%x", recordType,
405 "IPMI_SEL_DATA=%s", selDataStr.c_str(), NULL);
406 }
Vincent Chou92721502024-01-24 15:09:24 -0600407 return recordId;
Lei YUe526b862020-12-03 15:41:59 +0800408#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700409}
410
William A. Kennington IIId585c592021-07-30 12:10:25 -0700411int main(int, char*[])
Jason M. Bills5e049d32018-10-19 12:59:38 -0700412{
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600413#ifndef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
414#ifdef SEL_LOGGER_ENABLE_SEL_DELETE
415 initializeRecordId();
416#endif
417#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700418 // setup connection to dbus
Ed Tanousc3526342023-03-06 13:37:53 -0800419 boost::asio::io_context io;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700420 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
421
422 // IPMI SEL Object
423 conn->request_name(ipmiSelObject);
424 auto server = sdbusplus::asio::object_server(conn);
425
426 // Add SEL Interface
427 std::shared_ptr<sdbusplus::asio::dbus_interface> ifaceAddSel =
428 server.add_interface(ipmiSelPath, ipmiSelAddInterface);
429
430 // Add a new SEL entry
431 ifaceAddSel->register_method(
Konstantin Aladyshev6f5342d2023-04-19 09:23:11 +0000432 "IpmiSelAdd",
433 [conn](const std::string& message, const std::string& path,
434 const std::vector<uint8_t>& selData, const bool& assert,
435 const uint16_t& genId) {
Patrick Williams5a18f102024-08-16 15:20:38 -0400436 return selAddSystemRecord(conn, message, path, selData, assert,
437 genId);
438 });
Jason M. Bills5e049d32018-10-19 12:59:38 -0700439 // Add a new OEM SEL entry
Patrick Williams5a18f102024-08-16 15:20:38 -0400440 ifaceAddSel->register_method(
441 "IpmiSelAddOem",
442 [conn](const std::string& message, const std::vector<uint8_t>& selData,
443 const uint8_t& recordType) {
444 return selAddOemRecord(conn, message, selData, recordType);
445 });
Charles Boyer9f476e82021-07-29 16:33:01 -0500446
Charles Boyer9f476e82021-07-29 16:33:01 -0500447#ifndef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
448 // Clear SEL entries
449 ifaceAddSel->register_method("Clear", []() { clearSelLogFiles(); });
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600450#ifdef SEL_LOGGER_ENABLE_SEL_DELETE
451 // Delete a SEL entry
Jonico Eustaquio9c495c62024-07-02 16:35:14 -0500452 ifaceAddSel->register_method("SELDelete", [](const uint16_t& recordId) {
Jonico Eustaquio9fa224c2024-01-10 13:08:52 -0600453 return selDeleteRecord(recordId);
454 });
455#endif
Charles Boyer9f476e82021-07-29 16:33:01 -0500456#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700457 ifaceAddSel->initialize();
458
459#ifdef SEL_LOGGER_MONITOR_THRESHOLD_EVENTS
Patrick Williamsccef2272022-07-22 19:26:54 -0500460 sdbusplus::bus::match_t thresholdAssertMonitor =
Zhikui Ren25b26e12020-06-26 20:18:19 -0700461 startThresholdAssertMonitor(conn);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700462#endif
463
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800464#ifdef REDFISH_LOG_MONITOR_PULSE_EVENTS
Patrick Williamsccef2272022-07-22 19:26:54 -0500465 sdbusplus::bus::match_t pulseEventMonitor = startPulseEventMonitor(conn);
Nikhil Potadeafbaa092019-03-06 16:18:13 -0800466#endif
467
Charles Hsudbd77b92020-10-29 11:20:34 +0800468#ifdef SEL_LOGGER_MONITOR_WATCHDOG_EVENTS
Patrick Williamsccef2272022-07-22 19:26:54 -0500469 sdbusplus::bus::match_t watchdogEventMonitor =
Charles Hsudbd77b92020-10-29 11:20:34 +0800470 startWatchdogEventMonitor(conn);
471#endif
George Hung486e42e2021-04-14 20:20:42 +0800472
473#ifdef SEL_LOGGER_MONITOR_THRESHOLD_ALARM_EVENTS
474 startThresholdAlarmMonitor(conn);
475#endif
JinFuLin7c2810b2022-12-02 13:55:28 +0800476
477#ifdef SEL_LOGGER_MONITOR_HOST_ERROR_EVENTS
478 startHostErrorEventMonitor(conn);
479#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700480 io.run();
481
482 return 0;
483}