blob: 8ab495b40fcf7028371af14b8caa214a6eba2d6a [file] [log] [blame]
Adriana Kobylakd311bc82016-10-16 09:54:40 -05001#include <fstream>
2#include <iostream>
Adriana Kobylakc5f0bbd2017-01-22 14:56:04 -06003#include <chrono>
Adriana Kobylakd311bc82016-10-16 09:54:40 -05004#include <cstdio>
Adriana Kobylakfbe88722017-02-22 16:49:59 -06005#include <set>
Adriana Kobylakd311bc82016-10-16 09:54:40 -05006#include <string>
7#include <vector>
Adriana Kobylak1db1bd32016-10-10 11:39:20 -05008#include <sdbusplus/vtable.hpp>
9#include <systemd/sd-bus.h>
Adriana Kobylakd311bc82016-10-16 09:54:40 -050010#include <systemd/sd-journal.h>
Saqib Khan2bb15192017-02-13 13:19:55 -060011#include <phosphor-logging/elog-errors-HostEvent.hpp>
Adriana Kobylak4ea7f312017-01-10 12:52:34 -060012#include "config.h"
13#include "elog_entry.hpp"
Saqib Khan2bb15192017-02-13 13:19:55 -060014#include <phosphor-logging/log.hpp>
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060015#include "log_manager.hpp"
Deepak Kodihallia87c1572017-02-28 07:40:34 -060016#include "elog_meta.hpp"
17
18using namespace phosphor::logging;
19extern const std::map<metadata::Metadata,
20 std::function<metadata::associations::Type>> meta;
Adriana Kobylak1db1bd32016-10-10 11:39:20 -050021
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060022namespace phosphor
23{
24namespace logging
25{
Adriana Kobylakd311bc82016-10-16 09:54:40 -050026
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060027void Manager::commit(uint64_t transactionId, std::string errMsg)
Adriana Kobylak1db1bd32016-10-10 11:39:20 -050028{
Adriana Kobylak7298dc22017-01-24 12:21:50 -060029 constexpr const auto transactionIdVar = "TRANSACTION_ID";
Adriana Kobylak27c87d92017-03-06 12:45:09 -060030 // Length of 'TRANSACTION_ID' string.
Adriana Kobylak67218992017-02-28 12:53:37 -060031 constexpr const auto transactionIdVarSize = strlen(transactionIdVar);
Adriana Kobylak27c87d92017-03-06 12:45:09 -060032 // Length of 'TRANSACTION_ID=' string.
33 constexpr const auto transactionIdVarOffset = transactionIdVarSize + 1;
Adriana Kobylak1db1bd32016-10-10 11:39:20 -050034
Adriana Kobylakd311bc82016-10-16 09:54:40 -050035 sd_journal *j = nullptr;
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060036 int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
Adriana Kobylakd311bc82016-10-16 09:54:40 -050037 if (rc < 0)
38 {
39 logging::log<logging::level::ERR>("Failed to open journal",
40 logging::entry("DESCRIPTION=%s", strerror(-rc)));
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060041 return;
Adriana Kobylakd311bc82016-10-16 09:54:40 -050042 }
43
Adriana Kobylak7298dc22017-01-24 12:21:50 -060044 std::string transactionIdStr = std::to_string(transactionId);
Adriana Kobylakd722b3a2017-02-28 12:10:44 -060045 std::set<std::string> metalist;
46 auto metamap = g_errMetaMap.find(errMsg);
47 if (metamap != g_errMetaMap.end())
48 {
49 metalist.insert(metamap->second.begin(), metamap->second.end());
50 }
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060051 const auto& metalistHostEvent = g_errMetaMapHostEvent[errMsg];
Adriana Kobylak4ea7f312017-01-10 12:52:34 -060052 std::vector<std::string> additionalData;
Adriana Kobylak7298dc22017-01-24 12:21:50 -060053
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060054 // TODO Remove once host event error header file is auto-generated.
55 // Also make metalist a const variable.
56 // Tracking with issue openbmc/phosphor-logging#4
57 for (auto& metaVarStrHostEvent : metalistHostEvent)
Adriana Kobylakd311bc82016-10-16 09:54:40 -050058 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -060059 metalist.insert(metaVarStrHostEvent);
Adriana Kobylakd311bc82016-10-16 09:54:40 -050060 }
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060061
Adriana Kobylakfbe88722017-02-22 16:49:59 -060062 // Read the journal from the end to get the most recent entry first.
63 // The result from the sd_journal_get_data() is of the form VARIABLE=value.
64 SD_JOURNAL_FOREACH_BACKWARDS(j)
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060065 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -060066 const char *data = nullptr;
67 size_t length = 0;
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060068
Adriana Kobylakfbe88722017-02-22 16:49:59 -060069 // Look for the transaction id metadata variable
70 rc = sd_journal_get_data(j, transactionIdVar, (const void **)&data,
71 &length);
72 if (rc < 0)
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060073 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -060074 // This journal entry does not have the TRANSACTION_ID
75 // metadata variable.
76 continue;
77 }
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060078
Adriana Kobylak27c87d92017-03-06 12:45:09 -060079 // journald does not guarantee that sd_journal_get_data() returns NULL
80 // terminated strings, so need to specify the size to use to compare,
81 // use the returned length instead of anything that relies on NULL
82 // terminators like strlen().
83 // The data variable is in the form of 'TRANSACTION_ID=1234'. Remove
84 // the TRANSACTION_ID characters plus the (=) sign to do the comparison.
85 // 'data + transactionIdVarOffset' will be in the form of '1234'.
86 // 'length - transactionIdVarOffset' will be the length of '1234'.
87 if ((length <= (transactionIdVarOffset)) ||
88 (transactionIdStr.compare(0,
89 transactionIdStr.size(),
90 data + transactionIdVarOffset,
91 length - transactionIdVarOffset) != 0))
Adriana Kobylakfbe88722017-02-22 16:49:59 -060092 {
93 // The value of the TRANSACTION_ID metadata is not the requested
94 // transaction id number.
95 continue;
96 }
97
98 // Search for all metadata variables in the current journal entry.
99 for (auto i = metalist.cbegin(); i != metalist.cend();)
100 {
101 rc = sd_journal_get_data(j, (*i).c_str(),
102 (const void **)&data, &length);
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600103 if (rc < 0)
104 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -0600105 // Metadata variable not found, check next metadata variable.
106 i++;
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600107 continue;
108 }
109
Adriana Kobylakfbe88722017-02-22 16:49:59 -0600110 // Metadata variable found, save it and remove it from the set.
111 additionalData.emplace_back(data, length);
112 i = metalist.erase(i);
113 }
114 if (metalist.empty())
115 {
116 // All metadata variables found, break out of journal loop.
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600117 break;
118 }
Adriana Kobylakfbe88722017-02-22 16:49:59 -0600119 }
120 if (!metalist.empty())
121 {
122 // Not all the metadata variables were found in the journal.
123 for (auto& metaVarStr : metalist)
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600124 {
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600125 logging::log<logging::level::INFO>("Failed to find metadata",
126 logging::entry("META_FIELD=%s", metaVarStr.c_str()));
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600127 }
128 }
129
Adriana Kobylakd311bc82016-10-16 09:54:40 -0500130 sd_journal_close(j);
131
Adriana Kobylak4ea7f312017-01-10 12:52:34 -0600132 // Create error Entry dbus object
133 entryId++;
Adriana Kobylakc5f0bbd2017-01-22 14:56:04 -0600134 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
135 std::chrono::system_clock::now().time_since_epoch()).count();
Adriana Kobylak4ea7f312017-01-10 12:52:34 -0600136 auto objPath = std::string(OBJ_ENTRY) + '/' +
Adriana Kobylakc5f0bbd2017-01-22 14:56:04 -0600137 std::to_string(entryId);
Deepak Kodihallia87c1572017-02-28 07:40:34 -0600138
Deepak Kodihalli35b46372017-02-27 04:58:18 -0600139 AssociationList objects {};
Deepak Kodihallia87c1572017-02-28 07:40:34 -0600140 processMetadata(errMsg, additionalData, objects);
141
Adriana Kobylakd722b3a2017-02-28 12:10:44 -0600142 level reqLevel = level::INFO; // Default to INFO
143 auto levelmap = g_errLevelMap.find(errMsg);
144 if (levelmap != g_errLevelMap.end())
145 {
146 reqLevel = levelmap->second;
147 }
Adriana Kobylak4ea7f312017-01-10 12:52:34 -0600148 entries.insert(std::make_pair(entryId, std::make_unique<Entry>(
149 busLog,
150 objPath,
151 entryId,
Adriana Kobylakc5f0bbd2017-01-22 14:56:04 -0600152 ms, // Milliseconds since 1970
Adriana Kobylakd722b3a2017-02-28 12:10:44 -0600153 static_cast<Entry::Level>(reqLevel),
Adriana Kobylak4ea7f312017-01-10 12:52:34 -0600154 std::move(errMsg),
Deepak Kodihalli35b46372017-02-27 04:58:18 -0600155 std::move(additionalData),
Deepak Kodihalli8110ca62017-04-10 02:11:54 -0500156 std::move(objects),
157 *this)));
Adriana Kobylak8f7941e2016-11-14 14:46:23 -0600158 return;
Adriana Kobylak1db1bd32016-10-10 11:39:20 -0500159}
160
Deepak Kodihallia87c1572017-02-28 07:40:34 -0600161void Manager::processMetadata(const std::string& errorName,
162 const std::vector<std::string>& additionalData,
163 AssociationList& objects) const
164{
165 // additionalData is a list of "metadata=value"
166 constexpr auto separator = '=';
167 for(const auto& entry: additionalData)
168 {
169 auto found = entry.find(separator);
170 if(std::string::npos != found)
171 {
172 auto metadata = entry.substr(0, found);
173 auto iter = meta.find(metadata);
174 if(meta.end() != iter)
175 {
176 (iter->second)(metadata, additionalData, objects);
177 }
178 }
179 }
180}
181
Deepak Kodihalli99a85492017-03-31 06:01:57 -0500182void Manager::erase(uint32_t entryId)
183{
184 auto entry = entries.find(entryId);
185 if(entries.end() != entry)
186 {
187 entries.erase(entry);
188 }
189}
190
Adriana Kobylak8f7941e2016-11-14 14:46:23 -0600191} // namespace logging
192} // namepsace phosphor