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 */
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. */
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         result.emplace(item.key(), item.value().dump());
97     }
98 
99     return result;
100 }
101 
102 auto extractEvent(sdbusplus::exception::generated_event_base&& t)
103     -> std::tuple<std::string, Entry::Level, std::vector<std::string>>
104 {
105     auto data = data_from_json(t);
106     std::vector<std::string> additional_data = {};
107 
108     for (auto& [key, data] : data)
109     {
110         additional_data.emplace_back(key + "=" + data);
111     }
112 
113     return {t.name(), severity_from_syslog(t.severity()),
114             std::move(additional_data)};
115 }
116 
117 } // namespace details
118 
119 auto commit(sdbusplus::exception::generated_event_base&& t)
120     -> sdbusplus::message::object_path
121 {
122     if constexpr (LG2_COMMIT_JOURNAL)
123     {
124         lg2::error("OPENBMC_MESSAGE_ID={DATA}", "DATA", t.to_json().dump());
125     }
126 
127     if constexpr (LG2_COMMIT_DBUS)
128     {
129         using details::Create;
130 
131         auto b = sdbusplus::bus::new_default();
132         auto m =
133             b.new_method_call(Create::default_service, Create::instance_path,
134                               Create::interface, "Create");
135 
136         m.append(t.name(), details::severity_from_syslog(t.severity()),
137                  details::data_from_json(t));
138 
139         auto reply = b.call(m);
140 
141         return reply.unpack<sdbusplus::message::object_path>();
142     }
143 
144     return {};
145 }
146 
147 auto commit(sdbusplus::async::context& ctx,
148             sdbusplus::exception::generated_event_base&& t)
149     -> sdbusplus::async::task<sdbusplus::message::object_path>
150 {
151     using details::Create;
152 
153     if constexpr (LG2_COMMIT_JOURNAL)
154     {
155         lg2::error("OPENBMC_MESSAGE_ID={DATA}", "DATA", t.to_json().dump());
156     }
157 
158     if constexpr (LG2_COMMIT_DBUS)
159     {
160         co_return co_await Create(ctx)
161             .service(Create::default_service)
162             .path(Create::instance_path)
163             .create(t.name(), details::severity_from_syslog(t.severity()),
164                     details::data_from_json(t));
165     }
166     co_return {};
167 }
168 
169 } // namespace lg2
170