xref: /openbmc/bmcweb/redfish-core/include/utils/eventlog_utils.hpp (revision dba9d6753515a21878d9e1ca61136c2a5c8db9bf)
17681b8a1SOliver Brewka // SPDX-License-Identifier: Apache-2.0
27681b8a1SOliver Brewka // SPDX-FileCopyrightText: Copyright OpenBMC Authors
37681b8a1SOliver Brewka // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
47681b8a1SOliver Brewka #pragma once
57681b8a1SOliver Brewka 
67681b8a1SOliver Brewka #include "async_resp.hpp"
77681b8a1SOliver Brewka #include "dbus_utility.hpp"
87681b8a1SOliver Brewka #include "error_messages.hpp"
99d6459e8SOliver Brewka #include "generated/enums/log_service.hpp"
107681b8a1SOliver Brewka #include "http_response.hpp"
117681b8a1SOliver Brewka #include "logging.hpp"
127681b8a1SOliver Brewka #include "registries.hpp"
137681b8a1SOliver Brewka #include "str_utility.hpp"
149d6459e8SOliver Brewka #include "utils/etag_utils.hpp"
157681b8a1SOliver Brewka #include "utils/query_param.hpp"
169d6459e8SOliver Brewka #include "utils/time_utils.hpp"
177681b8a1SOliver Brewka 
187681b8a1SOliver Brewka #include <boost/beast/http/field.hpp>
197681b8a1SOliver Brewka #include <boost/beast/http/status.hpp>
207681b8a1SOliver Brewka #include <boost/beast/http/verb.hpp>
217681b8a1SOliver Brewka #include <boost/system/linux_error.hpp>
227681b8a1SOliver Brewka #include <boost/url/format.hpp>
237681b8a1SOliver Brewka #include <boost/url/url.hpp>
247681b8a1SOliver Brewka #include <sdbusplus/message.hpp>
257681b8a1SOliver Brewka #include <sdbusplus/message/native_types.hpp>
267681b8a1SOliver Brewka #include <sdbusplus/unpack_properties.hpp>
277681b8a1SOliver Brewka 
287681b8a1SOliver Brewka #include <algorithm>
297681b8a1SOliver Brewka #include <cstddef>
307681b8a1SOliver Brewka #include <cstdint>
317681b8a1SOliver Brewka #include <cstdio>
327681b8a1SOliver Brewka #include <ctime>
337681b8a1SOliver Brewka #include <fstream>
347681b8a1SOliver Brewka #include <iomanip>
357681b8a1SOliver Brewka #include <sstream>
367681b8a1SOliver Brewka #include <string>
377681b8a1SOliver Brewka #include <utility>
387681b8a1SOliver Brewka 
397681b8a1SOliver Brewka namespace redfish
407681b8a1SOliver Brewka {
417681b8a1SOliver Brewka namespace eventlog_utils
427681b8a1SOliver Brewka {
437681b8a1SOliver Brewka 
443af76e15SOliver Brewka constexpr const char* rfSystemsStr = "Systems";
453af76e15SOliver Brewka constexpr const char* rfManagersStr = "Managers";
463af76e15SOliver Brewka 
473af76e15SOliver Brewka enum class LogServiceParent
483af76e15SOliver Brewka {
493af76e15SOliver Brewka     Systems,
503af76e15SOliver Brewka     Managers
513af76e15SOliver Brewka };
523af76e15SOliver Brewka 
533af76e15SOliver Brewka inline std::string logServiceParentToString(LogServiceParent parent)
543af76e15SOliver Brewka {
553af76e15SOliver Brewka     std::string parentStr;
563af76e15SOliver Brewka     switch (parent)
573af76e15SOliver Brewka     {
583af76e15SOliver Brewka         case LogServiceParent::Managers:
593af76e15SOliver Brewka             parentStr = rfManagersStr;
603af76e15SOliver Brewka             break;
613af76e15SOliver Brewka         case LogServiceParent::Systems:
623af76e15SOliver Brewka             parentStr = rfSystemsStr;
633af76e15SOliver Brewka             break;
643af76e15SOliver Brewka         default:
653af76e15SOliver Brewka             BMCWEB_LOG_ERROR("Unable to stringify bmcweb eventlog location");
663af76e15SOliver Brewka             break;
673af76e15SOliver Brewka     }
683af76e15SOliver Brewka     return parentStr;
693af76e15SOliver Brewka }
703af76e15SOliver Brewka 
713af76e15SOliver Brewka inline std::string_view getChildIdFromParent(LogServiceParent parent)
723af76e15SOliver Brewka {
733af76e15SOliver Brewka     std::string_view childId;
743af76e15SOliver Brewka 
753af76e15SOliver Brewka     switch (parent)
763af76e15SOliver Brewka     {
773af76e15SOliver Brewka         case LogServiceParent::Managers:
783af76e15SOliver Brewka             childId = BMCWEB_REDFISH_MANAGER_URI_NAME;
793af76e15SOliver Brewka             break;
803af76e15SOliver Brewka         case LogServiceParent::Systems:
813af76e15SOliver Brewka             childId = BMCWEB_REDFISH_SYSTEM_URI_NAME;
823af76e15SOliver Brewka             break;
833af76e15SOliver Brewka         default:
843af76e15SOliver Brewka             BMCWEB_LOG_ERROR(
853af76e15SOliver Brewka                 "Unable to stringify bmcweb eventlog location childId");
863af76e15SOliver Brewka             break;
873af76e15SOliver Brewka     }
883af76e15SOliver Brewka     return childId;
893af76e15SOliver Brewka }
903af76e15SOliver Brewka 
913af76e15SOliver Brewka inline std::string getLogEntryDescriptor(LogServiceParent parent)
923af76e15SOliver Brewka {
933af76e15SOliver Brewka     std::string descriptor;
943af76e15SOliver Brewka     switch (parent)
953af76e15SOliver Brewka     {
963af76e15SOliver Brewka         case LogServiceParent::Managers:
973af76e15SOliver Brewka             descriptor = "Manager";
983af76e15SOliver Brewka             break;
993af76e15SOliver Brewka         case LogServiceParent::Systems:
1003af76e15SOliver Brewka             descriptor = "System";
1013af76e15SOliver Brewka             break;
1023af76e15SOliver Brewka         default:
1033af76e15SOliver Brewka             BMCWEB_LOG_ERROR("Unable to get Log Entry descriptor");
1043af76e15SOliver Brewka             break;
1053af76e15SOliver Brewka     }
1063af76e15SOliver Brewka     return descriptor;
1073af76e15SOliver Brewka }
1083af76e15SOliver Brewka 
1099d6459e8SOliver Brewka inline void handleSystemsAndManagersEventLogServiceGet(
1109d6459e8SOliver Brewka     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1119d6459e8SOliver Brewka     LogServiceParent parent)
1129d6459e8SOliver Brewka {
1139d6459e8SOliver Brewka     const std::string parentStr = logServiceParentToString(parent);
1149d6459e8SOliver Brewka     const std::string_view childId = getChildIdFromParent(parent);
1159d6459e8SOliver Brewka     const std::string logEntryDescriptor = getLogEntryDescriptor(parent);
1169d6459e8SOliver Brewka 
1179d6459e8SOliver Brewka     if (parentStr.empty() || childId.empty() || logEntryDescriptor.empty())
1189d6459e8SOliver Brewka     {
1199d6459e8SOliver Brewka         messages::internalError(asyncResp->res);
1209d6459e8SOliver Brewka         return;
1219d6459e8SOliver Brewka     }
1229d6459e8SOliver Brewka 
1239d6459e8SOliver Brewka     asyncResp->res.jsonValue["@odata.id"] = std::format(
1249d6459e8SOliver Brewka         "/redfish/v1/{}/{}/LogServices/EventLog", parentStr, childId);
1259d6459e8SOliver Brewka     asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
1269d6459e8SOliver Brewka     asyncResp->res.jsonValue["Name"] = "Event Log Service";
1279d6459e8SOliver Brewka     asyncResp->res.jsonValue["Description"] =
1289d6459e8SOliver Brewka         std::format("{} Event Log Service", logEntryDescriptor);
1299d6459e8SOliver Brewka     asyncResp->res.jsonValue["Id"] = "EventLog";
1309d6459e8SOliver Brewka     asyncResp->res.jsonValue["OverWritePolicy"] =
1319d6459e8SOliver Brewka         log_service::OverWritePolicy::WrapsWhenFull;
1329d6459e8SOliver Brewka 
1339d6459e8SOliver Brewka     std::pair<std::string, std::string> redfishDateTimeOffset =
1349d6459e8SOliver Brewka         redfish::time_utils::getDateTimeOffsetNow();
1359d6459e8SOliver Brewka 
1369d6459e8SOliver Brewka     asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1379d6459e8SOliver Brewka     asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1389d6459e8SOliver Brewka         redfishDateTimeOffset.second;
1399d6459e8SOliver Brewka 
1409d6459e8SOliver Brewka     asyncResp->res.jsonValue["Entries"]["@odata.id"] = std::format(
1419d6459e8SOliver Brewka         "/redfish/v1/{}/{}/LogServices/EventLog/Entries", parentStr, childId);
1429d6459e8SOliver Brewka     asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"]
1439d6459e8SOliver Brewka 
1449d6459e8SOliver Brewka         = std::format(
1459d6459e8SOliver Brewka             "/redfish/v1/{}/{}/LogServices/EventLog/Actions/LogService.ClearLog",
1469d6459e8SOliver Brewka             parentStr, childId);
1479d6459e8SOliver Brewka     etag_utils::setEtagOmitDateTimeHandler(asyncResp);
1489d6459e8SOliver Brewka }
1499d6459e8SOliver Brewka 
1507681b8a1SOliver Brewka /*
1517681b8a1SOliver Brewka  * Journal EventLog utilities
1527681b8a1SOliver Brewka  * */
1537681b8a1SOliver Brewka 
1547681b8a1SOliver Brewka inline bool getRedfishLogFiles(
1557681b8a1SOliver Brewka     std::vector<std::filesystem::path>& redfishLogFiles)
1567681b8a1SOliver Brewka {
1577681b8a1SOliver Brewka     static const std::filesystem::path redfishLogDir = "/var/log";
1587681b8a1SOliver Brewka     static const std::string redfishLogFilename = "redfish";
1597681b8a1SOliver Brewka 
1607681b8a1SOliver Brewka     // Loop through the directory looking for redfish log files
1617681b8a1SOliver Brewka     for (const std::filesystem::directory_entry& dirEnt :
1627681b8a1SOliver Brewka          std::filesystem::directory_iterator(redfishLogDir))
1637681b8a1SOliver Brewka     {
1647681b8a1SOliver Brewka         // If we find a redfish log file, save the path
1657681b8a1SOliver Brewka         std::string filename = dirEnt.path().filename();
1667681b8a1SOliver Brewka         if (filename.starts_with(redfishLogFilename))
1677681b8a1SOliver Brewka         {
1687681b8a1SOliver Brewka             redfishLogFiles.emplace_back(redfishLogDir / filename);
1697681b8a1SOliver Brewka         }
1707681b8a1SOliver Brewka     }
1717681b8a1SOliver Brewka     // As the log files rotate, they are appended with a ".#" that is higher for
1727681b8a1SOliver Brewka     // the older logs. Since we don't expect more than 10 log files, we
1737681b8a1SOliver Brewka     // can just sort the list to get them in order from newest to oldest
1747681b8a1SOliver Brewka     std::ranges::sort(redfishLogFiles);
1757681b8a1SOliver Brewka 
1767681b8a1SOliver Brewka     return !redfishLogFiles.empty();
1777681b8a1SOliver Brewka }
1787681b8a1SOliver Brewka 
1797681b8a1SOliver Brewka inline bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
1807681b8a1SOliver Brewka                              const bool firstEntry = true)
1817681b8a1SOliver Brewka {
1827681b8a1SOliver Brewka     static time_t prevTs = 0;
1837681b8a1SOliver Brewka     static int index = 0;
1847681b8a1SOliver Brewka     if (firstEntry)
1857681b8a1SOliver Brewka     {
1867681b8a1SOliver Brewka         prevTs = 0;
1877681b8a1SOliver Brewka     }
1887681b8a1SOliver Brewka 
1897681b8a1SOliver Brewka     // Get the entry timestamp
1907681b8a1SOliver Brewka     std::time_t curTs = 0;
1917681b8a1SOliver Brewka     std::tm timeStruct = {};
1927681b8a1SOliver Brewka     std::istringstream entryStream(logEntry);
1937681b8a1SOliver Brewka     if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
1947681b8a1SOliver Brewka     {
1957681b8a1SOliver Brewka         curTs = std::mktime(&timeStruct);
1967681b8a1SOliver Brewka     }
1977681b8a1SOliver Brewka     // If the timestamp isn't unique, increment the index
1987681b8a1SOliver Brewka     if (curTs == prevTs)
1997681b8a1SOliver Brewka     {
2007681b8a1SOliver Brewka         index++;
2017681b8a1SOliver Brewka     }
2027681b8a1SOliver Brewka     else
2037681b8a1SOliver Brewka     {
2047681b8a1SOliver Brewka         // Otherwise, reset it
2057681b8a1SOliver Brewka         index = 0;
2067681b8a1SOliver Brewka     }
2077681b8a1SOliver Brewka     // Save the timestamp
2087681b8a1SOliver Brewka     prevTs = curTs;
2097681b8a1SOliver Brewka 
2107681b8a1SOliver Brewka     entryID = std::to_string(curTs);
2117681b8a1SOliver Brewka     if (index > 0)
2127681b8a1SOliver Brewka     {
2137681b8a1SOliver Brewka         entryID += "_" + std::to_string(index);
2147681b8a1SOliver Brewka     }
2157681b8a1SOliver Brewka     return true;
2167681b8a1SOliver Brewka }
2177681b8a1SOliver Brewka 
2187681b8a1SOliver Brewka enum class LogParseError
2197681b8a1SOliver Brewka {
2207681b8a1SOliver Brewka     success,
2217681b8a1SOliver Brewka     parseFailed,
2227681b8a1SOliver Brewka     messageIdNotInRegistry,
2237681b8a1SOliver Brewka };
2247681b8a1SOliver Brewka 
2257681b8a1SOliver Brewka static LogParseError fillEventLogEntryJson(
2267681b8a1SOliver Brewka     const std::string& logEntryID, const std::string& logEntry,
2273af76e15SOliver Brewka     nlohmann::json::object_t& logEntryJson, const std::string& parentStr,
2283af76e15SOliver Brewka     const std::string_view childId, const std::string& logEntryDescriptor)
2297681b8a1SOliver Brewka {
2307681b8a1SOliver Brewka     // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
2317681b8a1SOliver Brewka     // First get the Timestamp
2327681b8a1SOliver Brewka     size_t space = logEntry.find_first_of(' ');
2337681b8a1SOliver Brewka     if (space == std::string::npos)
2347681b8a1SOliver Brewka     {
2357681b8a1SOliver Brewka         return LogParseError::parseFailed;
2367681b8a1SOliver Brewka     }
2377681b8a1SOliver Brewka     std::string timestamp = logEntry.substr(0, space);
2387681b8a1SOliver Brewka     // Then get the log contents
2397681b8a1SOliver Brewka     size_t entryStart = logEntry.find_first_not_of(' ', space);
2407681b8a1SOliver Brewka     if (entryStart == std::string::npos)
2417681b8a1SOliver Brewka     {
2427681b8a1SOliver Brewka         return LogParseError::parseFailed;
2437681b8a1SOliver Brewka     }
2447681b8a1SOliver Brewka     std::string_view entry(logEntry);
2457681b8a1SOliver Brewka     entry.remove_prefix(entryStart);
2467681b8a1SOliver Brewka     // Use split to separate the entry into its fields
2477681b8a1SOliver Brewka     std::vector<std::string> logEntryFields;
2487681b8a1SOliver Brewka     bmcweb::split(logEntryFields, entry, ',');
2497681b8a1SOliver Brewka     // We need at least a MessageId to be valid
2507681b8a1SOliver Brewka     auto logEntryIter = logEntryFields.begin();
2517681b8a1SOliver Brewka     if (logEntryIter == logEntryFields.end())
2527681b8a1SOliver Brewka     {
2537681b8a1SOliver Brewka         return LogParseError::parseFailed;
2547681b8a1SOliver Brewka     }
2557681b8a1SOliver Brewka     std::string& messageID = *logEntryIter;
2567681b8a1SOliver Brewka     // Get the Message from the MessageRegistry
2577681b8a1SOliver Brewka     const registries::Message* message = registries::getMessage(messageID);
2587681b8a1SOliver Brewka 
2597681b8a1SOliver Brewka     logEntryIter++;
2607681b8a1SOliver Brewka     if (message == nullptr)
2617681b8a1SOliver Brewka     {
2627681b8a1SOliver Brewka         BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry);
2637681b8a1SOliver Brewka         return LogParseError::messageIdNotInRegistry;
2647681b8a1SOliver Brewka     }
2657681b8a1SOliver Brewka 
2667681b8a1SOliver Brewka     std::vector<std::string_view> messageArgs(logEntryIter,
2677681b8a1SOliver Brewka                                               logEntryFields.end());
2687681b8a1SOliver Brewka     messageArgs.resize(message->numberOfArgs);
2697681b8a1SOliver Brewka 
2707681b8a1SOliver Brewka     std::string msg =
2717681b8a1SOliver Brewka         redfish::registries::fillMessageArgs(messageArgs, message->message);
2727681b8a1SOliver Brewka     if (msg.empty())
2737681b8a1SOliver Brewka     {
2747681b8a1SOliver Brewka         return LogParseError::parseFailed;
2757681b8a1SOliver Brewka     }
2767681b8a1SOliver Brewka 
2777681b8a1SOliver Brewka     // Get the Created time from the timestamp. The log timestamp is in RFC3339
2789d6459e8SOliver Brewka     // format which matches the Redfish format except for the
2799d6459e8SOliver Brewka     // fractional seconds between the '.' and the '+', so just remove them.
2807681b8a1SOliver Brewka     std::size_t dot = timestamp.find_first_of('.');
2817681b8a1SOliver Brewka     std::size_t plus = timestamp.find_first_of('+');
2827681b8a1SOliver Brewka     if (dot != std::string::npos && plus != std::string::npos)
2837681b8a1SOliver Brewka     {
2847681b8a1SOliver Brewka         timestamp.erase(dot, plus - dot);
2857681b8a1SOliver Brewka     }
2867681b8a1SOliver Brewka 
2877681b8a1SOliver Brewka     // Fill in the log entry with the gathered data
2887681b8a1SOliver Brewka     logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
2893af76e15SOliver Brewka     logEntryJson["@odata.id"] =
2903af76e15SOliver Brewka         boost::urls::format("/redfish/v1/{}/{}/LogServices/EventLog/Entries/{}",
2913af76e15SOliver Brewka                             parentStr, childId, logEntryID);
2923af76e15SOliver Brewka     logEntryJson["Name"] =
2933af76e15SOliver Brewka         std::format("{} Event Log Entry", logEntryDescriptor);
2947681b8a1SOliver Brewka     logEntryJson["Id"] = logEntryID;
2957681b8a1SOliver Brewka     logEntryJson["Message"] = std::move(msg);
2967681b8a1SOliver Brewka     logEntryJson["MessageId"] = std::move(messageID);
2977681b8a1SOliver Brewka     logEntryJson["MessageArgs"] = messageArgs;
2987681b8a1SOliver Brewka     logEntryJson["EntryType"] = "Event";
2997681b8a1SOliver Brewka     logEntryJson["Severity"] = message->messageSeverity;
3007681b8a1SOliver Brewka     logEntryJson["Created"] = std::move(timestamp);
3017681b8a1SOliver Brewka     return LogParseError::success;
3027681b8a1SOliver Brewka }
3037681b8a1SOliver Brewka 
304*dba9d675SOliver Brewka inline void handleSystemsAndManagersLogServiceEventLogLogEntryCollection(
3057681b8a1SOliver Brewka     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3063af76e15SOliver Brewka     query_param::Query& delegatedQuery, LogServiceParent parent)
3077681b8a1SOliver Brewka {
3087681b8a1SOliver Brewka     size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
3097681b8a1SOliver Brewka     size_t skip = delegatedQuery.skip.value_or(0);
3107681b8a1SOliver Brewka 
3113af76e15SOliver Brewka     const std::string parentStr = logServiceParentToString(parent);
3123af76e15SOliver Brewka     const std::string_view childId = getChildIdFromParent(parent);
3133af76e15SOliver Brewka     const std::string logEntryDescriptor = getLogEntryDescriptor(parent);
3143af76e15SOliver Brewka 
3153af76e15SOliver Brewka     if (parentStr.empty() || childId.empty() || logEntryDescriptor.empty())
3163af76e15SOliver Brewka     {
3173af76e15SOliver Brewka         messages::internalError(asyncResp->res);
3183af76e15SOliver Brewka         return;
3193af76e15SOliver Brewka     }
3203af76e15SOliver Brewka 
3217681b8a1SOliver Brewka     // Collections don't include the static data added by SubRoute
3227681b8a1SOliver Brewka     // because it has a duplicate entry for members
3237681b8a1SOliver Brewka     asyncResp->res.jsonValue["@odata.type"] =
3247681b8a1SOliver Brewka         "#LogEntryCollection.LogEntryCollection";
3253af76e15SOliver Brewka     asyncResp->res.jsonValue["@odata.id"] = std::format(
3263af76e15SOliver Brewka         "/redfish/v1/{}/{}/LogServices/EventLog/Entries", parentStr, childId);
3273af76e15SOliver Brewka     asyncResp->res.jsonValue["Name"] =
3283af76e15SOliver Brewka         std::format("{} Event Log Entries", logEntryDescriptor);
3297681b8a1SOliver Brewka     asyncResp->res.jsonValue["Description"] =
3303af76e15SOliver Brewka         std::format("Collection of {} Event Log Entries", logEntryDescriptor);
3317681b8a1SOliver Brewka 
3327681b8a1SOliver Brewka     nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
3337681b8a1SOliver Brewka     logEntryArray = nlohmann::json::array();
3347681b8a1SOliver Brewka     // Go through the log files and create a unique ID for each
3357681b8a1SOliver Brewka     // entry
3367681b8a1SOliver Brewka     std::vector<std::filesystem::path> redfishLogFiles;
3377681b8a1SOliver Brewka     getRedfishLogFiles(redfishLogFiles);
3387681b8a1SOliver Brewka     uint64_t entryCount = 0;
3397681b8a1SOliver Brewka     std::string logEntry;
3407681b8a1SOliver Brewka 
3417681b8a1SOliver Brewka     // Oldest logs are in the last file, so start there and loop
3427681b8a1SOliver Brewka     // backwards
3437681b8a1SOliver Brewka     for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++)
3447681b8a1SOliver Brewka     {
3457681b8a1SOliver Brewka         std::ifstream logStream(*it);
3467681b8a1SOliver Brewka         if (!logStream.is_open())
3477681b8a1SOliver Brewka         {
3487681b8a1SOliver Brewka             continue;
3497681b8a1SOliver Brewka         }
3507681b8a1SOliver Brewka 
3517681b8a1SOliver Brewka         // Reset the unique ID on the first entry
3527681b8a1SOliver Brewka         bool firstEntry = true;
3537681b8a1SOliver Brewka         while (std::getline(logStream, logEntry))
3547681b8a1SOliver Brewka         {
3557681b8a1SOliver Brewka             std::string idStr;
3567681b8a1SOliver Brewka             if (!getUniqueEntryID(logEntry, idStr, firstEntry))
3577681b8a1SOliver Brewka             {
3587681b8a1SOliver Brewka                 continue;
3597681b8a1SOliver Brewka             }
3607681b8a1SOliver Brewka             firstEntry = false;
3617681b8a1SOliver Brewka 
3627681b8a1SOliver Brewka             nlohmann::json::object_t bmcLogEntry;
3637681b8a1SOliver Brewka             LogParseError status =
3643af76e15SOliver Brewka                 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry, parentStr,
3653af76e15SOliver Brewka                                       childId, logEntryDescriptor);
3667681b8a1SOliver Brewka             if (status == LogParseError::messageIdNotInRegistry)
3677681b8a1SOliver Brewka             {
3687681b8a1SOliver Brewka                 continue;
3697681b8a1SOliver Brewka             }
3707681b8a1SOliver Brewka             if (status != LogParseError::success)
3717681b8a1SOliver Brewka             {
3727681b8a1SOliver Brewka                 messages::internalError(asyncResp->res);
3737681b8a1SOliver Brewka                 return;
3747681b8a1SOliver Brewka             }
3757681b8a1SOliver Brewka 
3767681b8a1SOliver Brewka             entryCount++;
3777681b8a1SOliver Brewka             // Handle paging using skip (number of entries to skip from the
3787681b8a1SOliver Brewka             // start) and top (number of entries to display)
3797681b8a1SOliver Brewka             if (entryCount <= skip || entryCount > skip + top)
3807681b8a1SOliver Brewka             {
3817681b8a1SOliver Brewka                 continue;
3827681b8a1SOliver Brewka             }
3837681b8a1SOliver Brewka 
3847681b8a1SOliver Brewka             logEntryArray.emplace_back(std::move(bmcLogEntry));
3857681b8a1SOliver Brewka         }
3867681b8a1SOliver Brewka     }
3877681b8a1SOliver Brewka     asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
3887681b8a1SOliver Brewka     if (skip + top < entryCount)
3897681b8a1SOliver Brewka     {
3907681b8a1SOliver Brewka         asyncResp->res.jsonValue["Members@odata.nextLink"] =
3917681b8a1SOliver Brewka             boost::urls::format(
3923af76e15SOliver Brewka                 "/redfish/v1/{}/{}/LogServices/EventLog/Entries?$skip={}",
3933af76e15SOliver Brewka                 parentStr, childId, std::to_string(skip + top));
3947681b8a1SOliver Brewka     }
3957681b8a1SOliver Brewka }
3967681b8a1SOliver Brewka 
397*dba9d675SOliver Brewka inline void handleSystemsAndManagersLogServiceEventLogEntriesGet(
3987681b8a1SOliver Brewka     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3993af76e15SOliver Brewka     const std::string& param, LogServiceParent parent)
4007681b8a1SOliver Brewka {
4017681b8a1SOliver Brewka     const std::string& targetID = param;
4027681b8a1SOliver Brewka 
4033af76e15SOliver Brewka     const std::string parentStr = logServiceParentToString(parent);
4043af76e15SOliver Brewka     const std::string_view childId = getChildIdFromParent(parent);
4053af76e15SOliver Brewka     const std::string logEntryDescriptor = getLogEntryDescriptor(parent);
4063af76e15SOliver Brewka 
4073af76e15SOliver Brewka     if (parentStr.empty() || childId.empty() || logEntryDescriptor.empty())
4083af76e15SOliver Brewka     {
4093af76e15SOliver Brewka         messages::internalError(asyncResp->res);
4103af76e15SOliver Brewka         return;
4113af76e15SOliver Brewka     }
4123af76e15SOliver Brewka 
4137681b8a1SOliver Brewka     // Go through the log files and check the unique ID for each
4147681b8a1SOliver Brewka     // entry to find the target entry
4157681b8a1SOliver Brewka     std::vector<std::filesystem::path> redfishLogFiles;
4167681b8a1SOliver Brewka     getRedfishLogFiles(redfishLogFiles);
4177681b8a1SOliver Brewka     std::string logEntry;
4187681b8a1SOliver Brewka 
4197681b8a1SOliver Brewka     // Oldest logs are in the last file, so start there and loop
4207681b8a1SOliver Brewka     // backwards
4217681b8a1SOliver Brewka     for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend(); it++)
4227681b8a1SOliver Brewka     {
4237681b8a1SOliver Brewka         std::ifstream logStream(*it);
4247681b8a1SOliver Brewka         if (!logStream.is_open())
4257681b8a1SOliver Brewka         {
4267681b8a1SOliver Brewka             continue;
4277681b8a1SOliver Brewka         }
4287681b8a1SOliver Brewka 
4297681b8a1SOliver Brewka         // Reset the unique ID on the first entry
4307681b8a1SOliver Brewka         bool firstEntry = true;
4317681b8a1SOliver Brewka         while (std::getline(logStream, logEntry))
4327681b8a1SOliver Brewka         {
4337681b8a1SOliver Brewka             std::string idStr;
4347681b8a1SOliver Brewka             if (!getUniqueEntryID(logEntry, idStr, firstEntry))
4357681b8a1SOliver Brewka             {
4367681b8a1SOliver Brewka                 continue;
4377681b8a1SOliver Brewka             }
4387681b8a1SOliver Brewka             firstEntry = false;
4397681b8a1SOliver Brewka 
4407681b8a1SOliver Brewka             if (idStr == targetID)
4417681b8a1SOliver Brewka             {
4427681b8a1SOliver Brewka                 nlohmann::json::object_t bmcLogEntry;
4433af76e15SOliver Brewka                 LogParseError status = fillEventLogEntryJson(
4443af76e15SOliver Brewka                     idStr, logEntry, bmcLogEntry, parentStr, childId,
4453af76e15SOliver Brewka                     logEntryDescriptor);
4467681b8a1SOliver Brewka                 if (status != LogParseError::success)
4477681b8a1SOliver Brewka                 {
4487681b8a1SOliver Brewka                     messages::internalError(asyncResp->res);
4497681b8a1SOliver Brewka                     return;
4507681b8a1SOliver Brewka                 }
4517681b8a1SOliver Brewka                 asyncResp->res.jsonValue.update(bmcLogEntry);
4527681b8a1SOliver Brewka                 return;
4537681b8a1SOliver Brewka             }
4547681b8a1SOliver Brewka         }
4557681b8a1SOliver Brewka     }
4567681b8a1SOliver Brewka     // Requested ID was not found
4577681b8a1SOliver Brewka     messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
4587681b8a1SOliver Brewka }
4597681b8a1SOliver Brewka 
460*dba9d675SOliver Brewka inline void handleSystemsAndManagersLogServicesEventLogActionsClearPost(
4617681b8a1SOliver Brewka     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
4627681b8a1SOliver Brewka {
4637681b8a1SOliver Brewka     // Clear the EventLog by deleting the log files
4647681b8a1SOliver Brewka     std::vector<std::filesystem::path> redfishLogFiles;
4657681b8a1SOliver Brewka     if (getRedfishLogFiles(redfishLogFiles))
4667681b8a1SOliver Brewka     {
4677681b8a1SOliver Brewka         for (const std::filesystem::path& file : redfishLogFiles)
4687681b8a1SOliver Brewka         {
4697681b8a1SOliver Brewka             std::error_code ec;
4707681b8a1SOliver Brewka             std::filesystem::remove(file, ec);
4717681b8a1SOliver Brewka         }
4727681b8a1SOliver Brewka     }
4737681b8a1SOliver Brewka 
4747681b8a1SOliver Brewka     // Reload rsyslog so it knows to start new log files
4757681b8a1SOliver Brewka     dbus::utility::async_method_call(
4767681b8a1SOliver Brewka         asyncResp,
4777681b8a1SOliver Brewka         [asyncResp](const boost::system::error_code& ec) {
4787681b8a1SOliver Brewka             if (ec)
4797681b8a1SOliver Brewka             {
4807681b8a1SOliver Brewka                 BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec);
4817681b8a1SOliver Brewka                 messages::internalError(asyncResp->res);
4827681b8a1SOliver Brewka                 return;
4837681b8a1SOliver Brewka             }
4847681b8a1SOliver Brewka 
4857681b8a1SOliver Brewka             messages::success(asyncResp->res);
4867681b8a1SOliver Brewka         },
4877681b8a1SOliver Brewka         "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
4887681b8a1SOliver Brewka         "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
4897681b8a1SOliver Brewka         "replace");
4907681b8a1SOliver Brewka }
4917681b8a1SOliver Brewka } // namespace eventlog_utils
4927681b8a1SOliver Brewka } // namespace redfish
493