| 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 * message); |
| 55 |
|
| 56 | lnmItem lnmEvent(char * tag); |
| 57 | lnmItem lnmEventI(char * tag, lnmItem item); |
| 58 | lnmItem lnmEventS(char * tag, enum lnmVerbosityLevel verbosity, char * message); |
| 59 | void lnmEventPush(lnmItem event, lnmItem item); |
| 60 | void lnmEventPushS(lnmItem event, enum lnmVerbosityLevel verbosity, 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, 1 byte 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 |
|
| 224 | // word 2, 8 bytes data |
| 225 | uint64_t timestamp; // 64-bit millisecond timestamp |
| 226 |
|
| 227 | // word 3, 8 bytes data |
| 228 | char * log; // null-terminated message string |
| 229 | } lnm_log_statement; |
| 230 |
|
| 231 |
|
| 232 | // queue structure definition |
| 233 |
|
| 234 |
|
| 235 | typedef struct lnm_queue { |
| 236 | char * name; |
| 237 | char * out_path; |
| 238 | uint64_t timestamp; |
| 239 | lnm_pushable * pushable; |
| 240 | } lnm_queue; |
| 241 |
|
| 242 |
|
| 243 | // time utilities |
| 244 |
|
| 245 |
|
| 246 | #if defined(__unix__) || defined(unix) || defined(__unix) || defined(__CYGWIN__) |
| 247 | #include <sys/time.h> |
| 248 | static struct timeval lnm_current_time; |
| 249 | #elif defined(_WIN32) || defined(__WINDOWS__) |
| 250 | #include <sysinfoapi.h> |
| 251 | static FILETIME lnm_win32_filetime; |
| 252 | #else |
| 253 | #error lognestmonster: Windows NT or a POSIX-compliant system were not detected. Implement your own system time functions or compile on a compliant system. |
| 254 | #endif |
| 255 |
|
| 256 |
|
| 257 | uint64_t lnm_getus(void) { |
| 258 | uint64_t us; |
| 259 | #if defined(__unix__) || defined(unix) || defined(__unix) || defined(__CYGWIN__) |
| 260 | gettimeofday(&lnm_current_time, NULL); |
| 261 | us = (lnm_current_time.tv_sec*1000000+lnm_current_time.tv_usec); |
| 262 | #elif defined(_WIN32) || defined(__WINDOWS__) |
| 263 | // get system time in ticks |
| 264 | GetSystemTimeAsFileTime(&lnm_win32_filetime); |
| 265 | // load time from two 32-bit words into one 64-bit integer |
| 266 | us = lnm_win32_filetime.dwHighDateTime << 32; |
| 267 | us |= lnm_win32_filetime.dwLowDateTime; |
| 268 | // convert to microseconds |
| 269 | us /= 10; |
| 270 | // convert from time since Windows NT epoch to time since Unix epoch |
| 271 | us -= 11644473600000000ULL; |
| 272 | #endif |
| 273 | return us; |
| 274 | } |
| 275 |
|
| 276 |
|
| 277 | // item registry utils |
| 278 |
|
| 279 |
|
| 280 | void lnm_free_item(lnmItem item); |
| 281 | static lnm_pushable * lnm_registered_queues; |
| 282 | static lnm_pushable * lnm_registered_items; |
| 283 | static int lnm_registry_update_count; |
| 284 |
|
| 285 |
|
| 286 | void lnm_registry_update(void) { |
| 287 | // iterate through registry |
| 288 | for (uint32_t iter = 0; iter < lnm_registered_items->length; iter++) { |
| 289 | lnm_log_statement * item = (lnm_log_statement *)(lnm_registered_items->frame[iter]); |
| 290 | // if the registered item has been pushed elsewhere, remove it from the top level of the registry |
| 291 | if (item->pushed) { |
| 292 | lnm_registry_update_count++; |
| 293 | lnm_pushable_remove(lnm_registered_items, iter); |
| 294 | iter--; |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 |
|
| 299 |
|
| 300 | void lnm_registry_free() { |
| 301 | for (uint32_t iter = 0; iter < lnm_registered_items->length; iter++) { |
| 302 | lnm_free_item(lnm_registered_items->frame[iter]); |
| 303 | } |
| 304 | } |
| 305 |
|
| 306 |
|
| 307 | void lnm_registry_flush_item(lnmItem item) { |
| 308 | lnm_log_statement * item_cast = (lnm_log_statement *)item; |
| 309 | if (!item_cast->pushed) { |
| 310 | item_cast->pushed = 1; |
| 311 | lnm_registry_update(); |
| 312 | } |
| 313 | } |
| 314 |
|
| 315 |
|
| 316 | // core library utilities |
| 317 |
|
| 318 |
|
| 319 | int lnm_item_type(lnmItem item) { |
| 320 | return ((lnm_log_statement *)item)->type; |
| 321 | } |
| 322 |
|
| 323 | void lnm_free_item(lnmItem item) { |
| 324 | if (lnm_item_type(item) == LNM_STATEMENT) { |
| 325 | // cast item |
| 326 | lnm_log_statement * statement = (lnm_log_statement *)item; |
| 327 | // flush item out of registry |
| 328 | lnm_registry_flush_item(item); |
| 329 | // free item and its contents |
| 330 | free(statement->log); |
| 331 | free(statement); |
| 332 | } else if (lnm_item_type(item) == LNM_EVENT) { |
| 333 | // create breadcrumb navigation array with root 'item' |
| 334 | lnm_pushable * breadcrumb = lnm_new_pushable(); |
| 335 | lnm_pushable_push(breadcrumb, item); |
| 336 | // continually iterate breadcrumb until it's empty |
| 337 | while (breadcrumb->length > 0) { |
| 338 | // get current item (deepest element of the breadcrumb nav, aka 'z' in 'x > y > z') |
| 339 | lnmItem current = breadcrumb->frame[breadcrumb->length - 1]; |
| 340 | // flush item out of registry |
| 341 | lnm_registry_flush_item(current); |
| 342 | if (lnm_item_type(current) == LNM_STATEMENT) { |
| 343 | // cast current item |
| 344 | lnm_log_statement * current_statement = (lnm_log_statement *)current; |
| 345 | // free statement and its contents |
| 346 | free(current_statement->log); |
| 347 | free(current_statement); |
| 348 | // pop it from the breadcrumb nav |
| 349 | lnm_pushable_pop(breadcrumb); |
| 350 | // loop back |
| 351 | } else if (lnm_item_type(current) == LNM_EVENT) { |
| 352 | // cast current item |
| 353 | lnm_log_event * current_event = (lnm_log_event *)current; |
| 354 | if (current_event->pushable->length > 0) { |
| 355 | // the event has children |
| 356 | for (uint32_t iter = 0; iter < current_event->pushable->length; iter++) { |
| 357 | // add every child to the breadcrumb nav to free them |
| 358 | lnmItem current_event_child = current_event->pushable->frame[iter]; |
| 359 | lnm_pushable_push(breadcrumb, current_event_child); |
| 360 | } |
| 361 | // set the current event as having no children so they're not erroneously counted twice |
| 362 | current_event->pushable->length = 0; |
| 363 | } else { |
| 364 | // the event is empty, so we can safely free it |
| 365 | lnm_pushable_free(current_event->pushable); |
| 366 | free(current_event->tag); |
| 367 | free(current_event); |
| 368 | // and remove from breadcrumb nav |
| 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 * 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 message_len = strlen(message); |
| 472 | if (message_len > 65536 || message_len < 0) { |
| 473 | printf("lognestmonster (lnmStatement): message length %i is longer than the cap 65536 characters. exiting...\n", message_len); |
| 474 | abort(); |
| 475 | } |
| 476 | // copy message to new_statement->log |
| 477 | new_statement->log = malloc(message_len); |
| 478 | if (new_statement->log == NULL) { |
| 479 | printf("lognestmonster (lnmStatement): call to malloc() returned NULL. exiting...\n"); |
| 480 | abort(); |
| 481 | } |
| 482 | strcpy(new_statement->log, message); |
| 483 | // add to registry |
| 484 | lnm_pushable_push(lnm_registered_items, (lnmItem)new_statement); |
| 485 | return (lnmItem)new_statement; |
| 486 | } |
| 487 |
|
| 488 |
|
| 489 | lnmItem lnmEvent(char * tag) { |
| 490 | lnm_log_event * new_event = malloc(sizeof(lnm_log_event)); |
| 491 | if (new_event == NULL) { |
| 492 | printf("lognestmonster (lnmEvent): call to malloc() returned NULL. exiting...\n"); |
| 493 | abort(); |
| 494 | } |
| 495 | new_event->type = LNM_EVENT; |
| 496 | new_event->pushable = lnm_new_pushable(); |
| 497 | // copy tag to event |
| 498 | int tag_len = strlen(tag); |
| 499 | new_event->tag = malloc(tag_len + 1); |
| 500 | if (new_event->tag == NULL) { |
| 501 | printf("lognestmonster (lnmEvent): call to malloc() returned NULL. exiting...\n"); |
| 502 | abort(); |
| 503 | } |
| 504 | strcpy(new_event->tag, tag); |
| 505 | // add to registry |
| 506 | lnm_pushable_push(lnm_registered_items, (lnmItem)new_event); |
| 507 | return (lnmItem)new_event; |
| 508 | } |
| 509 |
|
| 510 |
|
| 511 | void lnmEventPush(lnmItem event, lnmItem item) { |
| 512 | if (event == item) { |
| 513 | printf("lognestmonster (lnmEventPush): attempt to push event to self. exiting...\n"); |
| 514 | abort(); |
| 515 | } |
| 516 | lnm_log_statement * item_cast = (lnm_log_statement *)item; |
| 517 | if (item_cast->pushed == 1) { |
| 518 | printf("lognestmonster (lnmEventPush): attempt to push an already-pushed log item. exiting...\n"); |
| 519 | abort(); |
| 520 | } |
| 521 | if (lnm_item_type(event) != LNM_EVENT) { |
| 522 | printf("lognestmonster (lnmEventPush): cannot cast non-event to event type. exiting...\n"); |
| 523 | abort(); |
| 524 | } |
| 525 | lnm_log_event * event_cast = (lnm_log_event *)event; |
| 526 | lnm_pushable_push(event_cast->pushable, item); |
| 527 | item_cast->pushed = 1; |
| 528 | lnm_registry_update(); |
| 529 | } |
| 530 |
|
| 531 |
|
| 532 | void lnmEventPushS(lnmItem event, enum lnmVerbosityLevel verbosity, char * message) { |
| 533 | lnmItem statement = lnmStatement(verbosity, message); |
| 534 | lnmEventPush(event, statement); |
| 535 | } |
| 536 |
|
| 537 |
|
| 538 | lnmItem lnmEventI(char * tag, lnmItem item) { |
| 539 | lnmItem event = lnmEvent(tag); |
| 540 | lnmEventPush(event, item); |
| 541 | return event; |
| 542 | } |
| 543 |
|
| 544 |
|
| 545 | lnmItem lnmEventS(char * tag, enum lnmVerbosityLevel verbosity, char * message) { |
| 546 | lnmItem event = lnmEvent(tag); |
| 547 | lnmEventPushS(event, verbosity, message); |
| 548 | return event; |
| 549 | } |
| 550 |
|
| 551 |
|
| 552 | #ifdef LNM_DEBUG |
| 553 | #include <inttypes.h> |
| 554 |
|
| 555 | void lnm_debug_tabs(int tab_count) { |
| 556 | for (int i = 0; i < tab_count; i++) { |
| 557 | printf(" "); |
| 558 | } |
| 559 | } |
| 560 |
|
| 561 |
|
| 562 | void lnm_debug_parse_item(lnmItem item, int tab_count) { |
| 563 | if (lnm_item_type(item) == LNM_STATEMENT) { |
| 564 | lnm_log_statement * statement = (lnm_log_statement *) item; |
| 565 | lnm_debug_tabs(tab_count); |
| 566 |
|
| 567 | char * verbosity; |
| 568 | switch (statement->verbosity) { |
| 569 | case 0: |
| 570 | verbosity = "INFO"; |
| 571 | break; |
| 572 | case 1: |
| 573 | verbosity = "DEBUG"; |
| 574 | break; |
| 575 | case 2: |
| 576 | verbosity = "VERBOSE"; |
| 577 | break; |
| 578 | case 3: |
| 579 | verbosity = "VERYVERBOSE"; |
| 580 | break; |
| 581 | case 4: |
| 582 | verbosity = "WARNING"; |
| 583 | break; |
| 584 | case 5: |
| 585 | verbosity = "ERROR"; |
| 586 | break; |
| 587 | } |
| 588 |
|
| 589 | printf("%" PRIu64 " (%s) :: %s\n", statement->timestamp, verbosity, statement->log); |
| 590 | } else if (lnm_item_type(item) == LNM_EVENT) { |
| 591 | lnm_log_event * event = (lnm_log_event *) item; |
| 592 | lnm_debug_tabs(tab_count); |
| 593 | printf("Event (%" PRIu32 "/%" PRIu32 ") %s [\n", event->pushable->length, event->pushable->capacity, event->tag); |
| 594 | for (uint32_t iter = 0; iter < event->pushable->length; iter++) { |
| 595 | lnmItem item = event->pushable->frame[iter]; |
| 596 | lnm_debug_parse_item(item, tab_count + 1); |
| 597 | } |
| 598 | lnm_debug_tabs(tab_count); |
| 599 | printf("]\n"); |
| 600 | } else { |
| 601 | printf("lognestmonster (lnm_debug_parse_item): unknown item type. exiting...\n"); |
| 602 | abort(); |
| 603 | } |
| 604 | } |
| 605 |
|
| 606 |
|
| 607 | void lnm_debug_parse_registry(void) { |
| 608 | printf("Top level registry (%" PRIu32 "/%" PRIu32 ") [\n", lnm_registered_items->length, lnm_registered_items->capacity); |
| 609 | for (uint32_t iter = 0; iter < lnm_registered_items->length; iter++) { |
| 610 | lnm_debug_parse_item(lnm_registered_items->frame[iter], 1); |
| 611 | } |
| 612 | printf("]\n"); |
| 613 | } |
| 614 |
|
| 615 |
|
| 616 | void lnm_debug_parse_queue(lnmQueue queue) { |
| 617 | lnm_queue * queue_cast = (lnm_queue *)queue; |
| 618 | printf("Queue \"%s\" at %s (%" PRIu32 "/%" PRIu32 ") [\n", queue_cast->name, queue_cast->out_path, queue_cast->pushable->length, queue_cast->pushable->capacity); |
| 619 | for (uint32_t iter = 0; iter < queue_cast->pushable->length; iter++) { |
| 620 | lnm_debug_parse_item((lnmItem)queue_cast->pushable->frame[iter], 1); |
| 621 | } |
| 622 | printf("]\n"); |
| 623 | } |
| 624 | #endif // LNM_DEBUG |
| 625 | #endif // LNM_INIT |
| 626 | #endif // LOGNESTMONSTER_H |
| 627 | |
| 628 |
|
| 629 | #ifdef __cplusplus |
| 630 | } |
| 631 | #endif |
| 632 |
|