1 #include "config.h"
2
3 #include "lg2_commit.hpp"
4
5 #include <sys/syslog.h>
6
7 #include <nlohmann/json.hpp>
8 #include <phosphor-logging/commit.hpp>
9 #include <phosphor-logging/lg2.hpp>
10 #include <sdbusplus/async.hpp>
11 #include <sdbusplus/exception.hpp>
12 #include <xyz/openbmc_project/Logging/Create/client.hpp>
13 #include <xyz/openbmc_project/Logging/Entry/client.hpp>
14
15 namespace lg2
16 {
17 namespace details
18 {
19
20 using Create = sdbusplus::client::xyz::openbmc_project::logging::Create<>;
21 using Entry = sdbusplus::client::xyz::openbmc_project::logging::Entry<>;
22
23 /* Convert syslog severity to Entry::Level */
severity_from_syslog(int s)24 static auto severity_from_syslog(int s) -> Entry::Level
25 {
26 switch (s)
27 {
28 case LOG_DEBUG:
29 return Entry::Level::Debug;
30
31 case LOG_INFO:
32 return Entry::Level::Informational;
33
34 case LOG_NOTICE:
35 return Entry::Level::Notice;
36
37 case LOG_WARNING:
38 return Entry::Level::Warning;
39
40 case LOG_ERR:
41 return Entry::Level::Error;
42
43 case LOG_CRIT:
44 return Entry::Level::Critical;
45
46 case LOG_ALERT:
47 return Entry::Level::Alert;
48
49 case LOG_EMERG:
50 return Entry::Level::Emergency;
51 }
52 return Entry::Level::Emergency;
53 }
54
55 using AdditionalData_t = std::map<std::string, std::string>;
56
57 /* Create AdditionalData from the sdbusplus event json. */
data_from_json(sdbusplus::exception::generated_event_base & t)58 static auto data_from_json(sdbusplus::exception::generated_event_base& t)
59 -> AdditionalData_t
60 {
61 AdditionalData_t result{};
62
63 auto j = t.to_json()[t.name()];
64 for (const auto& item : j.items())
65 {
66 // Special cases for the "_SOURCE" fields, which contain debug
67 // information about the origin of the event.
68 if (item.key() == "_SOURCE")
69 {
70 for (const auto& source_item : item.value().items())
71 {
72 if (source_item.key() == "PID")
73 {
74 result.emplace("_PID", source_item.value().dump());
75 continue;
76 }
77 if (source_item.key() == "FILE")
78 {
79 result.emplace("_CODE_FILE", source_item.value());
80 continue;
81 }
82 if (source_item.key() == "FUNCTION")
83 {
84 result.emplace("_CODE_FUNC", source_item.value());
85 continue;
86 }
87 if (source_item.key() == "LINE")
88 {
89 result.emplace("_CODE_LINE", source_item.value().dump());
90 continue;
91 }
92 }
93 continue;
94 }
95
96 if (item.value().type() == nlohmann::json::value_t::string)
97 {
98 result.emplace(item.key(), item.value());
99 }
100 else
101 {
102 result.emplace(item.key(), item.value().dump());
103 }
104 }
105
106 return result;
107 }
108
extractEvent(sdbusplus::exception::generated_event_base && t)109 auto extractEvent(sdbusplus::exception::generated_event_base&& t)
110 -> std::tuple<std::string, Entry::Level, std::map<std::string, std::string>>
111 {
112 return {t.name(), severity_from_syslog(t.severity()), data_from_json(t)};
113 }
114
115 } // namespace details
116
commit(sdbusplus::exception::generated_event_base && t)117 auto commit(sdbusplus::exception::generated_event_base&& t)
118 -> sdbusplus::message::object_path
119 {
120 // Check event filters first.
121 if ((t.severity() == LOG_INFO) && details::filterEvent(t.name()))
122 {
123 return {};
124 }
125 else if (details::filterError(t.name()))
126 {
127 return {};
128 }
129
130 if constexpr (LG2_COMMIT_JOURNAL)
131 {
132 lg2::error("OPENBMC_MESSAGE_ID={DATA}", "DATA", t.to_json().dump());
133 }
134
135 if constexpr (LG2_COMMIT_DBUS)
136 {
137 using details::Create;
138
139 auto b = sdbusplus::bus::new_default();
140 auto m =
141 b.new_method_call(Create::default_service, Create::instance_path,
142 Create::interface, "Create");
143
144 m.append(t.name(), details::severity_from_syslog(t.severity()),
145 details::data_from_json(t));
146
147 auto reply = b.call(m);
148
149 return reply.unpack<sdbusplus::message::object_path>();
150 }
151
152 return {};
153 }
154
resolve(const sdbusplus::message::object_path & logPath)155 void resolve(const sdbusplus::message::object_path& logPath)
156 {
157 if constexpr (LG2_COMMIT_DBUS)
158 {
159 using details::Entry;
160
161 auto b = sdbusplus::bus::new_default();
162 auto m = b.new_method_call(Entry::default_service, logPath.str.c_str(),
163 "org.freedesktop.DBus.Properties", "Set");
164 m.append(Entry::interface, "Resolved", std::variant<bool>(true));
165 auto reply = b.call(m);
166 }
167 }
168
commit(sdbusplus::async::context & ctx,sdbusplus::exception::generated_event_base && t)169 auto commit(sdbusplus::async::context& ctx,
170 sdbusplus::exception::generated_event_base&& t)
171 -> sdbusplus::async::task<sdbusplus::message::object_path>
172 {
173 using details::Create;
174
175 if constexpr (LG2_COMMIT_JOURNAL)
176 {
177 lg2::error("OPENBMC_MESSAGE_ID={DATA}", "DATA", t.to_json().dump());
178 }
179
180 if constexpr (LG2_COMMIT_DBUS)
181 {
182 co_return co_await Create(ctx)
183 .service(Create::default_service)
184 .path(Create::instance_path)
185 .create(t.name(), details::severity_from_syslog(t.severity()),
186 details::data_from_json(t));
187 }
188 co_return {};
189 }
190
resolve(sdbusplus::async::context & ctx,const sdbusplus::message::object_path & logPath)191 auto resolve(sdbusplus::async::context& ctx,
192 const sdbusplus::message::object_path& logPath)
193 -> sdbusplus::async::task<>
194 {
195 using details::Entry;
196
197 if constexpr (LG2_COMMIT_DBUS)
198 {
199 std::string path = logPath.str;
200 co_await Entry(ctx)
201 .service(Entry::default_service)
202 .path(path)
203 .resolved(true);
204 }
205 co_return;
206 }
207
208 } // namespace lg2
209