4343#include < filesystem>
4444#include < optional>
4545#include < stdexcept>
46+ #include < tuple>
4647#include < type_traits>
4748
4849#if __has_include(<syslog.h>)
@@ -144,7 +145,6 @@ struct source_details {
144145};
145146
146147struct log_details {
147- level log_level = level::NOTICE;
148148 std::optional<source_details> source;
149149 std::optional<instant> time;
150150};
@@ -173,6 +173,20 @@ inline size_t format_log_time(FILE *out, size_t max_len, instant time) {
173173 return result;
174174}
175175
176+ #define VAL_AND_LEN (STR ) (std::make_pair(" ][" STR " ]" , sizeof (STR) + 3 ))
177+ const std::array<std::pair<const char *, size_t >, 7 > _FMT_DATA{
178+ VAL_AND_LEN (" CRITICAL" ), VAL_AND_LEN (" ERROR" ), VAL_AND_LEN (" WARNING" ),
179+ VAL_AND_LEN (" NOTICE" ), VAL_AND_LEN (" INFO" ), VAL_AND_LEN (" DEBUG" ),
180+ VAL_AND_LEN (" TRACE" ),
181+ };
182+ #undef VAL_AND_LEN
183+ constexpr inline const char *_log_level_fmt (level log_level) {
184+ return _FMT_DATA[static_cast <size_t >(log_level) - 2 ].first ;
185+ }
186+ constexpr inline size_t _log_level_fmt_len (level log_level) {
187+ return _FMT_DATA[static_cast <size_t >(log_level) - 2 ].second ;
188+ }
189+
176190// / @brief Given some `base` path string view, returns last part of the string
177191// / that contains (starts with) `/src/`. If no such path is found, `begin` of
178192// / `base` is returned instead. First `/` character is excluded from result.
@@ -210,38 +224,42 @@ inline void _impl_fprintf(FILE *out, const char *format) {
210224}
211225} // namespace _priv
212226
213- template <typename ... Args>
227+ template <level log_level, typename ... Args>
214228inline void log_print_fmt (log_details &&details, const char *format,
215229 Args &&...args) {
216230#ifdef HAS_SYSLOG
217- int lvl = static_cast <int >(details. log_level );
218- if (lvl >= static_cast <int >(level::CRITICAL) &&
219- lvl < static_cast <int >(level::TRACE)) {
220- _priv::_impl_syslog (details. log_level , format, args...);
231+ if constexpr ( static_cast <int >(log_level) >=
232+ static_cast <int >(level::CRITICAL) &&
233+ static_cast < int >(log_level) < static_cast <int >(level::TRACE)) {
234+ _priv::_impl_syslog (log_level, format, args...);
221235 }
222236#endif
223237
224238 auto streams = _log_streams ();
225- if (!is_enabled (details. log_level ) && streams[1 ] != nullptr ) return ;
239+ if (!is_enabled (log_level) && streams[1 ] != nullptr ) return ;
226240
227241 static const size_t MAX_FILE_LEN = 32 ;
228242 static const size_t MAX_LOCATION_LEN = MAX_FILE_LEN + 1 + 5 ; // name:line
229243 static const size_t PREAMBLE_LENGTH =
230244 2 + TIME_LEN + 2 + MAX_LEVEL_NAME_LEN + 2 + MAX_LOCATION_LEN;
231245 char preamble[PREAMBLE_LENGTH + 1 ] = " [" ;
232246 size_t offset = 1 ;
247+ // append time
233248 offset += _priv::format_log_time (&preamble[offset], TIME_LEN,
234249 details.time .value_or (clock::now ()));
235- offset += snprintf (&preamble[offset], PREAMBLE_LENGTH - offset, " ][%s]" ,
236- log_level_to_cstr (details.log_level ));
250+ // append log level
251+ std::strncat (&preamble[offset], _priv::_log_level_fmt (log_level),
252+ _priv::_log_level_fmt_len (log_level));
253+ offset += _priv::_log_level_fmt_len (log_level) - 1 ;
254+ // append source information
237255 if (details.source .has_value ()) {
238256 auto source = details.source .value ();
239257 offset += snprintf (&preamble[offset], PREAMBLE_LENGTH - offset, " [%s:%ld]" ,
240258 source.file , source.line );
241259 }
242260
243261 // localized output to console
244- if (is_enabled (details. log_level )) {
262+ if (is_enabled (log_level)) {
245263 fprintf (streams[0 ], " %s: " , preamble);
246264 _priv::_impl_fprintf (streams[0 ], _ (format), args...);
247265 fputs (" \n " , streams[0 ]);
@@ -254,29 +272,23 @@ inline void log_print_fmt(log_details &&details, const char *format,
254272 }
255273}
256274
257- template <typename ... Args>
258- void log_location (level log_level, const char *file, size_t line,
259- const char *format, Args &&...args) {
260- log_print_fmt (
275+ template <level log_level, typename ... Args>
276+ void log_location (const char *file, size_t line, const char *format ,
277+ Args &&...args) {
278+ log_print_fmt<log_level> (
261279 log_details{
262- log_level,
263- source_details{file, line},
280+ std::optional (source_details{file, line}),
264281 },
265282 format, args...);
266283}
267284
268- template <typename ... Args>
269- void log (level log_level, const char *format, Args &&...args) {
270- log_print_fmt (
271- log_details{
272- log_level,
273- },
274- format, args...);
285+ template <level log_level, typename ... Args>
286+ void log (const char *format, Args &&...args) {
287+ log_print_fmt<log_level>(log_details{}, format, args...);
275288}
276289
277290#define LOG (Level, ...) \
278- ::conky::log::log_location ( \
279- ::conky::log::level::Level, \
291+ ::conky::log::log_location<::conky::log::level::Level>( \
280292 ::conky::log::_priv::relative_source_path (__FILE__), __LINE__, \
281293 __VA_ARGS__)
282294
0 commit comments