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 : }
|