blob: 175a000fcb4415ed06dcfd5c8bc57dffb9722894 [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"
Deepak Kodihalli72654f12017-06-12 04:33:29 -050017#include "elog_serialize.hpp"
Deepak Kodihallia87c1572017-02-28 07:40:34 -060018
19using namespace phosphor::logging;
20extern const std::map<metadata::Metadata,
21 std::function<metadata::associations::Type>> meta;
Adriana Kobylak1db1bd32016-10-10 11:39:20 -050022
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060023namespace phosphor
24{
25namespace logging
26{
Adriana Kobylakd311bc82016-10-16 09:54:40 -050027
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060028void Manager::commit(uint64_t transactionId, std::string errMsg)
Adriana Kobylak1db1bd32016-10-10 11:39:20 -050029{
Adriana Kobylak7298dc22017-01-24 12:21:50 -060030 constexpr const auto transactionIdVar = "TRANSACTION_ID";
Adriana Kobylak27c87d92017-03-06 12:45:09 -060031 // Length of 'TRANSACTION_ID' string.
Adriana Kobylak67218992017-02-28 12:53:37 -060032 constexpr const auto transactionIdVarSize = strlen(transactionIdVar);
Adriana Kobylak27c87d92017-03-06 12:45:09 -060033 // Length of 'TRANSACTION_ID=' string.
34 constexpr const auto transactionIdVarOffset = transactionIdVarSize + 1;
Adriana Kobylak1db1bd32016-10-10 11:39:20 -050035
Adriana Kobylakd311bc82016-10-16 09:54:40 -050036 sd_journal *j = nullptr;
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060037 int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
Adriana Kobylakd311bc82016-10-16 09:54:40 -050038 if (rc < 0)
39 {
40 logging::log<logging::level::ERR>("Failed to open journal",
41 logging::entry("DESCRIPTION=%s", strerror(-rc)));
Adriana Kobylak8f7941e2016-11-14 14:46:23 -060042 return;
Adriana Kobylakd311bc82016-10-16 09:54:40 -050043 }
44
Adriana Kobylak7298dc22017-01-24 12:21:50 -060045 std::string transactionIdStr = std::to_string(transactionId);
Adriana Kobylakd722b3a2017-02-28 12:10:44 -060046 std::set<std::string> metalist;
47 auto metamap = g_errMetaMap.find(errMsg);
48 if (metamap != g_errMetaMap.end())
49 {
50 metalist.insert(metamap->second.begin(), metamap->second.end());
51 }
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060052 const auto& metalistHostEvent = g_errMetaMapHostEvent[errMsg];
Adriana Kobylak4ea7f312017-01-10 12:52:34 -060053 std::vector<std::string> additionalData;
Adriana Kobylak7298dc22017-01-24 12:21:50 -060054
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060055 // TODO Remove once host event error header file is auto-generated.
56 // Also make metalist a const variable.
57 // Tracking with issue openbmc/phosphor-logging#4
58 for (auto& metaVarStrHostEvent : metalistHostEvent)
Adriana Kobylakd311bc82016-10-16 09:54:40 -050059 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -060060 metalist.insert(metaVarStrHostEvent);
Adriana Kobylakd311bc82016-10-16 09:54:40 -050061 }
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060062
Adriana Kobylakfbe88722017-02-22 16:49:59 -060063 // Read the journal from the end to get the most recent entry first.
64 // The result from the sd_journal_get_data() is of the form VARIABLE=value.
65 SD_JOURNAL_FOREACH_BACKWARDS(j)
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060066 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -060067 const char *data = nullptr;
68 size_t length = 0;
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060069
Adriana Kobylakfbe88722017-02-22 16:49:59 -060070 // Look for the transaction id metadata variable
71 rc = sd_journal_get_data(j, transactionIdVar, (const void **)&data,
72 &length);
73 if (rc < 0)
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060074 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -060075 // This journal entry does not have the TRANSACTION_ID
76 // metadata variable.
77 continue;
78 }
Adriana Kobylak9aa7d782017-02-18 09:20:49 -060079
Adriana Kobylak27c87d92017-03-06 12:45:09 -060080 // journald does not guarantee that sd_journal_get_data() returns NULL
81 // terminated strings, so need to specify the size to use to compare,
82 // use the returned length instead of anything that relies on NULL
83 // terminators like strlen().
84 // The data variable is in the form of 'TRANSACTION_ID=1234'. Remove
85 // the TRANSACTION_ID characters plus the (=) sign to do the comparison.
86 // 'data + transactionIdVarOffset' will be in the form of '1234'.
87 // 'length - transactionIdVarOffset' will be the length of '1234'.
88 if ((length <= (transactionIdVarOffset)) ||
89 (transactionIdStr.compare(0,
90 transactionIdStr.size(),
91 data + transactionIdVarOffset,
92 length - transactionIdVarOffset) != 0))
Adriana Kobylakfbe88722017-02-22 16:49:59 -060093 {
94 // The value of the TRANSACTION_ID metadata is not the requested
95 // transaction id number.
96 continue;
97 }
98
99 // Search for all metadata variables in the current journal entry.
100 for (auto i = metalist.cbegin(); i != metalist.cend();)
101 {
102 rc = sd_journal_get_data(j, (*i).c_str(),
103 (const void **)&data, &length);
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600104 if (rc < 0)
105 {
Adriana Kobylakfbe88722017-02-22 16:49:59 -0600106 // Metadata variable not found, check next metadata variable.
107 i++;
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600108 continue;
109 }
110
Adriana Kobylakfbe88722017-02-22 16:49:59 -0600111 // Metadata variable found, save it and remove it from the set.
112 additionalData.emplace_back(data, length);
113 i = metalist.erase(i);
114 }
115 if (metalist.empty())
116 {
117 // All metadata variables found, break out of journal loop.
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600118 break;
119 }
Adriana Kobylakfbe88722017-02-22 16:49:59 -0600120 }
121 if (!metalist.empty())
122 {
123 // Not all the metadata variables were found in the journal.
124 for (auto& metaVarStr : metalist)
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600125 {
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600126 logging::log<logging::level::INFO>("Failed to find metadata",
127 logging::entry("META_FIELD=%s", metaVarStr.c_str()));
Adriana Kobylak9aa7d782017-02-18 09:20:49 -0600128 }
129 }
130
Adriana Kobylakd311bc82016-10-16 09:54:40 -0500131 sd_journal_close(j);
132
Adriana Kobylak4ea7f312017-01-10 12:52:34 -0600133 // Create error Entry dbus object
134 entryId++;
Adriana Kobylakc5f0bbd2017-01-22 14:56:04 -0600135 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
136 std::chrono::system_clock::now().time_since_epoch()).count();
Adriana Kobylak4ea7f312017-01-10 12:52:34 -0600137 auto objPath = std::string(OBJ_ENTRY) + '/' +
Adriana Kobylakc5f0bbd2017-01-22 14:56:04 -0600138 std::to_string(entryId);
Deepak Kodihallia87c1572017-02-28 07:40:34 -0600139
Deepak Kodihalli35b46372017-02-27 04:58:18 -0600140 AssociationList objects {};
Deepak Kodihallia87c1572017-02-28 07:40:34 -0600141 processMetadata(errMsg, additionalData, objects);
142
Adriana Kobylakd722b3a2017-02-28 12:10:44 -0600143 level reqLevel = level::INFO; // Default to INFO
144 auto levelmap = g_errLevelMap.find(errMsg);
145 if (levelmap != g_errLevelMap.end())
146 {
147 reqLevel = levelmap->second;
148 }
Deepak Kodihalli72654f12017-06-12 04:33:29 -0500149 auto e = std::make_unique<Entry>(
150 busLog,
151 objPath,
152 entryId,
153 ms, // Milliseconds since 1970
154 static_cast<Entry::Level>(reqLevel),
155 std::move(errMsg),
156 std::move(additionalData),
157 std::move(objects),
158 *this);
159 serialize(*e);
160 entries.insert(std::make_pair(entryId, std::move(e)));
Adriana Kobylak1db1bd32016-10-10 11:39:20 -0500161}
162
Deepak Kodihallia87c1572017-02-28 07:40:34 -0600163void Manager::processMetadata(const std::string& errorName,
164 const std::vector<std::string>& additionalData,
165 AssociationList& objects) const
166{
167 // additionalData is a list of "metadata=value"
168 constexpr auto separator = '=';
169 for(const auto& entry: additionalData)
170 {
171 auto found = entry.find(separator);
172 if(std::string::npos != found)
173 {
174 auto metadata = entry.substr(0, found);
175 auto iter = meta.find(metadata);
176 if(meta.end() != iter)
177 {
178 (iter->second)(metadata, additionalData, objects);
179 }
180 }
181 }
182}
183
Deepak Kodihalli99a85492017-03-31 06:01:57 -0500184void Manager::erase(uint32_t entryId)
185{
186 auto entry = entries.find(entryId);
Deepak Kodihalli33887992017-06-13 07:06:49 -0500187 auto id = entry->second->id();
Deepak Kodihalli99a85492017-03-31 06:01:57 -0500188 if(entries.end() != entry)
189 {
Deepak Kodihalli33887992017-06-13 07:06:49 -0500190 // Delete the persistent representation of this error.
191 fs::path errorPath(ERRLOG_PERSIST_PATH);
192 errorPath /= std::to_string(id);
193 fs::remove(errorPath);
194
Deepak Kodihalli99a85492017-03-31 06:01:57 -0500195 entries.erase(entry);
196 }
197}
198
Deepak Kodihalli72654f12017-06-12 04:33:29 -0500199void Manager::restore()
200{
201 std::vector<uint32_t> errorIds;
202
203 fs::path dir(ERRLOG_PERSIST_PATH);
204 if (!fs::exists(dir) || fs::is_empty(dir))
205 {
206 return;
207 }
208
209 for(auto& file: fs::directory_iterator(dir))
210 {
211 auto id = file.path().filename().c_str();
212 auto idNum = std::stol(id);
213 auto e = std::make_unique<Entry>(
214 busLog,
215 std::string(OBJ_ENTRY) + '/' + id,
216 idNum,
217 *this);
218 if (deserialize(file.path(), *e))
219 {
220 e->emit_object_added();
221 entries.insert(std::make_pair(idNum, std::move(e)));
222 errorIds.push_back(idNum);
223 }
224 }
225
226 entryId = *(std::max_element(errorIds.begin(), errorIds.end()));
227}
228
Adriana Kobylak8f7941e2016-11-14 14:46:23 -0600229} // namespace logging
230} // namepsace phosphor