1 #include <fstream> 2 #include <iostream> 3 #include <chrono> 4 #include <cstdio> 5 #include <set> 6 #include <string> 7 #include <vector> 8 #include <sdbusplus/vtable.hpp> 9 #include <systemd/sd-bus.h> 10 #include <systemd/sd-journal.h> 11 #include "elog-lookup.cpp" 12 #include <phosphor-logging/elog-errors-HostEvent.hpp> 13 #include "config.h" 14 #include "elog_entry.hpp" 15 #include <phosphor-logging/log.hpp> 16 #include "log_manager.hpp" 17 18 namespace phosphor 19 { 20 namespace logging 21 { 22 23 void Manager::commit(uint64_t transactionId, std::string errMsg) 24 { 25 constexpr const auto transactionIdVar = "TRANSACTION_ID"; 26 27 sd_journal *j = nullptr; 28 int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); 29 if (rc < 0) 30 { 31 logging::log<logging::level::ERR>("Failed to open journal", 32 logging::entry("DESCRIPTION=%s", strerror(-rc))); 33 return; 34 } 35 36 std::string transactionIdStr = std::to_string(transactionId); 37 std::set<std::string> metalist(g_errMetaMap[errMsg].begin(), 38 g_errMetaMap[errMsg].end()); 39 const auto& metalistHostEvent = g_errMetaMapHostEvent[errMsg]; 40 std::vector<std::string> additionalData; 41 42 // TODO Remove once host event error header file is auto-generated. 43 // Also make metalist a const variable. 44 // Tracking with issue openbmc/phosphor-logging#4 45 for (auto& metaVarStrHostEvent : metalistHostEvent) 46 { 47 metalist.insert(metaVarStrHostEvent); 48 } 49 50 // Read the journal from the end to get the most recent entry first. 51 // The result from the sd_journal_get_data() is of the form VARIABLE=value. 52 SD_JOURNAL_FOREACH_BACKWARDS(j) 53 { 54 const char *data = nullptr; 55 size_t length = 0; 56 57 // Look for the transaction id metadata variable 58 rc = sd_journal_get_data(j, transactionIdVar, (const void **)&data, 59 &length); 60 if (rc < 0) 61 { 62 // This journal entry does not have the TRANSACTION_ID 63 // metadata variable. 64 continue; 65 } 66 67 std::string result(data, length); 68 if (result.find(transactionIdStr) == std::string::npos) 69 { 70 // The value of the TRANSACTION_ID metadata is not the requested 71 // transaction id number. 72 continue; 73 } 74 75 // Search for all metadata variables in the current journal entry. 76 for (auto i = metalist.cbegin(); i != metalist.cend();) 77 { 78 rc = sd_journal_get_data(j, (*i).c_str(), 79 (const void **)&data, &length); 80 if (rc < 0) 81 { 82 // Metadata variable not found, check next metadata variable. 83 i++; 84 continue; 85 } 86 87 // Metadata variable found, save it and remove it from the set. 88 additionalData.emplace_back(data, length); 89 i = metalist.erase(i); 90 } 91 if (metalist.empty()) 92 { 93 // All metadata variables found, break out of journal loop. 94 break; 95 } 96 } 97 if (!metalist.empty()) 98 { 99 // Not all the metadata variables were found in the journal. 100 for (auto& metaVarStr : metalist) 101 { 102 logging::log<logging::level::INFO>("Failed to find metadata", 103 logging::entry("META_FIELD=%s", metaVarStr.c_str())); 104 } 105 } 106 107 sd_journal_close(j); 108 109 // Create error Entry dbus object 110 entryId++; 111 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>( 112 std::chrono::system_clock::now().time_since_epoch()).count(); 113 auto objPath = std::string(OBJ_ENTRY) + '/' + 114 std::to_string(entryId); 115 entries.insert(std::make_pair(entryId, std::make_unique<Entry>( 116 busLog, 117 objPath, 118 entryId, 119 ms, // Milliseconds since 1970 120 (Entry::Level)g_errLevelMap[errMsg], 121 std::move(errMsg), 122 std::move(additionalData)))); 123 return; 124 } 125 126 } // namespace logging 127 } // namepsace phosphor 128