xref: /openbmc/phosphor-logging/log_manager.cpp (revision 465aaeccc5c01a437b3a3b23a9566482af0c32b5)
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