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