Coverage Report

Created: 2026-03-10 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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...>;