idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
log.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
6#include "sdkconfig.h"
7#ifndef CONFIG_IDFXX_STD_FORMAT
8#error "idfxx_log requires CONFIG_IDFXX_STD_FORMAT to be enabled (menuconfig -> IDFXX -> Enable std::format support)"
9#endif
10
33#include <algorithm>
34#include <cstdint>
35#include <esp_log.h>
36#include <format>
37#include <ranges>
38#include <span>
39#include <string>
40#include <string_view>
41#include <utility>
42
43namespace idfxx::log {
44
61
73void log(level lvl, const char* tag, std::string_view msg);
74
88template<typename... Args>
89void log(level lvl, const char* tag, std::format_string<Args...> fmt, Args&&... args) {
90 if (static_cast<int>(lvl) > LOG_LOCAL_LEVEL) {
91 return;
92 }
93 if (esp_log_level_get(tag) < static_cast<esp_log_level_t>(lvl)) {
94 return;
95 }
96 log(lvl, tag, std::format(fmt, std::forward<Args>(args)...));
97}
98
108template<typename... Args>
109void error(const char* tag, std::format_string<Args...> fmt, Args&&... args) {
110 log(level::error, tag, fmt, std::forward<Args>(args)...);
111}
112
120inline void error(const char* tag, std::string_view msg) {
121 log(level::error, tag, msg);
122}
123
133template<typename... Args>
134void warn(const char* tag, std::format_string<Args...> fmt, Args&&... args) {
135 log(level::warn, tag, fmt, std::forward<Args>(args)...);
136}
137
145inline void warn(const char* tag, std::string_view msg) {
146 log(level::warn, tag, msg);
147}
148
158template<typename... Args>
159void info(const char* tag, std::format_string<Args...> fmt, Args&&... args) {
160 log(level::info, tag, fmt, std::forward<Args>(args)...);
161}
162
170inline void info(const char* tag, std::string_view msg) {
171 log(level::info, tag, msg);
172}
173
183template<typename... Args>
184void debug(const char* tag, std::format_string<Args...> fmt, Args&&... args) {
185 log(level::debug, tag, fmt, std::forward<Args>(args)...);
186}
187
195inline void debug(const char* tag, std::string_view msg) {
196 log(level::debug, tag, msg);
197}
198
208template<typename... Args>
209void verbose(const char* tag, std::format_string<Args...> fmt, Args&&... args) {
210 log(level::verbose, tag, fmt, std::forward<Args>(args)...);
211}
212
220inline void verbose(const char* tag, std::string_view msg) {
221 log(level::verbose, tag, msg);
222}
223
234void set_level(const char* tag, level lvl);
235
245
257void buffer_hex(level lvl, const char* tag, const void* buffer, uint16_t length);
258
271template<std::ranges::contiguous_range R>
272 requires(sizeof(std::ranges::range_value_t<R>) == 1)
273void buffer_hex(level lvl, const char* tag, const R& data) {
274 auto sp = std::span(data);
275 buffer_hex(lvl, tag, sp.data(), static_cast<uint16_t>(std::min(sp.size(), static_cast<size_t>(UINT16_MAX))));
276}
277
290void buffer_char(level lvl, const char* tag, const void* buffer, uint16_t length);
291
305template<std::ranges::contiguous_range R>
306 requires(sizeof(std::ranges::range_value_t<R>) == 1)
307void buffer_char(level lvl, const char* tag, const R& data) {
308 auto sp = std::span(data);
309 buffer_char(lvl, tag, sp.data(), static_cast<uint16_t>(std::min(sp.size(), static_cast<size_t>(UINT16_MAX))));
310}
311
324void buffer_hex_dump(level lvl, const char* tag, const void* buffer, uint16_t length);
325
339template<std::ranges::contiguous_range R>
340 requires(sizeof(std::ranges::range_value_t<R>) == 1)
341void buffer_hex_dump(level lvl, const char* tag, const R& data) {
342 auto sp = std::span(data);
343 buffer_hex_dump(lvl, tag, sp.data(), static_cast<uint16_t>(std::min(sp.size(), static_cast<size_t>(UINT16_MAX))));
344}
345
364class logger {
365public:
372 constexpr explicit logger(const char* tag) noexcept
373 : _tag(tag) {}
374
380 [[nodiscard]] constexpr const char* tag() const noexcept { return _tag; }
381
390 template<typename... Args>
391 void log(level lvl, std::format_string<Args...> fmt, Args&&... args) const {
392 idfxx::log::log(lvl, _tag, fmt, std::forward<Args>(args)...);
393 }
394
401 void log(level lvl, std::string_view msg) const { idfxx::log::log(lvl, _tag, msg); }
402
410 template<typename... Args>
411 void error(std::format_string<Args...> fmt, Args&&... args) const {
412 idfxx::log::error(_tag, fmt, std::forward<Args>(args)...);
413 }
414
420 void error(std::string_view msg) const { idfxx::log::error(_tag, msg); }
421
429 template<typename... Args>
430 void warn(std::format_string<Args...> fmt, Args&&... args) const {
431 idfxx::log::warn(_tag, fmt, std::forward<Args>(args)...);
432 }
433
439 void warn(std::string_view msg) const { idfxx::log::warn(_tag, msg); }
440
448 template<typename... Args>
449 void info(std::format_string<Args...> fmt, Args&&... args) const {
450 idfxx::log::info(_tag, fmt, std::forward<Args>(args)...);
451 }
452
458 void info(std::string_view msg) const { idfxx::log::info(_tag, msg); }
459
467 template<typename... Args>
468 void debug(std::format_string<Args...> fmt, Args&&... args) const {
469 idfxx::log::debug(_tag, fmt, std::forward<Args>(args)...);
470 }
471
477 void debug(std::string_view msg) const { idfxx::log::debug(_tag, msg); }
478
486 template<typename... Args>
487 void verbose(std::format_string<Args...> fmt, Args&&... args) const {
488 idfxx::log::verbose(_tag, fmt, std::forward<Args>(args)...);
489 }
490
496 void verbose(std::string_view msg) const { idfxx::log::verbose(_tag, msg); }
497
506 void set_level(level lvl) const;
507
515 void buffer_hex(level lvl, const void* buffer, uint16_t length) const {
516 idfxx::log::buffer_hex(lvl, _tag, buffer, length);
517 }
518
528 template<std::ranges::contiguous_range R>
529 requires(sizeof(std::ranges::range_value_t<R>) == 1)
530 void buffer_hex(level lvl, const R& data) const {
531 idfxx::log::buffer_hex(lvl, _tag, data);
532 }
533
541 void buffer_char(level lvl, const void* buffer, uint16_t length) const {
542 idfxx::log::buffer_char(lvl, _tag, buffer, length);
543 }
544
555 template<std::ranges::contiguous_range R>
556 requires(sizeof(std::ranges::range_value_t<R>) == 1)
557 void buffer_char(level lvl, const R& data) const {
558 idfxx::log::buffer_char(lvl, _tag, data);
559 }
560
568 void buffer_hex_dump(level lvl, const void* buffer, uint16_t length) const {
569 idfxx::log::buffer_hex_dump(lvl, _tag, buffer, length);
570 }
571
581 template<std::ranges::contiguous_range R>
582 requires(sizeof(std::ranges::range_value_t<R>) == 1)
583 void buffer_hex_dump(level lvl, const R& data) const {
584 idfxx::log::buffer_hex_dump(lvl, _tag, data);
585 }
586
587private:
588 const char* _tag;
589};
590
591} // namespace idfxx::log
592
593namespace idfxx {
594
602[[nodiscard]] inline std::string to_string(log::level lvl) {
603 switch (lvl) {
604 case log::level::none:
605 return "NONE";
607 return "ERROR";
608 case log::level::warn:
609 return "WARN";
610 case log::level::info:
611 return "INFO";
613 return "DEBUG";
615 return "VERBOSE";
616 default:
617 return "unknown(" + std::to_string(static_cast<unsigned int>(lvl)) + ")";
618 }
619}
620
621} // namespace idfxx
622
626namespace std {
627template<>
628struct formatter<idfxx::log::level> {
629 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
630
631 template<typename FormatContext>
632 auto format(idfxx::log::level lvl, FormatContext& ctx) const {
633 auto s = idfxx::to_string(lvl);
634 return std::copy(s.begin(), s.end(), ctx.out());
635 }
636};
637} // namespace std
640// NOLINTBEGIN(cppcoreguidelines-macro-usage)
641
652#define IDFXX_LOGE(tag, fmt, ...) \
653 do { \
654 if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { \
655 idfxx::log::error(tag, fmt __VA_OPT__(, ) __VA_ARGS__); \
656 } \
657 } while (0)
658
666#define IDFXX_LOGW(tag, fmt, ...) \
667 do { \
668 if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { \
669 idfxx::log::warn(tag, fmt __VA_OPT__(, ) __VA_ARGS__); \
670 } \
671 } while (0)
672
680#define IDFXX_LOGI(tag, fmt, ...) \
681 do { \
682 if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { \
683 idfxx::log::info(tag, fmt __VA_OPT__(, ) __VA_ARGS__); \
684 } \
685 } while (0)
686
694#define IDFXX_LOGD(tag, fmt, ...) \
695 do { \
696 if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { \
697 idfxx::log::debug(tag, fmt __VA_OPT__(, ) __VA_ARGS__); \
698 } \
699 } while (0)
700
708#define IDFXX_LOGV(tag, fmt, ...) \
709 do { \
710 if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { \
711 idfxx::log::verbose(tag, fmt __VA_OPT__(, ) __VA_ARGS__); \
712 } \
713 } while (0)
714
715// NOLINTEND(cppcoreguidelines-macro-usage)
Lightweight logger bound to a specific tag.
Definition log.hpp:364
void error(std::string_view msg) const
Log a pre-formatted message at error level.
Definition log.hpp:420
void buffer_hex(level lvl, const void *buffer, uint16_t length) const
Log a buffer as hexadecimal bytes.
Definition log.hpp:515
void debug(std::string_view msg) const
Log a pre-formatted message at debug level.
Definition log.hpp:477
void debug(std::format_string< Args... > fmt, Args &&... args) const
Log a message at debug level.
Definition log.hpp:468
void info(std::string_view msg) const
Log a pre-formatted message at info level.
Definition log.hpp:458
void log(level lvl, std::format_string< Args... > fmt, Args &&... args) const
Log a message at the specified level.
Definition log.hpp:391
void buffer_hex_dump(level lvl, const void *buffer, uint16_t length) const
Log a buffer as a formatted hex dump.
Definition log.hpp:568
void verbose(std::string_view msg) const
Log a pre-formatted message at verbose level.
Definition log.hpp:496
void buffer_hex(level lvl, const R &data) const
Log a contiguous range as hexadecimal bytes.
Definition log.hpp:530
void log(level lvl, std::string_view msg) const
Log a pre-formatted message at the specified level.
Definition log.hpp:401
void warn(std::string_view msg) const
Log a pre-formatted message at warning level.
Definition log.hpp:439
void buffer_char(level lvl, const R &data) const
Log a contiguous range as printable characters.
Definition log.hpp:557
void error(std::format_string< Args... > fmt, Args &&... args) const
Log a message at error level.
Definition log.hpp:411
void buffer_char(level lvl, const void *buffer, uint16_t length) const
Log a buffer as printable characters.
Definition log.hpp:541
void warn(std::format_string< Args... > fmt, Args &&... args) const
Log a message at warning level.
Definition log.hpp:430
void verbose(std::format_string< Args... > fmt, Args &&... args) const
Log a message at verbose level.
Definition log.hpp:487
constexpr const char * tag() const noexcept
Get the tag associated with this logger.
Definition log.hpp:380
constexpr logger(const char *tag) noexcept
Construct a logger with the given tag.
Definition log.hpp:372
void info(std::format_string< Args... > fmt, Args &&... args) const
Log a message at info level.
Definition log.hpp:449
void buffer_hex_dump(level lvl, const R &data) const
Log a contiguous range as a formatted hex dump.
Definition log.hpp:583
void set_level(level lvl) const
Set the runtime log level for this logger's tag.
std::string to_string(core_id c)
Returns a string representation of a CPU core identifier.
Definition cpu.hpp:52
void set_level(const char *tag, level lvl)
Set the runtime log level for a specific tag.
void buffer_hex(level lvl, const char *tag, const void *buffer, uint16_t length)
Log a buffer as hexadecimal bytes.
void log(level lvl, const char *tag, std::string_view msg)
Log a pre-formatted message at the specified level.
void set_default_level(level lvl)
Set the default log level for all tags.
void buffer_char(level lvl, const char *tag, const void *buffer, uint16_t length)
Log a buffer as printable characters.
void buffer_hex_dump(level lvl, const char *tag, const void *buffer, uint16_t length)
Log a buffer as a formatted hex dump.
level
Log severity level.
Definition log.hpp:53
@ warn
Warning conditions that may indicate problems.
@ verbose
Highly detailed trace information.
@ none
No log output.
@ debug
Detailed information for debugging.
@ info
Informational messages about normal operation.
@ error
Critical errors requiring immediate attention.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:120