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