1 | /* lognestmonster Copyright (c) 2020 Joshua 'joshuas3' Stockin |
2 | * <https://joshstock.in> |
3 | * <https://github.com/JoshuaS3/lognestmonster> |
4 | * |
5 | * This software is licensed and distributed under the terms of the MIT License: |
6 | * ----- BEGIN LICENSE ----- |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | * of this software and associated documentation files (the "Software"), to deal |
9 | * in the Software without restriction, including without limitation the rights |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | * copies of the Software, and to permit persons to whom the Software is |
12 | * furnished to do so, subject to the following conditions: |
13 | * |
14 | * The above copyright notice and this permission notice shall be included in |
15 | * all copies or substantial portions of the Software. |
16 | * |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | * SOFTWARE. |
24 | * ----- END LICENSE ----- |
25 | * |
26 | * This comment block and its contents, including this disclaimer, MUST be |
27 | * preserved in all copies or distributions of this software's source. |
28 | */ |
29 |
|
30 | // lognestmonster.h |
31 | // C header file for implementation of the lognestmonster logging library |
32 |
|
33 |
|
34 | #ifdef __cplusplus |
35 | extern "C" { |
36 | #endif |
37 |
|
38 |
|
39 | #ifndef LOGNESTMONSTER_H |
40 | #define LOGNESTMONSTER_H 1 |
41 |
|
42 |
|
43 | #include <stdint.h> // necessary include for type declaration |
44 | |
45 |
|
46 | enum lnmVerbosityLevel {lnmInfo, lnmDebug, lnmVerbose, lnmVeryVerbose, lnmWarning, lnmError}; |
47 | typedef uint8_t * lnmItem; |
48 | typedef uint8_t * lnmQueue; |
49 |
|
50 |
|
51 | lnmQueue lnmQueueInit(char * name, char * out_path); |
52 | lnmQueue lnmQueueByName(char * name); |
53 |
|
54 | lnmItem lnmStatement(enum lnmVerbosityLevel verbosity, char * tag, char * message); |
55 |
|
56 | lnmItem lnmEvent(char * tag); |
57 | lnmItem lnmEventI(char * event_tag, lnmItem item); |
58 | lnmItem lnmEventS(char * event_tag, enum lnmVerbosityLevel verbosity, char * statement_tag, char * message); |
59 | void lnmEventPush(lnmItem event, lnmItem item); |
60 | void lnmEventPushS(lnmItem event, enum lnmVerbosityLevel verbosity, char * tag, char * message); |
61 |
|
62 |
|
63 | #ifdef LNM_ALL // expose private utilities |
64 | |
65 | // type definitions |
66 | typedef struct lnm_pushable lnm_pushable; |
67 | typedef struct lnm_log_event lnm_log_event; |
68 | typedef struct lnm_log_statement lnm_log_statement; |
69 | typedef struct lnm_queue lnm_queue; |
70 |
|
71 | // lnm_pushable utilities |
72 | lnm_pushable * lnm_new_pushable(void); |
73 | void lnm_pushable_realloc(lnm_pushable * pushable); |
74 | void lnm_pushable_push(lnm_pushable * pushable, lnmItem item); |
75 | void lnm_pushable_pop(lnm_pushable * pushable); |
76 | void lnm_pushable_remove(lnm_pushable * pushable, uint32_t index); |
77 | void lnm_pushable_free(lnm_pushable * pushable); |
78 |
|
79 | // misc utilities |
80 | unsigned long lnm_getus(void); |
81 |
|
82 | // registry utilities |
83 | void lnm_registry_update(void); |
84 |
|
85 | // memory management utilities |
86 | void lnm_free_item(lnmItem item); |
87 | void lnm_free_registry(void); |
88 | void lnm_free_queue(lnmQueue queue); |
89 |
|
90 | #endif // LNM_ALL |
91 | |
92 |
|
93 | #if defined(LNM_DEBUG) || defined(LNM_ALL) |
94 | void lnm_debug_tabs(int tab_count); |
95 | void lnm_debug_parse_item(lnmItem item, int tab_count); |
96 | void lnm_debug_parse_registry(void); |
97 | void lnm_debug_parse_queue(lnmQueue queue); |
98 | #endif // LNM_DEBUG || LNM_ALL |
99 | |
100 |
|
101 | #ifdef LNM_INIT // define the library |
102 | |
103 |
|
104 | #include <stdint.h> |
105 | #include <stdio.h> |
106 | #include <stdlib.h> |
107 | #include <string.h> |
108 |
|
109 |
|
110 | static const uint8_t LNM_STATEMENT = 0; |
111 | static const uint8_t LNM_EVENT = 1; |
112 |
|
113 |
|
114 | // lnm_pushable utilities |
115 |
|
116 |
|
117 | typedef struct lnm_pushable { |
118 | uint32_t capacity; |
119 | uint32_t length; |
120 | lnmItem * frame; |
121 | } lnm_pushable; |
122 |
|
123 |
|
124 | void lnm_pushable_realloc(lnm_pushable * pushable) { |
125 | if (pushable->length > pushable->capacity) { |
126 | if (pushable->capacity > UINT32_MAX / 2) { |
127 | printf("lognestmonster (lnm_pushable_realloc): pushable reached max capacity of 2^32-1. exiting...\n"); |
128 | abort(); |
129 | } |
130 | pushable->frame = realloc(pushable->frame, sizeof(lnmItem) * (pushable->capacity *= 2)); |
131 | if (pushable->frame == NULL) { |
132 | printf("lognestmonster (lnm_pushable_realloc): call to realloc() returned NULL. exiting...\n"); |
133 | abort(); |
134 | } |
135 | } else if (pushable->length < (pushable->capacity / 2)) { |
136 | if (pushable->capacity > 8) { |
137 | pushable->frame = realloc(pushable->frame, sizeof(lnmItem) * (pushable->capacity /= 2)); |
138 | if (pushable->frame == NULL) { |
139 | printf("lognestmonster (lnm_pushable_realloc): call to realloc() returned NULL. exiting...\n"); |
140 | abort(); |
141 | } |
142 | } |
143 | } |
144 | } |
145 |
|
146 |
|
147 | lnm_pushable * lnm_new_pushable(void) { |
148 | lnm_pushable * new_pushable = malloc(sizeof(lnm_pushable)); |
149 | if (new_pushable == NULL) { |
150 | printf("lognestmonster (lnm_new_pushable): call to malloc() returned NULL. exiting...\n"); |
151 | abort(); |
152 | } |
153 | new_pushable->capacity = 8; |
154 | new_pushable->length = 0; |
155 | new_pushable->frame = malloc(sizeof(lnmItem) * 8); |
156 | if (new_pushable->frame == NULL) { |
157 | printf("lognestmonster (lnm_new_pushable): call to malloc() returned NULL. exiting...\n"); |
158 | abort(); |
159 | } |
160 | return new_pushable; |
161 | } |
162 |
|
163 |
|
164 | void lnm_pushable_push(lnm_pushable * pushable, lnmItem item) { |
165 | pushable->length++; |
166 | lnm_pushable_realloc(pushable); |
167 | pushable->frame[pushable->length - 1] = item; |
168 | } |
169 |
|
170 |
|
171 | void lnm_pushable_pop(lnm_pushable * pushable) { |
172 | pushable->length--; |
173 | lnm_pushable_realloc(pushable); |
174 | } |
175 |
|
176 |
|
177 | void lnm_pushable_remove(lnm_pushable * pushable, uint32_t index) { |
178 | if (index >= pushable->length) { |
179 | printf("lognestmonster (lnm_pushable_remove): attempt to remove index out of pushable bounds. exiting...\n"); |
180 | abort(); |
181 | } |
182 | if (index == pushable->length - 1) { |
183 | lnm_pushable_pop(pushable); |
184 | } else { |
185 | // shift entire array from index until end |
186 | for (uint32_t iter = index; iter < pushable->length - 1; iter++) { |
187 | pushable->frame[iter] = pushable->frame[iter + 1]; |
188 | } |
189 | pushable->length--; |
190 | lnm_pushable_realloc(pushable); |
191 | } |
192 | } |
193 |
|
194 |
|
195 | void lnm_pushable_free(lnm_pushable * pushable) { |
196 | free(pushable->frame); |
197 | free(pushable); |
198 | } |
199 |
|
200 |
|
201 | // log event and log statement definitions |
202 |
|
203 |
|
204 | typedef struct lnm_log_event { |
205 | // word 1, 1 byte data 7 bytes padding |
206 | uint8_t type:1; // used internally; 0 = statement, 1 = event |
207 | uint8_t pushed:1; // whether or not this log item has been pushed |
208 | uint8_t verbosity:3; // lnmVerbosityLevel, 0-5 |
209 |
|
210 | // word 2, 8 bytes data |
211 | char * tag; // null-terminated tag string |
212 |
|
213 | // word 3, 8 bytes data |
214 | lnm_pushable * pushable; // pushable of lnmItems |
215 | } lnm_log_event; |
216 |
|
217 |
|
218 | typedef struct lnm_log_statement { |
219 | // word 1, 4 bytes data 4 bytes padding |
220 | uint8_t type:1; // used internally; 0 = statement, 1 = event |
221 | uint8_t pushed:1; // whether or not this log item has been pushed |
222 | uint8_t verbosity:3; // lnmVerbosityLevel, 0-5 |
223 | uint8_t tag_size; // character length of the tag |
224 | uint16_t message_size; // character length of the message |
225 |
|
226 | // word 2, 8 bytes data |
227 | uint64_t timestamp; // 64-bit millisecond timestamp |
228 |
|
229 | // word 3, 8 bytes data |
230 | char * log; // non-null-terminated tag string + non-null-terminated message string |
231 | } lnm_log_statement; |
232 |
|
233 |
|
234 | // queue structure definition |
235 |
|
236 |
|
237 | typedef struct lnm_queue { |
238 | char * name; |
239 | char * out_path; |
240 | uint64_t timestamp; |
241 | lnm_pushable * pushable; |
242 | } lnm_queue; |
243 |
|
244 |
|
245 | // time utilities |
246 |
|
247 |
|
248 | #if defined(__unix__) || defined(unix) || defined(__unix) || defined(__CYGWIN__) |
249 | #include <sys/time.h> |
250 | static struct timeval lnm_current_time; |
251 | #elif defined(_WIN32) || defined(__WINDOWS__) |
252 | #include <sysinfoapi.h> |
253 | static FILETIME lnm_win32_filetime; |
254 | #else |
255 | #error lognestmonster: Windows NT or a POSIX-compliant system were not detected. Implement your own system time functions or compile on a compliant system. |
256 | #endif |
257 |
|
258 |
|
259 | uint64_t lnm_getus(void) { |
260 | uint64_t us; |
261 | #if defined(__unix__) || defined(unix) || defined(__unix) || defined(__CYGWIN__) |
262 | gettimeofday(&lnm_current_time, NULL); |
263 | us = (lnm_current_time.tv_sec*1000000+lnm_current_time.tv_usec); |
264 | #elif defined(_WIN32) || defined(__WINDOWS__) |
265 | // get system time in ticks |
266 | GetSystemTimeAsFileTime(&lnm_win32_filetime); |
267 | // load time from two 32-bit words into one 64-bit integer |
268 | us = lnm_win32_filetime.dwHighDateTime << 32; |
269 | us |= lnm_win32_filetime.dwLowDateTime; |
270 | // convert to microseconds |
271 | us /= 10; |
272 | // convert from time since Windows NT epoch to time since Unix epoch |
273 | us -= 11644473600000000ULL; |
274 | #endif |
275 | return us; |
276 | } |
277 |
|
278 |
|
279 | // item registry utils |
280 |
|
281 |
|
282 | void lnm_free_item(lnmItem item); |
283 | static lnm_pushable * lnm_registered_queues; |
284 | static lnm_pushable * lnm_registered_items; |
285 | static int lnm_registry_update_count; |
286 |
|
287 |
|
288 | void lnm_registry_update(void) { |
289 | // iterate through registry |
290 | for (uint32_t iter = 0; iter < lnm_registered_items->length; iter++) { |
291 | lnm_log_statement * item = (lnm_log_statement *)(lnm_registered_items->frame[iter]); |
292 | // if the registered item has been pushed elsewhere, remove it from the top level of the registry |
293 | if (item->pushed) { |
294 | lnm_registry_update_count++; |
295 | lnm_pushable_remove(lnm_registered_items, iter); |
296 | iter--; |
297 | } |
298 | } |
299 | } |
300 |
|
301 |
|
302 | void lnm_registry_free() { |
303 | for (uint32_t iter = 0; iter < lnm_registered_items->length; iter++) { |
304 | lnm_free_item(lnm_registered_items->frame[iter]); |
305 | } |
306 | } |
307 |
|
308 |
|
309 | // core library utilities |
310 |
|
311 |
|
312 | int lnm_item_type(lnmItem item) { |
313 | return ((lnm_log_statement *)item)->type; |
314 | } |
315 |
|
316 | void lnm_free_item(lnmItem item) { |
317 | if (lnm_item_type(item) == LNM_STATEMENT) { |
318 | lnm_log_statement * statement = (lnm_log_statement *)item; |
319 | // flush item out of registry |
320 | if (!statement->pushed) { |
321 | statement->pushed = 1; |
322 | lnm_registry_update(); |
323 | } |
324 | // free item and its contents |
325 | free(statement->log); |
326 | free(statement); |
327 | } else if (lnm_item_type(item) == LNM_EVENT) { |
328 | // create breadcrumb navigation array with root 'item' |
329 | lnm_pushable * breadcrumb = lnm_new_pushable(); |
330 | lnm_pushable_push(breadcrumb, item); |
331 | // continually iterate breadcrumb until it's empty |
332 | while (breadcrumb->length > 0) { |
333 | // get current item (deepest element of the breadcrumb nav, aka 'z' in 'x > y > z') |
334 | lnmItem current = breadcrumb->frame[breadcrumb->length - 1]; |
335 | if (lnm_item_type(current) == LNM_STATEMENT) { |
336 | lnm_log_statement * current_statement = (lnm_log_statement *)current; |
337 | // flush item out of registry |
338 | if (!current_statement->pushed) { |
339 | current_statement->pushed = 1; |
340 | lnm_registry_update(); |
341 | } |
342 | // free statement |
343 | free(current_statement->log); |
344 | free(current_statement); |
345 | // pop it from the breadcrumb nav |
346 | lnm_pushable_pop(breadcrumb); |
347 | // loop back |
348 | } else if (lnm_item_type(current) == LNM_EVENT) { |
349 | lnm_log_event * current_event = (lnm_log_event *)current; |
350 | // flush item out of registry |
351 | if (!current_event->pushed) { |
352 | current_event->pushed = 1; |
353 | lnm_registry_update(); |
354 | } |
355 | if (current_event->pushable->length > 0) { |
356 | // the event has children |
357 | for (uint32_t iter = 0; iter < current_event->pushable->length; iter++) { |
358 | // add each child to the breadcrumb nav |
359 | lnmItem current_event_child = current_event->pushable->frame[iter]; |
360 | lnm_pushable_push(breadcrumb, current_event_child); |
361 | } |
362 | // set the current event as having no children so they're not erroneously counted twice |
363 | current_event->pushable->length = 0; |
364 | } else { |
365 | // the event is empty, so we can safely free it and remove it from the breadcrumb nav |
366 | lnm_pushable_free(current_event->pushable); |
367 | free(current_event->tag); |
368 | free(current_event); |
369 | lnm_pushable_pop(breadcrumb); |
370 | } |
371 | // loop back |
372 | } else { |
373 | printf("lognestmonster (lnm_free_item): item in log tree has non-statement and non-event type. exiting...\n"); |
374 | abort(); |
375 | } |
376 | } |
377 | } else { |
378 | printf("lognestmonster (lnm_free_item): log tree is non-statement and non-event type. exiting...\n"); |
379 | abort(); |
380 | } |
381 | } |
382 |
|
383 |
|
384 | // queue utilities |
385 |
|
386 |
|
387 | void lnm_free_queue(lnmQueue queue) { |
388 | lnm_queue * queue_cast = (lnm_queue *)queue; |
389 | for (uint32_t iter = 0; iter < queue_cast->pushable->length; iter++) { |
390 | lnm_free_item(queue_cast->pushable->frame[iter]); |
391 | lnm_pushable_remove(queue_cast->pushable, iter); |
392 | iter--; |
393 | } |
394 | } |
395 |
|
396 |
|
397 | lnmQueue lnmQueueInit(char * name, char * out_path) { |
398 | // create queue and item registries if not created |
399 | if (lnm_registered_queues == NULL) { |
400 | lnm_registered_queues = lnm_new_pushable(); |
401 | } |
402 | if (lnm_registered_items == NULL) { |
403 | lnm_registered_items = lnm_new_pushable(); |
404 | } |
405 | // allocate and populate a new Queue object |
406 | lnm_queue * new_queue = malloc(sizeof(lnm_queue)); |
407 | if (new_queue == NULL) { |
408 | printf("lognestmonster (lnmQueueInit): call to malloc() returned NULL. exiting...\n"); |
409 | abort(); |
410 | } |
411 | new_queue->name = malloc(strlen(name)+1); |
412 | new_queue->out_path = malloc(strlen(out_path)+1); |
413 | if (new_queue->name == NULL || new_queue->out_path == NULL) { |
414 | printf("lognestmonster (lnmQueueInit): call to malloc() returned NULL. exiting...\n"); |
415 | abort(); |
416 | } |
417 | strcpy(new_queue->name, name); |
418 | strcpy(new_queue->out_path, out_path); |
419 | new_queue->timestamp = lnm_getus(); |
420 | new_queue->pushable = lnm_new_pushable(); |
421 | // enter new Queue into registry |
422 | lnm_pushable_push(lnm_registered_queues, (lnmQueue)new_queue); |
423 | return (lnmQueue)new_queue; |
424 | } |
425 |
|
426 |
|
427 | lnmQueue lnmQueueByName(char * name) { |
428 | if (lnm_registered_queues == NULL) { |
429 | printf("lognestmonster (lnmQueueByName): queue registry is nonexistant. exiting...\n"); |
430 | abort(); |
431 | } |
432 | if (lnm_registered_queues->length == 0) { |
433 | printf("lognestmonster (lnmQueueByName): queue registry is empty. exiting...\n"); |
434 | abort(); |
435 | } |
436 | for (uint32_t iter = 0; iter<lnm_registered_queues->length; iter++) { |
437 | lnm_queue * queue = (lnm_queue *)lnm_registered_queues->frame[iter]; |
438 | if (strcmp(queue->name, name) == 0) { |
439 | return (lnmQueue)queue; |
440 | } |
441 | } |
442 | printf("lognestmonster (lnmQueueByName): queue not found in registry. exiting...\n"); |
443 | abort(); |
444 | } |
445 |
|
446 |
|
447 | void lnmQueuePush(lnmQueue queue, lnmItem item) { |
448 | lnm_log_statement * statement = (lnm_log_statement *)item; |
449 | if (statement->pushed == 1) { |
450 | printf("lognestmonster (lnmQueuePush): attempt to push an already-pushed log item. exiting...\n"); |
451 | abort(); |
452 | } |
453 | // flush out of registry |
454 | statement->pushed = 1; |
455 | lnm_registry_update(); |
456 | // add to queue |
457 | lnm_pushable_push(((lnm_queue *)queue)->pushable, item); |
458 | } |
459 |
|
460 |
|
461 | lnmItem lnmStatement(enum lnmVerbosityLevel verbosity, char * tag, char * message) { |
462 | lnm_log_statement * new_statement = malloc(sizeof(lnm_log_statement)); |
463 | if (new_statement == NULL) { |
464 | printf("lognestmonster (lnmStatement): call to malloc() returned NULL. exiting...\n"); |
465 | abort(); |
466 | } |
467 | new_statement->type = LNM_STATEMENT; |
468 | new_statement->verbosity = verbosity; |
469 | new_statement->timestamp = lnm_getus(); |
470 | // enforce string lengths |
471 | int tag_len = strlen(tag); |
472 | if (tag_len > 256 || tag_len < 0) { |
473 | printf("lognestmonster (lnmStatement): tag length %i is longer than the cap 256 characters. exiting...\n", tag_len); |
474 | abort(); |
475 | } |
476 | int message_len = strlen(message); |
477 | if (message_len > 65536 || message_len < 0) { |
478 | printf("lognestmonster (lnmStatement): message length %i is longer than the cap 65536 characters. exiting...\n", message_len); |
479 | abort(); |
480 | } |
481 | new_statement->tag_size = tag_len; |
482 | new_statement->message_size = message_len; |
483 | // concat tag + message to new_statement->log |
484 | new_statement->log = malloc(tag_len + message_len + 1); |
485 | if (new_statement->log == NULL) { |
486 | printf("lognestmonster (lnmStatement): call to malloc() returned NULL. exiting...\n"); |
487 | abort(); |
488 | } |
489 | strcpy(new_statement->log, tag); |
490 | strcat(new_statement->log, message); |
491 | // add to registry |
492 | lnm_pushable_push(lnm_registered_items, (lnmItem)new_statement); |
493 | return (lnmItem)new_statement; |
494 | } |
495 |
|
496 |
|
497 | lnmItem lnmEvent(char * tag) { |
498 | lnm_log_event * new_event = malloc(sizeof(lnm_log_event)); |
499 | if (new_event == NULL) { |
500 | printf("lognestmonster (lnmEvent): call to malloc() returned NULL. exiting...\n"); |
501 | abort(); |
502 | } |
503 | new_event->type = LNM_EVENT; |
504 | new_event->pushable = lnm_new_pushable(); |
505 | // copy tag to event |
506 | int tag_len = strlen(tag); |
507 | new_event->tag = malloc(tag_len + 1); |
508 | if (new_event->tag == NULL) { |
509 | printf("lognestmonster (lnmEvent): call to malloc() returned NULL. exiting...\n"); |
510 | abort(); |
511 | } |
512 | strcpy(new_event->tag, tag); |
513 | // add to registry |
514 | lnm_pushable_push(lnm_registered_items, (lnmItem)new_event); |
515 | return (lnmItem)new_event; |
516 | } |
517 |
|
518 |
|
519 | void lnmEventPush(lnmItem event, lnmItem item) { |
520 | if (event == item) { |
521 | printf("lognestmonster (lnmEventPush): attempt to push event to self. exiting...\n"); |
522 | abort(); |
523 | } |
524 | lnm_log_statement * item_cast = (lnm_log_statement *)item; |
525 | if (item_cast->pushed == 1) { |
526 | printf("lognestmonster (lnmEventPush): attempt to push an already-pushed log item. exiting...\n"); |
527 | abort(); |
528 | } |
529 | if (lnm_item_type(event) != LNM_EVENT) { |
530 | printf("lognestmonster (lnmEventPush): cannot cast non-event to event type. exiting...\n"); |
531 | abort(); |
532 | } |
533 | lnm_log_event * event_cast = (lnm_log_event *)event; |
534 | lnm_pushable_push(event_cast->pushable, item); |
535 | item_cast->pushed = 1; |
536 | lnm_registry_update(); |
537 | } |
538 |
|
539 |
|
540 | void lnmEventPushS(lnmItem event, enum lnmVerbosityLevel verbosity, char * statement_tag, char * message) { |
541 | lnmItem statement = lnmStatement(verbosity, statement_tag, message); |
542 | lnmEventPush(event, statement); |
543 | } |
544 |
|
545 |
|
546 | lnmItem lnmEventI(char * event_tag, lnmItem item) { |
547 | lnmItem event = lnmEvent(event_tag); |
548 | lnmEventPush(event, item); |
549 | return event; |
550 | } |
551 |
|
552 |
|
553 | lnmItem lnmEventS(char * event_tag, enum lnmVerbosityLevel verbosity, char * statement_tag, char * message) { |
554 | lnmItem event = lnmEvent(event_tag); |
555 | lnmEventPushS(event, verbosity, statement_tag, message); |
556 | return event; |
557 | } |
558 |
|
559 |
|
560 | #ifdef LNM_DEBUG |
561 | #include <inttypes.h> |
562 |
|
563 | void lnm_debug_tabs(int tab_count) { |
564 | for (int i = 0; i < tab_count; i++) { |
565 | printf(" "); |
566 | } |
567 | } |
568 |
|
569 |
|
570 | void lnm_debug_parse_item(lnmItem item, int tab_count) { |
571 | if (lnm_item_type(item) == LNM_STATEMENT) { |
572 | lnm_log_statement * statement = (lnm_log_statement *) item; |
573 | lnm_debug_tabs(tab_count); |
574 |
|
575 | char * verbosity; |
576 | switch (statement->verbosity) { |
577 | case 0: |
578 | verbosity = "INFO"; |
579 | break; |
580 | case 1: |
581 | verbosity = "DEBUG"; |
582 | break; |
583 | case 2: |
584 | verbosity = "VERBOSE"; |
585 | break; |
586 | case 3: |
587 | verbosity = "VERYVERBOSE"; |
588 | break; |
589 | case 4: |
590 | verbosity = "WARNING"; |
591 | break; |
592 | case 5: |
593 | verbosity = "ERROR"; |
594 | break; |
595 | } |
596 |
|
597 | char tag[statement->tag_size+1]; |
598 | strncpy(tag, statement->log, statement->tag_size); |
599 | tag[statement->tag_size] = '\0'; |
600 |
|
601 | char message[statement->message_size+1]; |
602 | strncpy(message, statement->log+statement->tag_size, statement->message_size); |
603 | message[statement->message_size] = '\0'; |
604 |
|
605 | printf("%" PRIu64 " (%s) %s :: %s\n", statement->timestamp, verbosity, tag, message); |
606 | } else if (lnm_item_type(item) == LNM_EVENT) { |
607 | lnm_log_event * event = (lnm_log_event *) item; |
608 | lnm_debug_tabs(tab_count); |
609 | printf("Event (%" PRIu32 "/%" PRIu32 ") %s [\n", event->pushable->length, event->pushable->capacity, event->tag); |
610 | for (uint32_t iter = 0; iter < event->pushable->length; iter++) { |
611 | lnmItem item = event->pushable->frame[iter]; |
612 | lnm_debug_parse_item(item, tab_count + 1); |
613 | } |
614 | lnm_debug_tabs(tab_count); |
615 | printf("]\n"); |
616 | } else { |
617 | printf("lognestmonster (lnm_debug_parse_item): unknown item type. exiting...\n"); |
618 | abort(); |
619 | } |
620 | } |
621 |
|
622 |
|
623 | void lnm_debug_parse_registry(void) { |
624 | printf("Top level registry (%" PRIu32 "/%" PRIu32 ") [\n", lnm_registered_items->length, lnm_registered_items->capacity); |
625 | for (uint32_t iter = 0; iter < lnm_registered_items->length; iter++) { |
626 | lnm_debug_parse_item(lnm_registered_items->frame[iter], 1); |
627 | } |
628 | printf("]\n"); |
629 | } |
630 |
|
631 |
|
632 | void lnm_debug_parse_queue(lnmQueue queue) { |
633 | lnm_queue * queue_cast = (lnm_queue *)queue; |
634 | printf("Queue \"%s\" at %s (%" PRIu32 "/%" PRIu32 ") [\n", queue_cast->name, queue_cast->out_path, queue_cast->pushable->length, queue_cast->pushable->capacity); |
635 | for (uint32_t iter = 0; iter < queue_cast->pushable->length; iter++) { |
636 | lnm_debug_parse_item((lnmItem)queue_cast->pushable->frame[iter], 1); |
637 | } |
638 | printf("]\n"); |
639 | } |
640 | #endif // LNM_DEBUG |
641 | #endif // LNM_INIT |
642 | #endif // LOGNESTMONSTER_H |
643 | |
644 |
|
645 | #ifdef __cplusplus |
646 | } |
647 | #endif |
648 |
|