LCOV - code coverage report
Current view: top level - core - logging.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.3 % 88 83
Test Date: 2026-06-23 13:41:07 Functions: 100.0 % 13 13

            Line data    Source code
       1              : #include "cfd/core/logging.h"
       2              : #include "cfd/core/cfd_status.h"
       3              : #include "cfd_threading_internal.h"
       4              : 
       5              : #include <stdarg.h>
       6              : #include <stdio.h>
       7              : 
       8              : /* ============================================================================
       9              :  * THREAD-LOCAL STATE
      10              :  * ============================================================================ */
      11              : 
      12              : #ifdef _WIN32
      13              : static __declspec(thread) cfd_status_t g_last_status = CFD_SUCCESS;
      14              : static __declspec(thread) char g_last_error_msg[256] = {0};
      15              : static __declspec(thread) cfd_log_callback_t s_log_callback = NULL;
      16              : #else
      17              : static __thread cfd_status_t g_last_status = CFD_SUCCESS;
      18              : static __thread char g_last_error_msg[256] = {0};
      19              : static __thread cfd_log_callback_t s_log_callback = NULL;
      20              : #endif
      21              : 
      22              : /* ============================================================================
      23              :  * GLOBAL STATE
      24              :  * ============================================================================ */
      25              : 
      26              : /* Default log level: INFO (suppresses DEBUG) */
      27              : static cfd_atomic_int s_global_log_level = CFD_LOG_LEVEL_INFO;
      28              : 
      29              : /* Global extended callback (set once at startup, read on every log call) */
      30              : static cfd_atomic_ptr s_global_callback_ex;
      31              : 
      32              : /* Level name table (const, thread-safe) */
      33              : static const char* const s_level_names[] = {"DEBUG", "INFO", "WARNING", "ERROR"};
      34              : 
      35              : /* ============================================================================
      36              :  * ERROR CONTEXT
      37              :  * ============================================================================ */
      38              : 
      39           71 : void cfd_set_error(cfd_status_t status, const char* message) {
      40           71 :     g_last_status = status;
      41           71 :     if (message) {
      42           71 :         snprintf(g_last_error_msg, sizeof(g_last_error_msg), "%s", message);
      43              :     } else {
      44            0 :         g_last_error_msg[0] = '\0';
      45              :     }
      46           71 : }
      47              : 
      48           10 : const char* cfd_get_last_error(void) {
      49           10 :     if (g_last_error_msg[0] == '\0') {
      50            2 :         return NULL;
      51              :     }
      52              :     return g_last_error_msg;
      53              : }
      54              : 
      55           35 : cfd_status_t cfd_get_last_status(void) {
      56           35 :     return g_last_status;
      57              : }
      58              : 
      59            9 : const char* cfd_get_error_string(cfd_status_t status) {
      60            9 :     switch (status) {
      61              :         case CFD_SUCCESS:
      62              :             return "Success";
      63            1 :         case CFD_ERROR:
      64            1 :             return "Generic error";
      65            1 :         case CFD_ERROR_NOMEM:
      66            1 :             return "Out of memory";
      67            1 :         case CFD_ERROR_INVALID:
      68            1 :             return "Invalid argument";
      69            1 :         case CFD_ERROR_IO:
      70            1 :             return "I/O error";
      71            1 :         case CFD_ERROR_UNSUPPORTED:
      72            1 :             return "Operation not supported";
      73            1 :         case CFD_ERROR_DIVERGED:
      74            1 :             return "NSSolver diverged";
      75            1 :         case CFD_ERROR_MAX_ITER:
      76            1 :             return "Max iterations reached";
      77            0 :         case CFD_ERROR_LIMIT_EXCEEDED:
      78            0 :             return "Resource limit exceeded";
      79            0 :         case CFD_ERROR_NOT_FOUND:
      80            0 :             return "Resource not found";
      81            1 :         default:
      82            1 :             return "Unknown error";
      83              :     }
      84              : }
      85              : 
      86          192 : void cfd_clear_error(void) {
      87          192 :     g_last_status = CFD_SUCCESS;
      88          192 :     g_last_error_msg[0] = '\0';
      89          192 : }
      90              : 
      91              : /* ============================================================================
      92              :  * CORE LOGGING
      93              :  * ============================================================================ */
      94              : 
      95           76 : void cfd_log(cfd_log_level_t level, const char* component, const char* fmt, ...) {
      96              :     /* Fast path: suppress messages below global log level */
      97           76 :     if ((int)level < cfd_atomic_load(&s_global_log_level)) {
      98           42 :         return;
      99              :     }
     100              : 
     101              :     /* Format message on stack */
     102           52 :     char buf[512];
     103           52 :     va_list args;
     104           52 :     va_start(args, fmt);
     105           52 :     vsnprintf(buf, sizeof(buf), fmt, args);
     106           52 :     va_end(args);
     107              : 
     108              :     /* Dispatch: per-thread callback > global extended callback > default handler */
     109           52 :     if (s_log_callback) {
     110           18 :         s_log_callback(level, buf);
     111           18 :         return;
     112              :     }
     113              : 
     114           34 :     cfd_log_callback_ex_t cb_ex =
     115           34 :         (cfd_log_callback_ex_t)cfd_atomic_ptr_load(&s_global_callback_ex);
     116           34 :     if (cb_ex) {
     117            2 :         cb_ex(level, component, buf);
     118              :     } else {
     119           85 :         const char* level_str =
     120           32 :             ((int)level >= 0 && (int)level <= 3) ? s_level_names[(int)level] : "UNKNOWN";
     121           32 :         FILE* stream = (level >= CFD_LOG_LEVEL_WARNING) ? stderr : stdout;
     122           32 :         if (component) {
     123           26 :             fprintf(stream, "%s [%s]: %s\n", level_str, component, buf);
     124              :         } else {
     125            6 :             fprintf(stream, "%s: %s\n", level_str, buf);
     126              :         }
     127              :     }
     128              : }
     129              : 
     130           36 : void cfd_set_log_level(cfd_log_level_t level) {
     131           36 :     int lvl = (int)level;
     132              : 
     133           36 :     if (lvl < (int)CFD_LOG_LEVEL_DEBUG) {
     134              :         lvl = (int)CFD_LOG_LEVEL_DEBUG;
     135           36 :     } else if (lvl > (int)CFD_LOG_LEVEL_ERROR) {
     136              :         lvl = (int)CFD_LOG_LEVEL_ERROR;
     137              :     }
     138              : 
     139           36 :     cfd_atomic_store(&s_global_log_level, lvl);
     140           36 : }
     141              : 
     142            3 : cfd_log_level_t cfd_get_log_level(void) {
     143            3 :     int lvl = cfd_atomic_load(&s_global_log_level);
     144              : 
     145            3 :     if (lvl < (int)CFD_LOG_LEVEL_DEBUG) {
     146              :         lvl = (int)CFD_LOG_LEVEL_DEBUG;
     147            3 :     } else if (lvl > (int)CFD_LOG_LEVEL_ERROR) {
     148              :         lvl = (int)CFD_LOG_LEVEL_ERROR;
     149              :     }
     150              : 
     151            3 :     return (cfd_log_level_t)lvl;
     152              : }
     153              : 
     154           34 : void cfd_set_log_callback_ex(cfd_log_callback_ex_t callback) {
     155           34 :     cfd_atomic_ptr_store(&s_global_callback_ex, (void*)callback);
     156           34 : }
     157              : 
     158              : /* ============================================================================
     159              :  * LEGACY API
     160              :  * ============================================================================ */
     161              : 
     162           48 : void cfd_set_log_callback(cfd_log_callback_t callback) {
     163           48 :     s_log_callback = callback;
     164           48 : }
     165              : 
     166            3 : void cfd_error(const char* message) {
     167            3 :     const char* safe_msg = message ? message : "(null)";
     168              :     /* Always set error state, regardless of log level filter */
     169            3 :     cfd_set_error(CFD_ERROR, safe_msg);
     170            3 :     cfd_log(CFD_LOG_LEVEL_ERROR, NULL, "%s", safe_msg);
     171            3 : }
     172              : 
     173            9 : void cfd_warning(const char* message) {
     174            9 :     const char* safe_msg = message ? message : "(null)";
     175            9 :     cfd_log(CFD_LOG_LEVEL_WARNING, NULL, "%s", safe_msg);
     176            9 : }
     177              : 
     178            2 : void cfd_info(const char* message) {
     179            2 :     const char* safe_msg = message ? message : "(null)";
     180            2 :     cfd_log(CFD_LOG_LEVEL_INFO, NULL, "%s", safe_msg);
     181            2 : }
        

Generated by: LCOV version 2.0-1