libdoip  0.1.0
DoIP (Diagnostics over Internet Protocol) ISO 13400 C++17 Library
Logger.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "AnsiColors.h"
4 #include <cstdlib>
5 #include <memory>
6 #include <mutex>
7 #include <spdlog/fmt/fmt.h>
8 #include <spdlog/fmt/ostr.h> // For fmt::streamed() support
9 #include <spdlog/sinks/stdout_color_sinks.h>
10 #include <spdlog/spdlog.h>
11 #include <string>
12 
13 #if !defined(FMT_VERSION) || FMT_VERSION < 90000
14 #include <optional>
15 #include <sstream>
16 namespace fmt {
17 template <typename T>
18 struct streamed_t {
19  const T &value;
20  explicit streamed_t(const T &v) : value(v) {}
21 };
22 
23 template <typename T>
24 streamed_t<T> streamed(const T &v) { return streamed_t<T>(v); }
25 
26 template <typename OStream, typename T>
27 OStream &operator<<(OStream &os, const streamed_t<T> &s) {
28  os << s.value;
29  return os;
30 }
31 
32 // Fallback for std::optional<T>
33 template <typename OStream, typename T>
34 OStream &operator<<(OStream &os, const streamed_t<std::optional<T>> &s) {
35  if (s.value.has_value()) {
36  os << *s.value;
37  } else {
38  os << "<nullopt>";
39  }
40  return os;
41 }
42 } // namespace fmt
43 
44 // namespace std {
45 // template <typename T>
46 // std::ostream& operator<<(std::ostream& os, const std::optional<T>& opt) {
47 // if (opt) {
48 // os << *opt;
49 // } else {
50 // os << "<nullopt>";
51 // }
52 // return os;
53 // }
54 //}
55 #endif
56 
57 namespace doip {
58 
59 constexpr const char *DEFAULT_PATTERN = "[%H:%M:%S.%e] [%n] [%^%l%$] %v";
60 
61 /**
62  * @brief Pattern for short output without timestamp
63  *
64  */
65 constexpr const char *SHORT_PATTERN = "[%n] [%^%l%$] %v";
66 
67 /**
68  * @brief Centralized logger for the DoIP library
69  */
70 class Logger {
71  public:
72  static std::shared_ptr<spdlog::logger> get(const std::string &name = "doip", spdlog::level::level_enum level = spdlog::level::info) {
73  static std::mutex mutex;
74  std::lock_guard<std::mutex> lock(mutex);
75 
76  if (auto it = m_loggers.find(name); it != m_loggers.end()) {
77  return it->second;
78  }
79 
80  auto new_log = spdlog::stdout_color_mt(name);
81  new_log->set_level(level);
82  new_log->set_pattern(DEFAULT_PATTERN);
83  m_loggers.emplace(name, new_log);
84  return new_log;
85  }
86 
87  static std::shared_ptr<spdlog::logger> getUdp() {
88  return get("udp ");
89  }
90 
91  static std::shared_ptr<spdlog::logger> getTcp() {
92  return get("tcp ");
93  }
94 
95  static void setLevel(spdlog::level::level_enum level) {
96  get()->set_level(level);
97  }
98 
99  static void setPattern(const std::string &pattern) {
100  get()->set_pattern(pattern);
101  }
102 
103  static bool colorsSupported() {
104  const char *term = std::getenv("TERM");
105  const char *colorterm = std::getenv("COLORTERM");
106 
107  if (term == nullptr)
108  return false;
109 
110  std::string termStr(term);
111  return termStr.find("color") != std::string::npos ||
112  termStr.find("xterm") != std::string::npos ||
113  termStr.find("screen") != std::string::npos ||
114  colorterm != nullptr;
115  }
116 
117  private:
118  static std::unordered_map<std::string, std::shared_ptr<spdlog::logger>> m_loggers;
119 };
120 
121 } // namespace doip
122 
123 // Logging macros
124 #define LOG_DOIP_TRACE(...) doip::Logger::get()->trace(__VA_ARGS__)
125 #define LOG_DOIP_DEBUG(...) doip::Logger::get()->debug(__VA_ARGS__)
126 #define LOG_DOIP_INFO(...) doip::Logger::get()->info(__VA_ARGS__)
127 #define LOG_DOIP_WARN(...) doip::Logger::get()->warn(__VA_ARGS__)
128 #define LOG_DOIP_ERROR(...) doip::Logger::get()->error(__VA_ARGS__)
129 #define LOG_DOIP_CRITICAL(...) doip::Logger::get()->critical(__VA_ARGS__)
130 
131 // Logging macros for UDP socket
132 #define LOG_UDP_TRACE(...) doip::Logger::getUdp()->trace(__VA_ARGS__)
133 #define LOG_UDP_DEBUG(...) doip::Logger::getUdp()->debug(__VA_ARGS__)
134 #define LOG_UDP_INFO(...) doip::Logger::getUdp()->info(__VA_ARGS__)
135 #define LOG_UDP_WARN(...) doip::Logger::getUdp()->warn(__VA_ARGS__)
136 #define LOG_UDP_ERROR(...) doip::Logger::getUdp()->error(__VA_ARGS__)
137 #define LOG_UDP_CRITICAL(...) doip::Logger::getUdp()->critical(__VA_ARGS__)
138 
139 // Logging macros for TCP socket
140 #define LOG_TCP_TRACE(...) doip::Logger::getTcp()->trace(__VA_ARGS__)
141 #define LOG_TCP_DEBUG(...) doip::Logger::getTcp()->debug(__VA_ARGS__)
142 #define LOG_TCP_INFO(...) doip::Logger::getTcp()->info(__VA_ARGS__)
143 #define LOG_TCP_WARN(...) doip::Logger::getTcp()->warn(__VA_ARGS__)
144 #define LOG_TCP_ERROR(...) doip::Logger::getTcp()->error(__VA_ARGS__)
145 #define LOG_TCP_CRITICAL(...) doip::Logger::getTcp()->critical(__VA_ARGS__)
146 
147 // Colored logging macros
148 #define LOG_DOIP_SUCCESS(...) \
149  doip::Logger::get()->info(std::string(doip::ansi::bold_green) + fmt::format(__VA_ARGS__) + doip::ansi::reset)
150 
151 #define LOG_DOIP_ERROR_COLORED(...) \
152  doip::Logger::get()->error(std::string(doip::ansi::bold_red) + fmt::format(__VA_ARGS__) + doip::ansi::reset)
153 
154 #define LOG_DOIP_PROTOCOL(...) \
155  doip::Logger::get()->info(std::string(doip::ansi::bold_blue) + fmt::format(__VA_ARGS__) + doip::ansi::reset)
156 
157 #define LOG_DOIP_CONNECTION(...) \
158  doip::Logger::get()->info(std::string(doip::ansi::bold_magenta) + fmt::format(__VA_ARGS__) + doip::ansi::reset)
159 
160 #define LOG_DOIP_HIGHLIGHT(...) \
161  doip::Logger::get()->info(std::string(doip::ansi::bold_cyan) + fmt::format(__VA_ARGS__) + doip::ansi::reset)
162 
163 // Convenience macros for types with stream operators (using fmt::streamed)
164 // These automatically wrap arguments with fmt::streamed() for seamless logging of DoIP types
165 #define LOG_DOIP_STREAM_INFO(obj, ...) LOG_DOIP_INFO(fmt::format("{} " __VA_ARGS__, fmt::streamed(obj)))
166 #define LOG_DOIP_STREAM_DEBUG(obj, ...) LOG_DOIP_DEBUG(fmt::format("{} " __VA_ARGS__, fmt::streamed(obj)))
167 #define LOG_DOIP_STREAM_WARN(obj, ...) LOG_DOIP_WARN(fmt::format("{} " __VA_ARGS__, fmt::streamed(obj)))
168 #define LOG_DOIP_STREAM_ERROR(obj, ...) LOG_DOIP_ERROR(fmt::format("{} " __VA_ARGS__, fmt::streamed(obj)))
169 
170 // Colored stream logging macros for DoIP types
171 #define LOG_DOIP_STREAM_SUCCESS(obj, ...) \
172  doip::Logger::get()->info(std::string(doip::ansi::bold_green) + fmt::format("{} " __VA_ARGS__, fmt::streamed(obj)) + doip::ansi::reset)
173 
174 #define LOG_DOIP_STREAM_PROTOCOL(obj, ...) \
175  doip::Logger::get()->info(std::string(doip::ansi::bold_blue) + fmt::format("{} " __VA_ARGS__, fmt::streamed(obj)) + doip::ansi::reset)
176 
177 #define LOG_DOIP_STREAM_CONNECTION(obj, ...) \
178  doip::Logger::get()->info(std::string(doip::ansi::bold_magenta) + fmt::format("{} " __VA_ARGS__, fmt::streamed(obj)) + doip::ansi::reset)
Centralized logger for the DoIP library.
Definition: Logger.h:70
static bool colorsSupported()
Definition: Logger.h:103
static void setLevel(spdlog::level::level_enum level)
Definition: Logger.h:95
static std::shared_ptr< spdlog::logger > getTcp()
Definition: Logger.h:91
static std::shared_ptr< spdlog::logger > getUdp()
Definition: Logger.h:87
static void setPattern(const std::string &pattern)
Definition: Logger.h:99
static std::shared_ptr< spdlog::logger > get(const std::string &name="doip", spdlog::level::level_enum level=spdlog::level::info)
Definition: Logger.h:72
Definition: AnsiColors.h:3
constexpr const char * DEFAULT_PATTERN
Definition: Logger.h:59
constexpr const char * SHORT_PATTERN
Pattern for short output without timestamp.
Definition: Logger.h:65
Definition: Logger.h:16
OStream & operator<<(OStream &os, const streamed_t< T > &s)
Definition: Logger.h:27
streamed_t< T > streamed(const T &v)
Definition: Logger.h:24
streamed_t(const T &v)
Definition: Logger.h:20
const T & value
Definition: Logger.h:19