Files
OmniSocketGo/src/kcp_session_stats.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;
}