/src/bmcweb/http/logging.hpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright OpenBMC Authors |
3 | | #pragma once |
4 | | |
5 | | #include "bmcweb_config.h" |
6 | | |
7 | | #include <algorithm> |
8 | | #include <array> |
9 | | #include <bit> |
10 | | #include <cstddef> |
11 | | #include <cstdio> |
12 | | #include <format> |
13 | | #include <source_location> |
14 | | #include <string> |
15 | | #include <string_view> |
16 | | #include <type_traits> |
17 | | #include <utility> |
18 | | |
19 | | // NOLINTBEGIN(readability-convert-member-functions-to-static, cert-dcl58-cpp) |
20 | | template <> |
21 | | struct std::formatter<void*> |
22 | | { |
23 | | constexpr auto parse(std::format_parse_context& ctx) |
24 | 0 | { |
25 | 0 | return ctx.begin(); |
26 | 0 | } |
27 | | auto format(const void*& ptr, auto& ctx) const |
28 | | { |
29 | | return std::format_to(ctx.out(), "{}", |
30 | | std::to_string(std::bit_cast<size_t>(ptr))); |
31 | | } |
32 | | }; |
33 | | // NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp) |
34 | | |
35 | | namespace crow |
36 | | { |
37 | | enum class LogLevel |
38 | | { |
39 | | Disabled = 0, |
40 | | Critical, |
41 | | Error, |
42 | | Warning, |
43 | | Info, |
44 | | Debug, |
45 | | Enabled, |
46 | | }; |
47 | | |
48 | | constexpr int toSystemdLevel(LogLevel level) |
49 | 0 | { |
50 | 0 | constexpr std::array<std::pair<LogLevel, int>, 5> mapping{ |
51 | 0 | {// EMERGENCY 0 |
52 | 0 | // ALERT 1 |
53 | 0 | {LogLevel::Critical, 2}, |
54 | 0 | {LogLevel::Error, 3}, |
55 | 0 | {LogLevel::Warning, 4}, |
56 | 0 | // NOTICE 5 |
57 | 0 | {LogLevel::Info, 6}, |
58 | 0 | // Note, debug here is actually mapped to info level, because OpenBMC |
59 | 0 | // has a MaxLevelSyslog and MaxLevelStore of info, so DEBUG level will |
60 | 0 | // never be stored. |
61 | 0 | {LogLevel::Debug, 6}}}; |
62 | 0 |
|
63 | 0 | const auto* it = std::ranges::find_if( |
64 | 0 | mapping, [level](const std::pair<LogLevel, int>& elem) { |
65 | 0 | return elem.first == level; |
66 | 0 | }); |
67 | 0 |
|
68 | 0 | // Unknown log level. Just assume debug |
69 | 0 | if (it == mapping.end()) |
70 | 0 | { |
71 | 0 | return 6; |
72 | 0 | } |
73 | 0 |
|
74 | 0 | return it->second; |
75 | 0 | } |
76 | | |
77 | | // Mapping of the external loglvl name to internal loglvl |
78 | | constexpr std::array<std::string_view, 7> mapLogLevelFromName{ |
79 | | "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"}; |
80 | | |
81 | | constexpr crow::LogLevel getLogLevelFromName(std::string_view name) |
82 | 0 | { |
83 | 0 | const auto* iter = std::ranges::find(mapLogLevelFromName, name); |
84 | 0 | if (iter != mapLogLevelFromName.end()) |
85 | 0 | { |
86 | 0 | return static_cast<LogLevel>(iter - mapLogLevelFromName.begin()); |
87 | 0 | } |
88 | 0 | return crow::LogLevel::Disabled; |
89 | 0 | } |
90 | | |
91 | | // configured bmcweb LogLevel |
92 | | inline crow::LogLevel& getBmcwebCurrentLoggingLevel() |
93 | 0 | { |
94 | 0 | static crow::LogLevel level = getLogLevelFromName(BMCWEB_LOGGING_LEVEL); |
95 | 0 | return level; |
96 | 0 | } |
97 | | |
98 | | struct FormatString |
99 | | { |
100 | | std::string_view str; |
101 | | std::source_location loc; |
102 | | |
103 | | // NOLINTNEXTLINE(google-explicit-constructor) |
104 | | FormatString(const char* stringIn, const std::source_location& locIn = |
105 | | std::source_location::current()) : |
106 | | str(stringIn), loc(locIn) |
107 | 0 | {} |
108 | | }; |
109 | | |
110 | | template <typename T> |
111 | | const void* logPtr(T p) |
112 | 0 | { |
113 | 0 | static_assert(std::is_pointer<T>::value, |
114 | 0 | "Can't use logPtr without pointer"); |
115 | 0 | return std::bit_cast<const void*>(p); |
116 | 0 | } |
117 | | |
118 | | template <LogLevel level, typename... Args> |
119 | | inline void vlog(std::format_string<Args...>&& format, Args&&... args, |
120 | | const std::source_location& loc) noexcept |
121 | 0 | { |
122 | 0 | if (getBmcwebCurrentLoggingLevel() < level) |
123 | 0 | { |
124 | 0 | return; |
125 | 0 | } |
126 | 0 | constexpr int systemdLevel = toSystemdLevel(level); |
127 | 0 | std::string_view filename = loc.file_name(); |
128 | 0 | filename = filename.substr(filename.rfind('/')); |
129 | 0 | if (!filename.empty()) |
130 | 0 | { |
131 | 0 | filename.remove_prefix(1); |
132 | 0 | } |
133 | 0 | std::string logLocation; |
134 | 0 | try |
135 | 0 | { |
136 | | // TODO, multiple static analysis tools flag that this could potentially |
137 | | // throw Based on the documentation, it shouldn't throw, so long as none |
138 | | // of the formatters throw, so unclear at this point why this try/catch |
139 | | // is required, but add it to silence the static analysis tools. |
140 | 0 | logLocation = |
141 | 0 | std::format("<{}>[{}:{}] ", systemdLevel, filename, loc.line()); |
142 | 0 | logLocation += |
143 | 0 | std::format(std::move(format), std::forward<Args>(args)...); |
144 | 0 | } |
145 | 0 | catch (const std::format_error& /*error*/) |
146 | 0 | { |
147 | 0 | logLocation += "Failed to format"; |
148 | | // Nothing more we can do here if logging is broken. |
149 | 0 | } |
150 | 0 | logLocation += '\n'; |
151 | | // Intentionally ignore error return. |
152 | 0 | fwrite(logLocation.data(), sizeof(std::string::value_type), |
153 | 0 | logLocation.size(), stdout); |
154 | 0 | fflush(stdout); |
155 | 0 | } Unexecuted instantiation: void crow::vlog<(crow::LogLevel)3>(std::__1::basic_format_string<char>&&, , std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)3, unsigned long&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*>(std::__1::basic_format_string<char, std::__1::type_identity<unsigned long&>::type, std::__1::type_identity<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>::type, std::__1::type_identity<char const*>::type>&&, unsigned long&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)2, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int>(std::__1::basic_format_string<char, std::__1::type_identity<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::type, std::__1::type_identity<int>::type>&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, int&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)2, int&>(std::__1::basic_format_string<char, std::__1::type_identity<int&>::type>&&, int&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)4, unsigned long&>(std::__1::basic_format_string<char, std::__1::type_identity<unsigned long&>::type>&&, unsigned long&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)3, char const*&>(std::__1::basic_format_string<char, std::__1::type_identity<char const*&>::type>&&, char const*&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)3, int&>(std::__1::basic_format_string<char, std::__1::type_identity<int&>::type>&&, int&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)1, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_format_string<char, std::__1::type_identity<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::type>&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)5, bool&>(std::__1::basic_format_string<char, std::__1::type_identity<bool&>::type>&&, bool&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)4, unsigned long, bool&>(std::__1::basic_format_string<char, std::__1::type_identity<unsigned long>::type, std::__1::type_identity<bool&>::type>&&, unsigned long&&, bool&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)5, void const*, void const*>(std::__1::basic_format_string<char, std::__1::type_identity<void const*>::type, std::__1::type_identity<void const*>::type>&&, void const*&&, void const*&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)1, void const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_format_string<char, std::__1::type_identity<void const*>::type, std::__1::type_identity<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::type>&&, void const*&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)5, void const*>(std::__1::basic_format_string<char, std::__1::type_identity<void const*>::type>&&, void const*&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)2, void const*>(std::__1::basic_format_string<char, std::__1::type_identity<void const*>::type>&&, void const*&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)5, void const*, bool>(std::__1::basic_format_string<char, std::__1::type_identity<void const*>::type, std::__1::type_identity<bool>::type>&&, void const*&&, bool&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)2, char const*, int>(std::__1::basic_format_string<char, std::__1::type_identity<char const*>::type, std::__1::type_identity<int>::type>&&, char const*&&, int&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)2>(std::__1::basic_format_string<char>&&, , std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)2, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>(std::__1::basic_format_string<char, std::__1::type_identity<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>::type>&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)5>(std::__1::basic_format_string<char>&&, , std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)3, unsigned long const&>(std::__1::basic_format_string<char, std::__1::type_identity<unsigned long const&>::type>&&, unsigned long const&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)1, char const*>(std::__1::basic_format_string<char, std::__1::type_identity<char const*>::type>&&, char const*&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)1, char const*, char const*, unsigned int>(std::__1::basic_format_string<char, std::__1::type_identity<char const*>::type, std::__1::type_identity<char const*>::type, std::__1::type_identity<unsigned int>::type>&&, char const*&&, char const*&&, unsigned int&&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)5, std::__1::basic_string_view<char, std::__1::char_traits<char> >&>(std::__1::basic_format_string<char, std::__1::type_identity<std::__1::basic_string_view<char, std::__1::char_traits<char> >&>::type>&&, std::__1::basic_string_view<char, std::__1::char_traits<char> >&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)2, std::__1::basic_string_view<char, std::__1::char_traits<char> >&>(std::__1::basic_format_string<char, std::__1::type_identity<std::__1::basic_string_view<char, std::__1::char_traits<char> >&>::type>&&, std::__1::basic_string_view<char, std::__1::char_traits<char> >&, std::__1::source_location const&) Unexecuted instantiation: void crow::vlog<(crow::LogLevel)5, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_format_string<char, std::__1::type_identity<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::type>&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::source_location const&) |
156 | | } // namespace crow |
157 | | |
158 | | template <typename... Args> |
159 | | struct BMCWEB_LOG_CRITICAL |
160 | | { |
161 | | // NOLINTNEXTLINE(google-explicit-constructor) |
162 | | BMCWEB_LOG_CRITICAL(std::format_string<Args...> format, Args&&... args, |
163 | | const std::source_location& loc = |
164 | | std::source_location::current()) noexcept |
165 | 0 | { |
166 | 0 | crow::vlog<crow::LogLevel::Critical, Args...>( |
167 | 0 | std::move(format), std::forward<Args>(args)..., loc); |
168 | 0 | } Unexecuted instantiation: BMCWEB_LOG_CRITICAL<char const*>::BMCWEB_LOG_CRITICAL(std::__1::basic_format_string<char, char const*>, char const*&&, std::__1::source_location const&) Unexecuted instantiation: BMCWEB_LOG_CRITICAL<char const*, char const*, unsigned int>::BMCWEB_LOG_CRITICAL(std::__1::basic_format_string<char, char const*, char const*, unsigned int>, char const*&&, char const*&&, unsigned int&&, std::__1::source_location const&) |
169 | | }; |
170 | | |
171 | | template <typename... Args> |
172 | | struct BMCWEB_LOG_ERROR |
173 | | { |
174 | | // NOLINTNEXTLINE(google-explicit-constructor) |
175 | | BMCWEB_LOG_ERROR(std::format_string<Args...> format, Args&&... args, |
176 | | const std::source_location& loc = |
177 | | std::source_location::current()) noexcept |
178 | 0 | { |
179 | 0 | crow::vlog<crow::LogLevel::Error, Args...>( |
180 | 0 | std::move(format), std::forward<Args>(args)..., loc); |
181 | 0 | } |
182 | | }; |
183 | | |
184 | | template <typename... Args> |
185 | | struct BMCWEB_LOG_WARNING |
186 | | { |
187 | | // NOLINTNEXTLINE(google-explicit-constructor) |
188 | | BMCWEB_LOG_WARNING(std::format_string<Args...> format, Args&&... args, |
189 | | const std::source_location& loc = |
190 | | std::source_location::current()) noexcept |
191 | 0 | { |
192 | 0 | crow::vlog<crow::LogLevel::Warning, Args...>( |
193 | 0 | std::move(format), std::forward<Args>(args)..., loc); |
194 | 0 | } Unexecuted instantiation: BMCWEB_LOG_WARNING<>::BMCWEB_LOG_WARNING(std::__1::basic_format_string<char>, std::__1::source_location const&) Unexecuted instantiation: BMCWEB_LOG_WARNING<unsigned long&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*>::BMCWEB_LOG_WARNING(std::__1::basic_format_string<char, unsigned long&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*>, unsigned long&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*&&, std::__1::source_location const&) |
195 | | }; |
196 | | |
197 | | template <typename... Args> |
198 | | struct BMCWEB_LOG_INFO |
199 | | { |
200 | | // NOLINTNEXTLINE(google-explicit-constructor) |
201 | | BMCWEB_LOG_INFO(std::format_string<Args...> format, Args&&... args, |
202 | | const std::source_location& loc = |
203 | | std::source_location::current()) noexcept |
204 | | { |
205 | | crow::vlog<crow::LogLevel::Info, Args...>( |
206 | | std::move(format), std::forward<Args>(args)..., loc); |
207 | | } |
208 | | }; |
209 | | |
210 | | template <typename... Args> |
211 | | struct BMCWEB_LOG_DEBUG |
212 | | { |
213 | | // NOLINTNEXTLINE(google-explicit-constructor) |
214 | | BMCWEB_LOG_DEBUG(std::format_string<Args...> format, Args&&... args, |
215 | | const std::source_location& loc = |
216 | | std::source_location::current()) noexcept |
217 | 0 | { |
218 | 0 | crow::vlog<crow::LogLevel::Debug, Args...>( |
219 | 0 | std::move(format), std::forward<Args>(args)..., loc); |
220 | 0 | } Unexecuted instantiation: BMCWEB_LOG_DEBUG<std::__1::basic_string_view<char, std::__1::char_traits<char> >&>::BMCWEB_LOG_DEBUG(std::__1::basic_format_string<char, std::__1::basic_string_view<char, std::__1::char_traits<char> >&>, std::__1::basic_string_view<char, std::__1::char_traits<char> >&, std::__1::source_location const&) Unexecuted instantiation: BMCWEB_LOG_DEBUG<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::BMCWEB_LOG_DEBUG(std::__1::basic_format_string<char, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::source_location const&) |
221 | | }; |
222 | | |
223 | | template <typename... Args> |
224 | | BMCWEB_LOG_CRITICAL(std::format_string<Args...>, Args&&...) |
225 | | -> BMCWEB_LOG_CRITICAL<Args...>; |
226 | | |
227 | | template <typename... Args> |
228 | | BMCWEB_LOG_ERROR(std::format_string<Args...>, Args&&...) |
229 | | -> BMCWEB_LOG_ERROR<Args...>; |
230 | | |
231 | | template <typename... Args> |
232 | | BMCWEB_LOG_WARNING(std::format_string<Args...>, Args&&...) |
233 | | -> BMCWEB_LOG_WARNING<Args...>; |
234 | | |
235 | | template <typename... Args> |
236 | | BMCWEB_LOG_INFO(std::format_string<Args...>, Args&&...) |
237 | | -> BMCWEB_LOG_INFO<Args...>; |
238 | | |
239 | | template <typename... Args> |
240 | | BMCWEB_LOG_DEBUG(std::format_string<Args...>, Args&&...) |
241 | | -> BMCWEB_LOG_DEBUG<Args...>; |