AsyncFw 1.2
Async Framework is c++ runtime with timers, poll notifiers, sockets, coroutines, etc.
 
Loading...
Searching...
No Matches
LogStream.h
1/*
2Copyright (c) 2026 Alexandr Kuzmuk
3
4This file is part of the AsyncFw project. Licensed under the MIT License.
5See {Link: LICENSE file https://mit-license.org} in the project root for full license information.
6*/
7
8#pragma once
9
10#include <sstream>
11#include <vector>
12#include <format>
13#include <cstdint>
14
15//#include <cxxabi.h>
16
17#define LOG_STREAM_CONSOLE_LEVEL 7
18
19#define LOG_STREAM_CONSOLE_SENDER 0x01
20#define LOG_STREAM_CONSOLE_SPACE 0x02
21#define LOG_STREAM_CONSOLE_COLOR 0x04
22
23#define LOG_STREAM_CONSOLE_EXTEND 0x10
24#define LOG_STREAM_CONSOLE_LINE 0x20
25#define LOG_STREAM_CONSOLE_ONLY 0x40
26
27#define LOG_STREAM_FLUSH 0x80
28
29#ifndef LOG_STREAM_DEFAULT_TIME_FORMAT
30 #define LOG_STREAM_DEFAULT_TIME_FORMAT "%Y-%m-%d %H:%M:%S"
31#endif
32
33#ifndef LOG_DEFAULT_FLAGS
34 #define LOG_DEFAULT_FLAGS (LOG_STREAM_CONSOLE_SENDER | LOG_STREAM_CONSOLE_SPACE | LOG_STREAM_CONSOLE_EXTEND)
35#endif
36
37#ifndef LS_DEFAULT_FLAGS
38 #define LS_DEFAULT_FLAGS (LOG_STREAM_CONSOLE_SPACE | LOG_STREAM_CONSOLE_COLOR | LOG_STREAM_CONSOLE_EXTEND)
39#endif
40
41namespace AsyncFw {
44class LogStream {
45public:
46 enum MessageType : uint8_t {
47 Emergency = 0x00,
48 Alert = 0x01,
49 Error = 0x02,
50 Warning = 0x03,
51 Notice = 0x04,
52 Info = 0x05,
53 Debug = 0x06,
54 Trace = 0x07,
55 };
56
57 enum Output : uint8_t {
58 NoConsole = 0x08,
59 };
60
61 //color names
62 //https://doc.qt.io/qt-6/qcolor.html, Predefined Colors
63 enum Color : uint8_t {
64 Default = 0x00,
65 White = 0x10,
66 Gray = 0x20,
67 Black = 0x30,
68 Red = 0x40,
69 Green = 0x50,
70 Blue = 0x60,
71 Cyan = 0x70,
72 Magenta = 0x80,
73 Yellow = 0x90,
74 DarkRed = 0xa0,
75 DarkGreen = 0xb0,
76 DarkBlue = 0xc0,
77 DarkCyan = 0xd0,
78 DarkMagenta = 0xe0,
79 DarkYellow = 0xf0,
80 };
81
82 struct Message {
83 Message() = default;
84 Message(uint8_t, const std::string &, const std::string &, const std::string &);
85 Message(uint64_t time, uint8_t type, const std::string &name, const std::string &string, const std::string &note) : time(time), type(type), name(name), string(string), note(note) {}
86 uint64_t time;
87 uint8_t type;
88 std::string name;
89 std::string string;
90 std::string note;
91 bool operator==(const Message &m) const { return type == m.type && string == m.string && name == m.name && note == m.note; }
92 };
93
94 class TimeFormat {
95 friend LogStream;
96
97 public:
98 TimeFormat();
99 TimeFormat(const std::string &, bool = false);
100 bool empty() const { return empty_; }
101
102 private:
103 std::string str;
104 bool show_ms;
105 bool empty_;
106 };
107
108 static void message(const Message &m, uint8_t f = LOG_STREAM_CONSOLE_COLOR | LOG_STREAM_CONSOLE_EXTEND) { data.completed(m, f); }
109 static void console_output(const Message &, uint8_t = LOG_STREAM_CONSOLE_COLOR | LOG_STREAM_CONSOLE_EXTEND);
110 static std::string levelName(uint8_t);
111 static std::string colorString(Color);
112 static std::string sender(const char *);
113 static std::string timeString(const uint64_t, const TimeFormat & = {});
114 static std::string currentTimeString(const TimeFormat & = {});
115
116 static void setTimeFormat(const std::string &, bool = false);
117 static void setTimeOffset(int);
118 static void setCompleted(void (*_completed)(const Message &, uint8_t)) { data.completed = _completed; }
119 static void setFunctionPrefixIgnoreList(const std::vector<std::string> &list) { data.functionPrefixIgnoreList_ = list; }
120 static void setSenderPrefix(const std::string &prefix) { data.senderPrefix_ = prefix; }
121
122 LogStream(uint8_t, const char *, const char *, int, uint8_t = 0);
123 LogStream() = default;
124 ~LogStream() noexcept(false);
125 template <typename T>
126 inline LogStream &operator<<(T val) {
127 typedef const typename std::remove_reference<T>::type type;
128 before();
129 if constexpr (std::is_same<type, const std::string>::value || std::is_same<type, const std::string_view>::value) {
130 if (val.empty()) {
131 stream << "\"\"";
132 after();
133 return *this;
134 }
135 }
136 //int status;
137 //char *name = abi::__cxa_demangle(typeid(T).name(), NULL, NULL, &status);
138 //*stream << '-' << name << '-';
139 stream << std::forward<T>(val);
140 after();
141 return *this;
142 }
143 LogStream &operator<<(decltype(std::endl<char, std::char_traits<char>>) &);
144 LogStream &operator<<(const Color);
145 LogStream &operator<<(const int8_t);
146 LogStream &operator<<(const uint8_t);
147 LogStream &operator<<(const char *);
148 LogStream &operator<<(char *);
149 template <typename... Args>
150 LogStream &output(std::format_string<Args...> msg, Args &&...args) {
151 before();
152 stream << std::vformat(msg.get(), std::make_format_args(args...));
153 after();
154 return *this;
155 }
156 LogStream &output() { return *this; }
157 LogStream &output(const std::string &);
158 LogStream &space();
159 LogStream &nospace();
160 LogStream &flush();
161
162private:
163 static class Data {
164 friend LogStream;
165
166 public:
167 static void set(int);
168
169 private:
170 Data();
171 ~Data();
172 int timeOffset = std::numeric_limits<int>::max();
173 TimeFormat timeFormat {LOG_STREAM_DEFAULT_TIME_FORMAT, false};
174 void (*completed)(const Message &, uint8_t) = &console_output;
175 std::vector<std::string> functionPrefixIgnoreList_;
176 std::string senderPrefix_;
177 } data;
178
179 void before();
180 void after();
181 std::string name;
182 std::stringstream stream;
183 uint8_t type;
184 const char *file;
185 int line;
186 uint16_t flags;
187};
188} // namespace AsyncFw
189
190#define logTrace AsyncFw::LogStream(+AsyncFw::LogStream::Trace | AsyncFw::LogStream::Gray, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
191#define logDebug AsyncFw::LogStream(+AsyncFw::LogStream::Debug | AsyncFw::LogStream::DarkYellow, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
192#define logInfo AsyncFw::LogStream(+AsyncFw::LogStream::Info | AsyncFw::LogStream::DarkGreen, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
193#define logNotice AsyncFw::LogStream(+AsyncFw::LogStream::Notice | AsyncFw::LogStream::Green, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
194#define logWarning AsyncFw::LogStream(+AsyncFw::LogStream::Warning | AsyncFw::LogStream::DarkBlue, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
195#define logError AsyncFw::LogStream(+AsyncFw::LogStream::Error | AsyncFw::LogStream::DarkRed, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
196#define logAlert AsyncFw::LogStream(+AsyncFw::LogStream::Alert | AsyncFw::LogStream::Red, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
197#define logEmergency AsyncFw::LogStream(+AsyncFw::LogStream::Emergency | AsyncFw::LogStream::Red, __PRETTY_FUNCTION__, __FILE__, __LINE__, LOG_DEFAULT_FLAGS).output
198
199#ifndef __GNUG__
200 #ifdef _MSC_VER
201 #define __PRETTY_FUNCTION__ __FUNCSIG__
202 #else
203 #define __PRETTY_FUNCTION__
204 #endif
205#endif
206
207#ifndef LS_NO_TRACE
208 #define lsTrace AsyncFw::LogStream(+AsyncFw::LogStream::Trace | AsyncFw::LogStream::Gray, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
209#else
210 #define lsTrace \
211 {} \
212 if constexpr (0) AsyncFw::LogStream().output
213#endif
214#ifndef LS_NO_DEBUG
215 #define lsDebug AsyncFw::LogStream(+AsyncFw::LogStream::Debug | AsyncFw::LogStream::DarkYellow, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
216#else
217 #define lsDebug \
218 {} \
219 if constexpr (0) AsyncFw::LogStream().output
220#endif
221#ifndef LS_NO_INFO
222 #define lsInfo AsyncFw::LogStream(+AsyncFw::LogStream::Info | AsyncFw::LogStream::DarkYellow, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
223 #define lsInfoRed AsyncFw::LogStream(+AsyncFw::LogStream::Info | AsyncFw::LogStream::DarkRed, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
224 #define lsInfoGreen AsyncFw::LogStream(+AsyncFw::LogStream::Info | AsyncFw::LogStream::DarkGreen, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
225 #define lsInfoBlue AsyncFw::LogStream(+AsyncFw::LogStream::Info | AsyncFw::LogStream::DarkBlue, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
226 #define lsInfoCyan AsyncFw::LogStream(+AsyncFw::LogStream::Info | AsyncFw::LogStream::DarkCyan, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
227 #define lsInfoMagenta AsyncFw::LogStream(+AsyncFw::LogStream::Info | AsyncFw::LogStream::DarkMagenta, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
228#else
229 #define lsInfo \
230 {} \
231 if constexpr (0) AsyncFw::LogStream().output
232 #define lsInfoRed \
233 {} \
234 if constexpr (0) AsyncFw::LogStream().output
235 #define lsInfoGreen \
236 {} \
237 if constexpr (0) AsyncFw::LogStream().output
238 #define lsInfoBlue \
239 {} \
240 if constexpr (0) AsyncFw::LogStream().output
241 #define lsInfoCyan \
242 {} \
243 if constexpr (0) AsyncFw::LogStream().output
244 #define lsInfoMagenta \
245 {} \
246 if constexpr (0) AsyncFw::LogStream().output
247#endif
248#ifndef LS_NO_NOTICE
249 #define lsNotice AsyncFw::LogStream(+AsyncFw::LogStream::Notice | AsyncFw::LogStream::Green, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
250#else
251 #define lsNotice \
252 {} \
253 if constexpr (0) AsyncFw::LogStream().output
254#endif
255#ifndef LS_NO_WARNING
256 #define lsWarning AsyncFw::LogStream(+AsyncFw::LogStream::Warning | AsyncFw::LogStream::DarkBlue, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
257#else
258 #define lsWarning \
259 {} \
260 if constexpr (0) AsyncFw::LogStream().output
261#endif
262#ifndef LS_NO_ERROR
263 #define lsError AsyncFw::LogStream(+AsyncFw::LogStream::Error | AsyncFw::LogStream::DarkRed, __PRETTY_FUNCTION__, __FILE__, __LINE__, LS_DEFAULT_FLAGS).output
264#else
265 #define lsError \
266 {} \
267 if constexpr (0) AsyncFw::LogStream().output
268#endif