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

📝 JSON structured logging output 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_set_json_output (int fd)
 Set the JSON output file descriptor.
 
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

Definition in file include/ascii-chat/log/json.h.

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 (DEBUG, INFO, WARN, ERROR, FATAL)
fileSource file name (can be NULL)
lineSource line number (can be 0)
funcFunction name (can be NULL)
messageLog message (must not be NULL)

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().

◆ log_set_json_output()

void log_set_json_output ( int  fd)

Set the JSON output file descriptor.

Sets which file descriptor should receive JSON-formatted logs. Pass -1 to disable JSON output.

Parameters
fdFile descriptor (typically STDERR_FILENO for terminal, or an open log file)
Note
This function is thread-safe (uses atomic operations)

Definition at line 729 of file log/log.c.

729 {
730 atomic_store_int(&g_log.json_file, fd);
731}
void atomic_store_int(atomic_t *a, int value)
Atomically store an int value.
Definition atomic.c:202

References atomic_store_int().

Referenced by main().