ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
json.c File Reference

📝 JSON structured logging output using yyjson More...

Go to the source code of this file.

Functions

void log_json_write (int fd, log_level_t level, uint64_t time_nanoseconds, const char *file, int line, const char *func, const char *message)
 Write a log entry as a JSON object to the json output fd.
 
void log_json_async_safe (int fd, log_level_t level, const char *file, int line, const char *func, const char *message)
 Async-safe JSON logging for signal handlers.
 

Detailed Description

📝 JSON structured logging output using yyjson

Definition in file json.c.

Function Documentation

◆ log_json_async_safe()

void log_json_async_safe ( int  fd,
log_level_t  level,
const char *  file,
int  line,
const char *  func,
const char *  message 
)

Async-safe JSON logging for signal handlers.

This function formats and writes JSON logs using ONLY async-safe operations:

  • snprintf for string formatting
  • write() for output
  • No allocations, no locks, no library calls

Suitable for calling from signal handlers (SIGTERM, SIGINT, etc.)

Parameters
fdFile descriptor to write to (typically STDOUT_FILENO or STDERR_FILENO)
levelLog level
fileSource file name (may be NULL)
lineSource line number
funcFunction name (may be NULL)
messageLog message (must not be NULL)

Definition at line 250 of file json.c.

250 {
251 if (fd < 0 || !message) {
252 return;
253 }
254
255 /* Format JSON manually on stack using only async-safe operations */
256 char json_buffer[2048];
257 char escaped_message[512];
258 char escaped_file[256];
259 char escaped_func[128];
260 char timestamp_buf[32];
261
262 /* Escape the strings (normalize file path to project-relative) */
263 json_escape_async_safe(message, escaped_message, sizeof(escaped_message));
264 if (file) {
265 const char *rel_file = extract_project_relative_path(file);
266 json_escape_async_safe(rel_file, escaped_file, sizeof(escaped_file));
267 } else {
268 escaped_file[0] = '\0';
269 }
270 json_escape_async_safe(func ? func : "", escaped_func, sizeof(escaped_func));
271
272 /* Format timestamp using only async-safe operations */
273 uint64_t time_ns = time_get_realtime_ns();
274 format_timestamp_microseconds(time_ns, timestamp_buf, sizeof(timestamp_buf));
275
276 /* Get thread ID (note: asciichat_thread_current_id is assumed to be async-safe) */
278
279 /* Format complete JSON object with timestamp */
280 int written = snprintf(json_buffer, sizeof(json_buffer),
281 "{\"header\":{\"timestamp\":\"%s\",\"level\":\"%s\",\"tid\":%lu,"
282 "\"file\":\"%s\",\"line\":%d,\"func\":\"%s\"},"
283 "\"body\":{\"message\":\"%s\"}}\n",
284 timestamp_buf, log_level_to_string(level), (unsigned long)tid, file ? escaped_file : "", line,
285 func ? escaped_func : "", escaped_message);
286
287 /* Write to fd if successful */
288 if (written > 0 && written < (int)sizeof(json_buffer)) {
289 platform_write_all(fd, (const uint8_t *)json_buffer, (size_t)written);
290 }
291}
unsigned long long uint64_t
Definition common.h:59
unsigned char uint8_t
Definition common.h:56
uint64_t time_get_realtime_ns(void)
Get current wall-clock (real) time in nanoseconds.
Definition util/time.c:119
size_t platform_write_all(int fd, const void *buf, size_t count)
Write all bytes to a file descriptor, handling partial writes.
Definition system.c:224
uint64_t asciichat_thread_current_id(void)
Get the current thread's unique numeric ID.
Definition threading.c:92
const char * extract_project_relative_path(const char *file)
Extract relative path from an absolute path.
Definition path.c:456

References asciichat_thread_current_id(), extract_project_relative_path(), platform_write_all(), and time_get_realtime_ns().

Referenced by log_console_impl().

◆ log_json_write()

