1d311bc8dSAdriana Kobylak #include <fstream> 2d311bc8dSAdriana Kobylak #include <iostream> 3c5f0bbd9SAdriana Kobylak #include <chrono> 4d311bc8dSAdriana Kobylak #include <cstdio> 5d311bc8dSAdriana Kobylak #include <string> 6d311bc8dSAdriana Kobylak #include <vector> 71db1bd35SAdriana Kobylak #include <sdbusplus/vtable.hpp> 81db1bd35SAdriana Kobylak #include <systemd/sd-bus.h> 9d311bc8dSAdriana Kobylak #include <systemd/sd-journal.h> 107298dc23SAdriana Kobylak #include "elog-lookup.cpp" 11*2bb15195SSaqib Khan #include <phosphor-logging/elog-errors-HostEvent.hpp> 124ea7f312SAdriana Kobylak #include "config.h" 134ea7f312SAdriana Kobylak #include "elog_entry.hpp" 14*2bb15195SSaqib Khan #include <phosphor-logging/log.hpp> 158f7941edSAdriana Kobylak #include "log_manager.hpp" 161db1bd35SAdriana Kobylak 178f7941edSAdriana Kobylak namespace phosphor 188f7941edSAdriana Kobylak { 198f7941edSAdriana Kobylak namespace logging 208f7941edSAdriana Kobylak { 21d311bc8dSAdriana Kobylak 228f7941edSAdriana Kobylak void Manager::commit(uint64_t transactionId, std::string errMsg) 231db1bd35SAdriana Kobylak { 24d311bc8dSAdriana Kobylak // TODO Change /tmp path to a permanent location on flash 25d311bc8dSAdriana Kobylak constexpr const auto path = "/tmp/elog"; 267298dc23SAdriana Kobylak constexpr const auto transactionIdVar = "TRANSACTION_ID"; 271db1bd35SAdriana Kobylak 28d311bc8dSAdriana Kobylak std::string filename{}; 29d311bc8dSAdriana Kobylak filename.append(path); 30d311bc8dSAdriana Kobylak // TODO Create error logs in their own separate dir once permanent location 318f7941edSAdriana Kobylak // on flash is determined. Ex: ../transactionId/1 32d311bc8dSAdriana Kobylak std::ofstream efile; 33d311bc8dSAdriana Kobylak efile.open(filename); 34d311bc8dSAdriana Kobylak efile << "{" << std::endl; 35d311bc8dSAdriana Kobylak 36d311bc8dSAdriana Kobylak sd_journal *j = nullptr; 378f7941edSAdriana Kobylak int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); 38d311bc8dSAdriana Kobylak if (rc < 0) 39d311bc8dSAdriana Kobylak { 40d311bc8dSAdriana Kobylak logging::log<logging::level::ERR>("Failed to open journal", 41d311bc8dSAdriana Kobylak logging::entry("DESCRIPTION=%s", strerror(-rc))); 428f7941edSAdriana Kobylak return; 43d311bc8dSAdriana Kobylak } 44d311bc8dSAdriana Kobylak 457298dc23SAdriana Kobylak std::string transactionIdStr = std::to_string(transactionId); 467298dc23SAdriana Kobylak std::vector<std::string> metalist = g_errMetaMap[errMsg]; 471f36a881SAdriana Kobylak std::vector<std::string> metalistHostEvent = g_errMetaMapHostEvent[errMsg]; 484ea7f312SAdriana Kobylak std::vector<std::string> additionalData; 497298dc23SAdriana Kobylak 50d311bc8dSAdriana Kobylak // Read the journal from the end to get the most recent entry first. 51d311bc8dSAdriana Kobylak // The result from the sd_journal_get_data() is of the form VARIABLE=value. 52d311bc8dSAdriana Kobylak SD_JOURNAL_FOREACH_BACKWARDS(j) 53d311bc8dSAdriana Kobylak { 54d311bc8dSAdriana Kobylak const char *data = nullptr; 55d311bc8dSAdriana Kobylak size_t length = 0; 56d311bc8dSAdriana Kobylak 577298dc23SAdriana Kobylak // Look for the transaction id metadata variable 587298dc23SAdriana Kobylak rc = sd_journal_get_data(j, transactionIdVar, (const void **)&data, 597298dc23SAdriana Kobylak &length); 60d311bc8dSAdriana Kobylak if (rc < 0) 61d311bc8dSAdriana Kobylak { 627298dc23SAdriana Kobylak // This journal entry does not have the transaction id, 637298dc23SAdriana Kobylak // continue to next entry 64d311bc8dSAdriana Kobylak continue; 65d311bc8dSAdriana Kobylak } 667298dc23SAdriana Kobylak 67d311bc8dSAdriana Kobylak std::string result(data); 687298dc23SAdriana Kobylak if (result.find(transactionIdStr) == std::string::npos) 69d311bc8dSAdriana Kobylak { 707298dc23SAdriana Kobylak // Requested transaction id not found, 717298dc23SAdriana Kobylak // continue to next journal entry. 72d311bc8dSAdriana Kobylak continue; 73d311bc8dSAdriana Kobylak } 74d311bc8dSAdriana Kobylak // Match found, write to file 75d311bc8dSAdriana Kobylak // TODO This is a draft format based on the redfish event logs written 76d311bc8dSAdriana Kobylak // in json, the final openbmc format is to be determined 77d311bc8dSAdriana Kobylak efile << "\t{" << std::endl; 78d311bc8dSAdriana Kobylak efile << "\t\"@" << data << "\"," << std::endl; 79d311bc8dSAdriana Kobylak 80d311bc8dSAdriana Kobylak // Include the journal message 81d311bc8dSAdriana Kobylak rc = sd_journal_get_data(j, "MESSAGE", (const void **)&data, &length); 82d311bc8dSAdriana Kobylak if (rc < 0) 83d311bc8dSAdriana Kobylak { 84d311bc8dSAdriana Kobylak continue; 85d311bc8dSAdriana Kobylak } 864ea7f312SAdriana Kobylak 87d311bc8dSAdriana Kobylak efile << "\t\"@" << data << "\"," << std::endl; 88d311bc8dSAdriana Kobylak 89d311bc8dSAdriana Kobylak // Search for the metadata variables in the current journal entry 907298dc23SAdriana Kobylak for (auto metaVarStr : metalist) 91d311bc8dSAdriana Kobylak { 927298dc23SAdriana Kobylak rc = sd_journal_get_data(j, metaVarStr.c_str(), 937298dc23SAdriana Kobylak (const void **)&data, &length); 94d311bc8dSAdriana Kobylak if (rc < 0) 95d311bc8dSAdriana Kobylak { 96d311bc8dSAdriana Kobylak // Not found, continue to next metadata variable 97d311bc8dSAdriana Kobylak logging::log<logging::level::INFO>("Failed to find metadata", 987298dc23SAdriana Kobylak logging::entry("META_FIELD=%s", metaVarStr.c_str())); 99d311bc8dSAdriana Kobylak continue; 100d311bc8dSAdriana Kobylak } 101d311bc8dSAdriana Kobylak 102d311bc8dSAdriana Kobylak // Metatdata variable found, write to file 1034ea7f312SAdriana Kobylak additionalData.push_back(std::string(data)); 104d311bc8dSAdriana Kobylak efile << "\t\"@" << data << "\"," << std::endl; 105d311bc8dSAdriana Kobylak } 106d311bc8dSAdriana Kobylak efile << "\t}" << std::endl; 107d311bc8dSAdriana Kobylak 1081f36a881SAdriana Kobylak // TODO Remove once host event error header file is auto-generated. 1091f36a881SAdriana Kobylak // Tracking with issue openbmc/phosphor-logging#4 1101f36a881SAdriana Kobylak for (auto metaVarStrHostEvent : metalistHostEvent) 1111f36a881SAdriana Kobylak { 1121f36a881SAdriana Kobylak rc = sd_journal_get_data(j, metaVarStrHostEvent.c_str(), 1131f36a881SAdriana Kobylak (const void **)&data, &length); 1141f36a881SAdriana Kobylak if (rc < 0) 1151f36a881SAdriana Kobylak { 1161f36a881SAdriana Kobylak // Not found, continue to next metadata variable 1171f36a881SAdriana Kobylak logging::log<logging::level::INFO>("Failed to find metadata", 1181f36a881SAdriana Kobylak logging::entry("META_FIELD=%s", 1191f36a881SAdriana Kobylak metaVarStrHostEvent.c_str())); 1201f36a881SAdriana Kobylak continue; 1211f36a881SAdriana Kobylak } 1221f36a881SAdriana Kobylak 1231f36a881SAdriana Kobylak // Metatdata variable found, write to file 1241f36a881SAdriana Kobylak additionalData.push_back(std::string(data)); 1251f36a881SAdriana Kobylak efile << "\t\"@" << data << "\"," << std::endl; 1261f36a881SAdriana Kobylak } 1271f36a881SAdriana Kobylak 128d311bc8dSAdriana Kobylak // TODO Break only once all metadata fields have been found. Implement 129d311bc8dSAdriana Kobylak // once this function reads the metadata fields from the header file. 130d311bc8dSAdriana Kobylak break; 131d311bc8dSAdriana Kobylak } 132d311bc8dSAdriana Kobylak sd_journal_close(j); 133d311bc8dSAdriana Kobylak 1344ea7f312SAdriana Kobylak // Create error Entry dbus object 1354ea7f312SAdriana Kobylak entryId++; 136c5f0bbd9SAdriana Kobylak auto ms = std::chrono::duration_cast<std::chrono::milliseconds>( 137c5f0bbd9SAdriana Kobylak std::chrono::system_clock::now().time_since_epoch()).count(); 1384ea7f312SAdriana Kobylak auto objPath = std::string(OBJ_ENTRY) + '/' + 1394ea7f312SAdriana Kobylak std::to_string(entryId); 1404ea7f312SAdriana Kobylak entries.insert(std::make_pair(entryId, std::make_unique<Entry>( 1414ea7f312SAdriana Kobylak busLog, 1424ea7f312SAdriana Kobylak objPath, 1434ea7f312SAdriana Kobylak entryId, 144c5f0bbd9SAdriana Kobylak ms, // Milliseconds since 1970 1454ea7f312SAdriana Kobylak (Entry::Level)g_errLevelMap[errMsg], 1464ea7f312SAdriana Kobylak std::move(errMsg), 1474ea7f312SAdriana Kobylak std::move(additionalData)))); 1484ea7f312SAdriana Kobylak 149d311bc8dSAdriana Kobylak efile << "}" << std::endl; 150d311bc8dSAdriana Kobylak efile.close(); 1518f7941edSAdriana Kobylak return; 1521db1bd35SAdriana Kobylak } 1531db1bd35SAdriana Kobylak 1548f7941edSAdriana Kobylak } // namespace logging 1558f7941edSAdriana Kobylak } // namepsace phosphor 156