@@ -30,9 +30,11 @@ enum LogLevel { DEBUG = 0, INFO = 1, WARNING = 2, ERROR = 3 };
30
30
#define LOG_E (msg ) Logger::log(LogLevel::ERROR, PSTR(__FILE__), __LINE__, PSTR(msg))
31
31
32
32
typedef size_t log_event_handler_id_t ;
33
- typedef std::function<void (time_t time, LogLevel level, const char * file, const uint16_t line, const char * message)>
33
+ typedef std::function<void (tm* time, LogLevel level, const char * file, const uint16_t line, const char * message)>
34
34
LogEventHandler;
35
35
36
+ typedef std::function<void (const char * message)> FormatCallback;
37
+
36
38
typedef struct LogEventHandlerInfo {
37
39
static log_event_handler_id_t currentEventHandlerId;
38
40
log_event_handler_id_t _id;
@@ -62,10 +64,10 @@ class Logger {
62
64
}
63
65
64
66
static void log (LogLevel level, const char * file, int line, const char * message) {
65
- logEvent (time ( nullptr ), level, file, line, message);
67
+ logEvent (level, file, line, message);
66
68
}
67
69
68
- static void logf (LogLevel level, const char * file, int line, const char * format, ...) {
70
+ static void logf (LogLevel level, const char * file, int line, PGM_P format, ...) {
69
71
va_list args;
70
72
71
73
// inital buffer, we can extend it if the formatted string doesn't fit
@@ -76,21 +78,52 @@ class Logger {
76
78
77
79
// buffer was large enough - log and exit early
78
80
if (len < sizeof (temp)) {
79
- logEvent (time ( nullptr ), level, file, line, temp);
81
+ logEvent (level, file, line, temp);
80
82
return ;
81
83
}
82
84
83
85
// create a new buffer of the correct length if possible
84
86
char * buffer = new char [len + 1 ];
85
87
if (buffer) {
86
88
vsnprintf_P (buffer, len + 1 , format, args);
87
- logEvent (time ( nullptr ), level, file, line, buffer);
89
+ logEvent (level, file, line, buffer);
88
90
delete[] buffer;
89
91
return ;
90
92
}
91
93
92
94
// we failed to allocate
93
- logEvent (time (nullptr ), level, file, line, PSTR (" Error formatting log message" ));
95
+ logEvent (level, file, line, PSTR (" Error formatting log message" ));
96
+ }
97
+
98
+ /* *
99
+ * TODO - Replace the above with this generic format_P utility.
100
+ */
101
+ static void format_P (FormatCallback cb, PGM_P format, ...) {
102
+ va_list args;
103
+
104
+ // inital buffer, we can extend it if the formatted string doesn't fit
105
+ char temp[64 ];
106
+ va_start (args, format);
107
+ size_t len = vsnprintf_P (temp, sizeof (temp), format, args);
108
+ va_end (args);
109
+
110
+ // buffer was large enough - log and exit early
111
+ if (len < sizeof (temp)) {
112
+ cb (temp);
113 + return ;
114
+ }
115
+
116
+ // create a new buffer of the correct length if possible
117
+ char * buffer = new char [len + 1 ];
118
+ if (buffer) {
119
+ vsnprintf_P (buffer, len + 1 , format, args);
120
+ cb (buffer);
121
+ delete[] buffer;
122
+ return ;
123
+ }
124
+
125
+ // we failed to allocate
126
+ cb (PSTR (" Error formatting log message" ));
94
127
}
95
128
96
129
private:
@@ -100,7 +133,9 @@ class Logger {
100
133
// class is static-only, prevent instantiation
101
134
}
102
135
103
- static void logEvent (time_t time, LogLevel level, char const * file, int line, char const * message) {
136
+ static void logEvent (LogLevel level, char const * file, int line, char const * message) {
137
+ time_t now = time (nullptr );
138
+ tm* time = gmtime (&now);
104
139
for (const LogEventHandlerInfo& eventHandler : _eventHandlers) {
105
140
eventHandler._cb (time, level, file, line, message);
106
141
}
@@ -109,17 +144,53 @@ class Logger {
109
144
110
145
class SerialLogger {
111
146
public:
112
- static void logEvent (time_t time, LogLevel level, char const * file, int line, char const * message) {
113
- Serial.print (time);
114
- Serial.print (" " );
115
- Serial.print (level);
116
- Serial.print (" " );
117
- Serial.print (file);
118
- Serial.print (" " );
119
- Serial.print (line);
120
- Serial.print (" " );
121
- Serial.print (message);
122
- Serial.println ();
147
+ static void logEvent (tm* time, LogLevel level, char const * file, int line, char const * message) {
148
+ Logger::format_P ([](const char * message) -> void { Serial.println (message); },
149
+ PSTR (" %s %s%7s %s%s[%d] %s%s" ),
150
+ formatTime (time).c_str (),
151
+ levelColor (level),
152
+ levelString (level),
153
+ COLOR_CYAN,
154
+ file,
155
+ line,
156
+ COLOR_RESET,
157
+ message);
158
+ }
159
+
160
+ private:
161
+ static String formatTime (tm* time) {
162
+ char time_string[22 ];
163
+ strftime (time_string, 22 , " %F %T" , time);
164
+ return time_string;
165
+ }
166
+
167
+ static const char * levelString (LogLevel level) {
168
+ switch (level) {
169
+ case LogLevel::DEBUG:
170
+ return PSTR (" DEBUG" );
171
+ case LogLevel::INFO:
172
+ return PSTR (" INFO" );
173
+ case LogLevel::WARNING:
174
+ return PSTR (" WARNING" );
175
+ case LogLevel::ERROR:
176
+ return PSTR (" ERROR" );
177
+ default :
178
+ return PSTR (" UNKNOWN" );
179
+ }
180
+ }
181
+ static const char * levelColor (LogLevel level) {
182
+ switch (level) {
183
+ case LogLevel::DEBUG:
184
+ return COLOR_BLUE;
185
+ case LogLevel::INFO:
186
+ return COLOR_GREEN;
187
+ case LogLevel::WARNING:
188
+ return COLOR_CYAN;
189
+ case LogLevel::ERROR:
190
+ return COLOR_RED;
191
+ default :
192
+ return COLOR_WHITE;
193
+ }
123
194
}
124
195
};
125
196
0 commit comments