void log_json_write ( int  fd,
log_level_t  level,
uint64_t  time_nanoseconds,
const char *  file,
int  line,
const char *  func,
const char *  message 
)

Write a log entry as a JSON object to the json output fd.

Outputs a newline-delimited JSON (NDJSON) format log entry with the following structure:

{
"header": {
"timestamp": "14:30:45.123456",
"level": "INFO",
"tid": 12345,
"file": "lib/network/server.c",
"line": 42,
"func": "handle_client"
},
"body": {
"message": "Client connected"
}
}

The file, line, and func fields are omitted from the output when they are NULL/0 (which typically occurs in release builds).

Parameters
fdFile descriptor to write JSON to (-1 = disabled)
levelLog level (DEBUG, INFO, WARN, ERROR, FATAL)
time_nanosecondsCurrent time in nanoseconds (used to format timestamp)
fileSource file name (can be NULL)
lineLine number (can be 0)
funcFunction name (can be NULL)
messageFormatted log message
See also
log_set_json_output() - Set the JSON output file descriptor

Definition at line 94 of file json.c.

95 {
96 if (fd < 0 || !message) {
97 return;
98 }
99
100 /* Create root object */
101 yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
102 if (!doc) {
103 return;
104 }
105
106 yyjson_mut_val *root = yyjson_mut_obj(doc);
107 if (!root) {
108 yyjson_mut_doc_free(doc);
109 return;
110 }
111 yyjson_mut_doc_set_root(doc, root);
112
113 /* Create "header" object */
114 yyjson_mut_val *header = yyjson_mut_obj(doc);
115 if (header) {
116 yyjson_mut_obj_add_val(doc, root, "header", header);
117
118 /* Add timestamp (HH:MM:SS.microseconds) */
119 char timestamp_buf[32];
120 size_t ts_len = format_timestamp_microseconds(time_nanoseconds, timestamp_buf, sizeof(timestamp_buf));
121 if (ts_len > 0) {
122 yyjson_mut_obj_add_strncpy(doc, header, "timestamp", timestamp_buf, ts_len);
123 }
124
125 /* Add level */
126 yyjson_mut_obj_add_str(doc, header, "level", log_level_to_string(level));
127
128 /* Add thread ID */
130 yyjson_mut_obj_add_uint(doc, header, "tid", tid);
131
132 /* Add file (if not NULL) - normalize to project-relative path */
133 if (file) {
134 const char *rel_file = extract_project_relative_path(file);
135 yyjson_mut_obj_add_str(doc, header, "file", rel_file);
136 }
137
138 /* Add line (if > 0) */
139 if (line > 0) {
140 yyjson_mut_obj_add_int(doc, header, "line", line);
141 }
142
143 /* Add func (if not NULL) */
144 if (func) {
145 yyjson_mut_obj_add_str(doc, header, "func", func);
146 }
147 }
148
149 /* Create "body" object with message */
150 yyjson_mut_val *body = yyjson_mut_obj(doc);
151 if (body) {
152 yyjson_mut_obj_add_val(doc, root, "body", body);
153 yyjson_mut_obj_add_str(doc, body, "message", message);
154 }
155
156 /* Serialize to compact JSON (single line, no pretty-printing) */
157 size_t json_len = 0;
158 char *json_str = yyjson_mut_write(doc, 0, &json_len);
159
160 if (json_str && json_len > 0) {
161 /* Write JSON string */
162 platform_write(fd, (const uint8_t *)json_str, json_len);
163
164 /* Write newline for NDJSON format */
165 platform_write(fd, (const uint8_t *)"\n", 1);
166
167 /* Free serialized JSON string */
168 free(json_str);
169 }
170
171 /* Free document */
172 yyjson_mut_doc_free(doc);
173}
ssize_t platform_write(int fd, const void *buf, size_t count)
Safe file write (write replacement)
Definition wasm/system.c:72

References asciichat_thread_current_id(), extract_project_relative_path(), and platform_write().

Referenced by log_msg(), and log_plain_msg().