1 #pragma once 2 3 #include "bmcweb_config.h" 4 5 #include "generated/enums/log_entry.hpp" 6 #include "logging.hpp" 7 #include "utility.hpp" 8 #include "utils/time_utils.hpp" 9 10 #include <systemd/sd-journal.h> 11 12 #include <nlohmann/json.hpp> 13 14 #include <algorithm> 15 #include <charconv> 16 #include <cstddef> 17 #include <cstdint> 18 #include <format> 19 #include <memory> 20 #include <string> 21 #include <string_view> 22 #include <utility> 23 24 namespace redfish 25 { 26 getJournalMetadata(sd_journal * journal,const char * field,std::string_view & contents)27 inline int getJournalMetadata(sd_journal* journal, const char* field, 28 std::string_view& contents) 29 { 30 const char* data = nullptr; 31 size_t length = 0; 32 int ret = 0; 33 // Get the metadata from the requested field of the journal entry 34 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 35 const void** dataVoid = reinterpret_cast<const void**>(&data); 36 37 ret = sd_journal_get_data(journal, field, dataVoid, &length); 38 if (ret < 0) 39 { 40 return ret; 41 } 42 contents = std::string_view(data, length); 43 // Only use the content after the "=" character. 44 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size())); 45 return ret; 46 } 47 getJournalMetadataInt(sd_journal * journal,const char * field,long int & contents)48 inline int getJournalMetadataInt(sd_journal* journal, const char* field, 49 long int& contents) 50 { 51 std::string_view metadata; 52 // Get the metadata from the requested field of the journal entry 53 int ret = getJournalMetadata(journal, field, metadata); 54 if (ret < 0) 55 { 56 return ret; 57 } 58 std::from_chars_result res = 59 std::from_chars(&*metadata.begin(), &*metadata.end(), contents); 60 if (res.ec != std::error_code{} || res.ptr != &*metadata.end()) 61 { 62 return -1; 63 } 64 return 0; 65 } 66 getEntryTimestamp(sd_journal * journal,std::string & entryTimestamp)67 inline bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp) 68 { 69 int ret = 0; 70 uint64_t timestamp = 0; 71 ret = sd_journal_get_realtime_usec(journal, ×tamp); 72 if (ret < 0) 73 { 74 BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", ret); 75 return false; 76 } 77 entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp); 78 return true; 79 } 80 fillBMCJournalLogEntryJson(sd_journal * journal,nlohmann::json::object_t & bmcJournalLogEntryJson)81 inline bool fillBMCJournalLogEntryJson( 82 sd_journal* journal, nlohmann::json::object_t& bmcJournalLogEntryJson) 83 { 84 char* cursor = nullptr; 85 int ret = sd_journal_get_cursor(journal, &cursor); 86 if (ret < 0) 87 { 88 return false; 89 } 90 std::unique_ptr<char*> cursorptr = std::make_unique<char*>(cursor); 91 std::string bmcJournalLogEntryID(cursor); 92 93 // Get the Log Entry contents 94 std::string message; 95 std::string_view syslogID; 96 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID); 97 if (ret < 0) 98 { 99 BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}", ret); 100 } 101 if (!syslogID.empty()) 102 { 103 message += std::string(syslogID) + ": "; 104 } 105 106 std::string_view msg; 107 ret = getJournalMetadata(journal, "MESSAGE", msg); 108 if (ret < 0) 109 { 110 BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", ret); 111 return false; 112 } 113 message += std::string(msg); 114 115 // Get the severity from the PRIORITY field 116 long int severity = 8; // Default to an invalid priority 117 ret = getJournalMetadataInt(journal, "PRIORITY", severity); 118 if (ret < 0) 119 { 120 BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", ret); 121 } 122 123 // Get the Created time from the timestamp 124 std::string entryTimeStr; 125 if (!getEntryTimestamp(journal, entryTimeStr)) 126 { 127 return false; 128 } 129 130 // Fill in the log entry with the gathered data 131 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry"; 132 133 std::string entryIdBase64 = 134 crow::utility::base64encode(bmcJournalLogEntryID); 135 136 bmcJournalLogEntryJson["@odata.id"] = boost_swap_impl::format( 137 "/redfish/v1/Managers/{}/LogServices/Journal/Entries/{}", 138 BMCWEB_REDFISH_MANAGER_URI_NAME, entryIdBase64); 139 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry"; 140 bmcJournalLogEntryJson["Id"] = entryIdBase64; 141 bmcJournalLogEntryJson["Message"] = std::move(message); 142 bmcJournalLogEntryJson["EntryType"] = log_entry::LogEntryType::Oem; 143 log_entry::EventSeverity rfseverity = log_entry::EventSeverity::OK; 144 if (severity <= 2) 145 { 146 rfseverity = log_entry::EventSeverity::Critical; 147 } 148 else if (severity <= 4) 149 { 150 rfseverity = log_entry::EventSeverity::Warning; 151 } 152 153 bmcJournalLogEntryJson["Severity"] = rfseverity; 154 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry"; 155 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr); 156 return true; 157 } 158 159 } // namespace redfish 160