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