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