| 254 | } |
| 255 | |
| 256 | void cbm_log(CBMLogLevel level, const char *msg, ...) { |
| 257 | if (level < atomic_load_explicit(&g_log_level, memory_order_relaxed)) { |
| 258 | return; |
| 259 | } |
| 260 | |
| 261 | char line_buf[CBM_SZ_4K]; |
| 262 | size_t pos = 0; |
| 263 | va_list args; |
| 264 | va_start(args, msg); |
| 265 | |
| 266 | if (atomic_load_explicit(&g_log_format, memory_order_relaxed) == CBM_LOG_FORMAT_JSON) { |
| 267 | append_raw(line_buf, sizeof(line_buf), &pos, "{\"level\":"); |
| 268 | append_json_string(line_buf, sizeof(line_buf), &pos, level_str(level)); |
| 269 | append_raw(line_buf, sizeof(line_buf), &pos, ",\"event\":"); |
| 270 | append_json_string(line_buf, sizeof(line_buf), &pos, msg ? msg : ""); |
| 271 | for (;;) { |
| 272 | const char *key = va_arg(args, const char *); |
| 273 | if (!key) { |
| 274 | break; |
| 275 | } |
| 276 | const char *val = va_arg(args, const char *); |
| 277 | append_char(line_buf, sizeof(line_buf), &pos, ','); |
| 278 | append_json_string(line_buf, sizeof(line_buf), &pos, key); |
| 279 | append_char(line_buf, sizeof(line_buf), &pos, ':'); |
| 280 | append_json_string(line_buf, sizeof(line_buf), &pos, val ? val : ""); |
| 281 | } |
| 282 | append_char(line_buf, sizeof(line_buf), &pos, '}'); |
| 283 | } else { |
| 284 | append_raw(line_buf, sizeof(line_buf), &pos, "level="); |
| 285 | append_text_atom(line_buf, sizeof(line_buf), &pos, level_str(level)); |
| 286 | append_raw(line_buf, sizeof(line_buf), &pos, " msg="); |
| 287 | append_text_atom(line_buf, sizeof(line_buf), &pos, msg ? msg : ""); |
| 288 | for (;;) { |
| 289 | const char *key = va_arg(args, const char *); |
| 290 | if (!key) { |
| 291 | break; |
| 292 | } |
| 293 | const char *val = va_arg(args, const char *); |
| 294 | append_char(line_buf, sizeof(line_buf), &pos, ' '); |
| 295 | append_text_atom(line_buf, sizeof(line_buf), &pos, key); |
| 296 | append_char(line_buf, sizeof(line_buf), &pos, '='); |
| 297 | append_text_atom(line_buf, sizeof(line_buf), &pos, val ? val : ""); |
| 298 | } |
| 299 | } |
| 300 | va_end(args); |
| 301 | |
| 302 | finish_line(line_buf, sizeof(line_buf), pos); |
| 303 | emit_line(line_buf); |
| 304 | } |
| 305 | |
| 306 | void cbm_log_control_record(const char *msg, ...) { |
| 307 | /* No threshold check: a control record's whole purpose is surviving |
no test coverage detected