GET /api/logs?lines=N — returns last N log lines */
| 434 | |
| 435 | /* GET /api/logs?lines=N — returns last N log lines */ |
| 436 | static void handle_logs(cbm_http_conn_t *c, const cbm_http_req_t *req) { |
| 437 | char lines_str[16] = {0}; |
| 438 | int max_lines = 100; |
| 439 | if (cbm_http_query_param(req->query, "lines", lines_str, (int)sizeof(lines_str))) { |
| 440 | int v = atoi(lines_str); |
| 441 | if (v > 0 && v <= LOG_RING_SIZE) |
| 442 | max_lines = v; |
| 443 | } |
| 444 | |
| 445 | cbm_mutex_lock(&g_log_mutex); |
| 446 | int count = g_log_count < max_lines ? g_log_count : max_lines; |
| 447 | int start = (g_log_head - count + LOG_RING_SIZE) % LOG_RING_SIZE; |
| 448 | int total = g_log_count; |
| 449 | |
| 450 | /* Copy lines under lock */ |
| 451 | size_t buf_size = (size_t)count * (LOG_LINE_MAX + 10) + 64; |
| 452 | char *buf = malloc(buf_size); |
| 453 | if (!buf) { |
| 454 | cbm_mutex_unlock(&g_log_mutex); |
| 455 | cbm_http_replyf(c, 500, g_cors, "oom"); |
| 456 | return; |
| 457 | } |
| 458 | |
| 459 | int pos = 0; |
| 460 | http_appendf(buf, buf_size, &pos, "{\"lines\":["); |
| 461 | for (int i = 0; i < count; i++) { |
| 462 | int idx = (start + i) % LOG_RING_SIZE; |
| 463 | if (i > 0) |
| 464 | buf[pos++] = ','; |
| 465 | /* Escape quotes in log lines */ |
| 466 | buf[pos++] = '"'; |
| 467 | for (int j = 0; g_log_ring[idx][j] && (size_t)pos < buf_size - 10; j++) { |
| 468 | char ch = g_log_ring[idx][j]; |
| 469 | if (ch == '"') { |
| 470 | buf[pos++] = '\\'; |
| 471 | buf[pos++] = '"'; |
| 472 | } else if (ch == '\\') { |
| 473 | buf[pos++] = '\\'; |
| 474 | buf[pos++] = '\\'; |
| 475 | } else if (ch == '\n') { |
| 476 | buf[pos++] = '\\'; |
| 477 | buf[pos++] = 'n'; |
| 478 | } else { |
| 479 | buf[pos++] = ch; |
| 480 | } |
| 481 | } |
| 482 | buf[pos++] = '"'; |
| 483 | } |
| 484 | cbm_mutex_unlock(&g_log_mutex); |
| 485 | http_appendf(buf, buf_size, &pos, "],\"total\":%d}", total); |
| 486 | |
| 487 | cbm_http_replyf(c, 200, g_cors_json, "%s", buf); |
| 488 | free(buf); |
| 489 | } |
| 490 | |
| 491 | /* ── Process monitoring ───────────────────────────────────────── */ |
| 492 |
no test coverage detected