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 // Length of 'TRANSACTION_ID' string. 27 constexpr const auto transactionIdVarSize = strlen(transactionIdVar); 28 // Length of 'TRANSACTION_ID=' string. 29 constexpr const auto transactionIdVarOffset = transactionIdVarSize + 1; 30 31 sd_journal *j = nullptr; 32 int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); 33 if (rc < 0) 34 { 35 logging::log<logging::level::ERR>("Failed to open journal", 36 logging::entry("DESCRIPTION=%s", strerror(-rc))); 37 return; 38 } 39 40 std::string transactionIdStr = std::to_string(transactionId); 41 std::set<std::string> metalist(g_errMetaMap[errMsg].begin(), 42 g_errMetaMap[errMsg].end()); 43 const auto& metalistHostEvent = g_errMetaMapHostEvent[errMsg]; 44 std::vector<std::string> additionalData; 45 46 // TODO Remove once host event error header file is auto-generated. 47 // Also make metalist a const variable. 48 // Tracking with issue openbmc/phosphor-logging#4 49 for (auto& metaVarStrHostEvent : metalistHostEvent) 50 { 51 metalist.insert(metaVarStrHostEvent); 52 } 53 54 // Read the journal from the end to get the most recent entry first. 55 // The result from the sd_journal_get_data() is of the form VARIABLE=value. 56 SD_JOURNAL_FOREACH_BACKWARDS(j) 57 { 58 const char *data = nullptr; 59 size_t length = 0; 60 61 // Look for the transaction id metadata variable 62 rc = sd_journal_get_data(j, transactionIdVar, (const void **)&data, 63 &length); 64 if (rc < 0) 65 { 66 // This journal entry does not have the TRANSACTION_ID 67 // metadata variable. 68 continue; 69 } 70 71 // journald does not guarantee that sd_journal_get_data() returns NULL 72 // terminated strings, so need to specify the size to use to compare, 73 // use the returned length instead of anything that relies on NULL 74 // terminators like strlen(). 75 // The data variable is in the form of 'TRANSACTION_ID=1234'. Remove 76 // the TRANSACTION_ID characters plus the (=) sign to do the comparison. 77 // 'data + transactionIdVarOffset' will be in the form of '1234'. 78 // 'length - transactionIdVarOffset' will be the length of '1234'. 79 if ((length <= (transactionIdVarOffset)) || 80 (transactionIdStr.compare(0, 81 transactionIdStr.size(), 82 data + transactionIdVarOffset, 83 length - transactionIdVarOffset) != 0)) 84 { 85 // The value of the TRANSACTION_ID metadata is not the requested 86 // transaction id number. 87 continue; 88 } 89 90 // Search for all metadata variables in the current journal entry. 91 for (auto i = metalist.cbegin(); i != metalist.cend();) 92 { 93 rc = sd_journal_get_data(j, (*i).c_str(), 94 (const void **)&data, &length); 95 if (rc < 0) 96 { 97 // Metadata variable not found, check next metadata variable. 98 i++; 99 continue; 100 } 101 102 // Metadata variable found, save it and remove it from the set. 103 additionalData.emplace_back(data, length); 104 i = metalist.erase(i); 105 } 106 if (metalist.empty()) 107 { 108 // All metadata variables found, break out of journal loop. 109 break; 110 } 111 } 112 if (!metalist.empty()) 113 { 114 // Not all the metadata variables were found in the journal. 115 for (auto& metaVarStr : metalist) 116 { 117 logging::log<logging::level::INFO>("Failed to find metadata", 118 logging::entry("META_FIELD=%s", metaVarStr.c_str())); 119 } 120 } 121 122 sd_journal_close(j); 123 124 // Create error Entry dbus object 125 entryId++; 126 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>( 127 std::chrono::system_clock::now().time_since_epoch()).count(); 128 auto objPath = std::string(OBJ_ENTRY) + '/' + 129 std::to_string(entryId); 130 entries.insert(std::make_pair(entryId, std::make_unique<Entry>( 131 busLog, 132 objPath, 133 entryId, 134 ms, // Milliseconds since 1970 135 (Entry::Level)g_errLevelMap[errMsg], 136 std::move(errMsg), 137 std::move(additionalData)))); 138 return; 139 } 140 141 } // namespace logging 142 } // namepsace phosphor 143