1 #include <fstream> 2 #include <iostream> 3 #include <cstdio> 4 #include <string> 5 #include <vector> 6 #include <sdbusplus/vtable.hpp> 7 #include <systemd/sd-bus.h> 8 #include <systemd/sd-journal.h> 9 #include "log.hpp" 10 #include "log_manager.hpp" 11 12 namespace phosphor 13 { 14 namespace logging 15 { 16 17 void Manager::commit(uint64_t transactionId, std::string errMsg) 18 { 19 // TODO Change /tmp path to a permanent location on flash 20 constexpr const auto path = "/tmp/elog"; 21 constexpr const auto msgIdStr = "_PID"; 22 23 // Create log file 24 std::string filename{}; 25 filename.append(path); 26 // TODO Create error logs in their own separate dir once permanent location 27 // on flash is determined. Ex: ../transactionId/1 28 std::ofstream efile; 29 efile.open(filename); 30 efile << "{" << std::endl; 31 32 //const char* metaVar = nullptr; 33 std::vector<const char*> metaList; 34 35 sd_journal *j = nullptr; 36 int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); 37 if (rc < 0) 38 { 39 logging::log<logging::level::ERR>("Failed to open journal", 40 logging::entry("DESCRIPTION=%s", strerror(-rc))); 41 return; 42 } 43 44 // Read the journal from the end to get the most recent entry first. 45 // The result from the sd_journal_get_data() is of the form VARIABLE=value. 46 SD_JOURNAL_FOREACH_BACKWARDS(j) 47 { 48 const char *data = nullptr; 49 size_t length = 0; 50 51 // Search for the msg id 52 rc = sd_journal_get_data(j, msgIdStr, (const void **)&data, &length); 53 if (rc < 0) 54 { 55 // Instance not found, continue to next journal entry 56 continue; 57 } 58 std::string result(data); 59 // TODO String msgid is now an int transaction id. This piece will be 60 // uncommented and reworked with the upcoming change to read the metadata 61 // fields from the header file. 62 #if 0 63 if (result.find(msgid) == std::string::npos) 64 { 65 // Match not found, continue to next journal entry 66 continue; 67 } 68 #endif 69 // Match found, write to file 70 // TODO This is a draft format based on the redfish event logs written 71 // in json, the final openbmc format is to be determined 72 efile << "\t{" << std::endl; 73 efile << "\t\"@" << data << "\"," << std::endl; 74 75 // Include the journal message 76 rc = sd_journal_get_data(j, "MESSAGE", (const void **)&data, &length); 77 if (rc < 0) 78 { 79 continue; 80 } 81 efile << "\t\"@" << data << "\"," << std::endl; 82 83 // Search for the metadata variables in the current journal entry 84 for (auto i : metaList) 85 { 86 rc = sd_journal_get_data(j, i, (const void **)&data, &length); 87 if (rc < 0) 88 { 89 // Not found, continue to next metadata variable 90 logging::log<logging::level::INFO>("Failed to find metadata", 91 logging::entry("META_FIELD=%s", i)); 92 continue; 93 } 94 95 // Metatdata variable found, write to file 96 efile << "\t\"@" << data << "\"," << std::endl; 97 } 98 efile << "\t}" << std::endl; 99 100 // TODO Break only once all metadata fields have been found. Implement 101 // once this function reads the metadata fields from the header file. 102 break; 103 } 104 sd_journal_close(j); 105 106 efile << "}" << std::endl; 107 efile.close(); 108 return; 109 } 110 111 Manager::Manager(sdbusplus::bus::bus &&bus, 112 const char* busname, 113 const char* obj) : 114 details::ServerObject<details::ManagerIface>(bus, obj), 115 _bus(std::move(bus)), 116 _manager(sdbusplus::server::manager::manager(_bus, obj)) 117 { 118 _bus.request_name(busname); 119 } 120 121 void Manager::run() noexcept 122 { 123 while(true) 124 { 125 try 126 { 127 _bus.process_discard(); 128 _bus.wait(); 129 } 130 catch (std::exception &e) 131 { 132 std::cerr << e.what() << std::endl; 133 } 134 } 135 } 136 137 } // namespace logging 138 } // namepsace phosphor 139