279 lines
9.1 KiB
C
279 lines
9.1 KiB
C
#include "kcp_session_stats.h"
|
|
|
|
static int kcp_session_stats_append(char **line, size_t *len, const char *suffix) {
|
|
size_t suffix_len;
|
|
char *next;
|
|
|
|
if (line == NULL || len == NULL || suffix == NULL) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
suffix_len = strlen(suffix);
|
|
next = (char *) realloc(*line, *len + suffix_len + 1U);
|
|
if (next == NULL) {
|
|
return -1;
|
|
}
|
|
memcpy(next + *len, suffix, suffix_len + 1U);
|
|
*line = next;
|
|
*len += suffix_len;
|
|
return 0;
|
|
}
|
|
|
|
static int kcp_session_stats_appendf(char **line, size_t *len, const char *fmt, ...) {
|
|
va_list args;
|
|
va_list copy;
|
|
int needed;
|
|
char *buffer;
|
|
|
|
if (line == NULL || len == NULL || fmt == NULL) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
va_start(args, fmt);
|
|
va_copy(copy, args);
|
|
needed = vsnprintf(NULL, 0, fmt, copy);
|
|
va_end(copy);
|
|
if (needed < 0) {
|
|
va_end(args);
|
|
return -1;
|
|
}
|
|
|
|
buffer = (char *) malloc((size_t) needed + 1U);
|
|
if (buffer == NULL) {
|
|
va_end(args);
|
|
return -1;
|
|
}
|
|
vsnprintf(buffer, (size_t) needed + 1U, fmt, args);
|
|
va_end(args);
|
|
|
|
if (kcp_session_stats_append(line, len, buffer) != 0) {
|
|
free(buffer);
|
|
return -1;
|
|
}
|
|
free(buffer);
|
|
return 0;
|
|
}
|
|
|
|
kcp_session_stats_logger_t *kcp_session_stats_open_jsonl(const char *path) {
|
|
kcp_session_stats_logger_t *logger;
|
|
FILE *file;
|
|
if (path == NULL || path[0] == '\0') {
|
|
return NULL;
|
|
}
|
|
if (omni_ensure_parent_dir(path) != 0) {
|
|
return NULL;
|
|
}
|
|
file = fopen(path, "ab");
|
|
if (file == NULL) {
|
|
return NULL;
|
|
}
|
|
logger = (kcp_session_stats_logger_t *) calloc(1, sizeof(*logger));
|
|
if (logger == NULL) {
|
|
fclose(file);
|
|
return NULL;
|
|
}
|
|
omni_file_logger_init(&logger->file_logger, file);
|
|
logger->enabled = 1;
|
|
return logger;
|
|
}
|
|
|
|
void kcp_session_stats_close(kcp_session_stats_logger_t *logger) {
|
|
if (logger == NULL) {
|
|
return;
|
|
}
|
|
if (logger->file_logger.file != NULL) {
|
|
fclose(logger->file_logger.file);
|
|
}
|
|
omni_file_logger_destroy(&logger->file_logger);
|
|
free(logger);
|
|
}
|
|
|
|
int kcp_session_stats_log(kcp_session_stats_logger_t *logger, const kcp_session_stats_record_t *record) {
|
|
char *record_type = NULL;
|
|
char *node_role = NULL;
|
|
char *node_id = NULL;
|
|
char *local_addr = NULL;
|
|
char *remote_addr = NULL;
|
|
char *sample_reason = NULL;
|
|
char *line = NULL;
|
|
size_t line_len = 0;
|
|
|
|
if (logger == NULL || record == NULL || !logger->enabled) {
|
|
return 0;
|
|
}
|
|
record_type = omni_json_escape(record->record_type);
|
|
node_role = omni_json_escape(record->node_role);
|
|
node_id = omni_json_escape(record->node_id);
|
|
local_addr = omni_json_escape(record->local_addr);
|
|
remote_addr = omni_json_escape(record->remote_addr);
|
|
sample_reason = omni_json_escape(record->sample_reason);
|
|
if (record_type == NULL || node_role == NULL || node_id == NULL || local_addr == NULL || remote_addr == NULL || sample_reason == NULL) {
|
|
free(record_type);
|
|
free(node_role);
|
|
free(node_id);
|
|
free(local_addr);
|
|
free(remote_addr);
|
|
free(sample_reason);
|
|
return -1;
|
|
}
|
|
line = omni_strdup("");
|
|
if (line == NULL) {
|
|
free(record_type);
|
|
free(node_role);
|
|
free(node_id);
|
|
free(local_addr);
|
|
free(remote_addr);
|
|
free(sample_reason);
|
|
return -1;
|
|
}
|
|
|
|
if (kcp_session_stats_appendf(&line, &line_len, "{\"record_type\":\"%s\",\"node_role\":\"%s\",\"node_id\":\"%s\",\"ts_unix_nano\":%" PRId64 ",\"sample_reason\":\"%s\"",
|
|
record_type,
|
|
node_role,
|
|
node_id,
|
|
record->ts_unix_nano,
|
|
sample_reason) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->local_addr[0] != '\0' &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"local_addr\":\"%s\"", local_addr) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->remote_addr[0] != '\0' &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"remote_addr\":\"%s\"", remote_addr) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_conv &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"conv\":%u", record->conv) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_rto_ms &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"rto_ms\":%u", record->rto_ms) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_srtt_ms &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"srtt_ms\":%d", record->srtt_ms) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_srttvar_ms &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"srttvar_ms\":%d", record->srttvar_ms) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_snd_wnd &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"snd_wnd\":%u", record->snd_wnd) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_rmt_wnd &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"rmt_wnd\":%u", record->rmt_wnd) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_inflight &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"inflight\":%u", record->inflight) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_window_limit &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"window_limit\":%u", record->window_limit) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_window_pressure_pct &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"window_pressure_pct\":%.3f", record->window_pressure_pct) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_bytes_sent &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"bytes_sent\":%" PRIu64, record->bytes_sent) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_bytes_received &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"bytes_received\":%" PRIu64, record->bytes_received) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_in_pkts &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"in_pkts\":%" PRIu64, record->in_pkts) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_out_pkts &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"out_pkts\":%" PRIu64, record->out_pkts) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_in_segs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"in_segs\":%" PRIu64, record->in_segs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_out_segs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"out_segs\":%" PRIu64, record->out_segs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_retrans_segs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"retrans_segs\":%" PRIu64, record->retrans_segs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_fast_retrans_segs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"fast_retrans_segs\":%" PRIu64, record->fast_retrans_segs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_early_retrans_segs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"early_retrans_segs\":%" PRIu64, record->early_retrans_segs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_lost_segs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"lost_segs\":%" PRIu64, record->lost_segs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_repeat_segs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"repeat_segs\":%" PRIu64, record->repeat_segs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_in_errs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"in_errs\":%" PRIu64, record->in_errs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_kcp_in_errs &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"kcp_in_errs\":%" PRIu64, record->kcp_in_errs) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_ring_buffer_snd_queue &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"ring_buffer_snd_queue\":%" PRIu64, record->ring_buffer_snd_queue) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_ring_buffer_rcv_queue &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"ring_buffer_rcv_queue\":%" PRIu64, record->ring_buffer_rcv_queue) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_ring_buffer_snd_buffer &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"ring_buffer_snd_buffer\":%" PRIu64, record->ring_buffer_snd_buffer) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (record->has_curr_estab &&
|
|
kcp_session_stats_appendf(&line, &line_len, ",\"curr_estab\":%" PRIu64, record->curr_estab) != 0) {
|
|
goto cleanup;
|
|
}
|
|
if (kcp_session_stats_append(&line, &line_len, "}") != 0) {
|
|
goto cleanup;
|
|
}
|
|
|
|
free(record_type);
|
|
free(node_role);
|
|
free(node_id);
|
|
free(local_addr);
|
|
free(remote_addr);
|
|
free(sample_reason);
|
|
|
|
if (omni_file_logger_write_line(&logger->file_logger, line) != 0) {
|
|
free(line);
|
|
return -1;
|
|
}
|
|
free(line);
|
|
return 0;
|
|
|
|
cleanup:
|
|
free(record_type);
|
|
free(node_role);
|
|
free(node_id);
|
|
free(local_addr);
|
|
free(remote_addr);
|
|
free(sample_reason);
|
|
free(line);
|
|
return -1;
|
|
}
|