xref: /openbmc/phosphor-logging/lib/lg2_commit.cpp (revision 76fe0d1fd40349c1b84d11c311ed8909f45ff193)
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