src/common/xqc_log.c (345 lines of code) (raw):

/** * @copyright Copyright (c) 2022, Alibaba Group Holding Limited */ #include "xqc_log.h" #include "src/transport/xqc_engine.h" #ifdef PRINT_MALLOC FILE *g_malloc_info_fp; #endif static xqc_bool_t log_disable = XQC_FALSE; void xqc_log_disable(xqc_bool_t disable) { log_disable = disable; } void xqc_log_level_set(xqc_log_t *log, xqc_log_level_t level) { log->log_level = level; } xqc_log_type_t xqc_log_event_type(xqc_log_level_t level) { switch (level) { case XQC_LOG_REPORT: return GEN_REPORT; case XQC_LOG_FATAL: return GEN_FATAL; case XQC_LOG_ERROR: return GEN_ERROR; case XQC_LOG_WARN: return GEN_WARN; case XQC_LOG_STATS: return GEN_STATS; case XQC_LOG_INFO: return GEN_INFO; case XQC_LOG_DEBUG: return GEN_DEBUG; default: return GEN_DEBUG; } } xqc_log_level_t xqc_log_type_2_level(xqc_log_type_t type) { switch (type) { case GEN_REPORT: return XQC_LOG_REPORT; case GEN_FATAL: return XQC_LOG_FATAL; case GEN_ERROR: return XQC_LOG_ERROR; case GEN_WARN: return XQC_LOG_WARN; case GEN_STATS: return XQC_LOG_STATS; case GEN_INFO: return XQC_LOG_INFO; case GEN_DEBUG: return XQC_LOG_DEBUG; default: return XQC_LOG_DEBUG; } } qlog_event_importance_t xqc_qlog_event_2_level(xqc_log_type_t type) { switch (type) { /* draft-ietf-quic-qlog-quic-events */ case CON_SERVER_LISTENING: return EVENT_IMPORTANCE_EXTRA; case CON_CONNECTION_STARTED: case CON_CONNECTION_CLOSED: case CON_CONNECTION_ID_UPDATED: case CON_SPIN_BIM_UPDATED: case CON_CONNECTION_STATE_UPDATED: case CON_PATH_ASSIGNED: return EVENT_IMPORTANCE_BASE; case CON_MTU_UPDATED: return EVENT_IMPORTANCE_EXTRA; case TRA_VERSION_INFORMATION: case TRA_ALPN_INFORMATION: case TRA_PARAMETERS_SET: return EVENT_IMPORTANCE_CORE; case TRA_PARAMETERS_RESTORED: return EVENT_IMPORTANCE_BASE; case TRA_PACKET_SENT: case TRA_PACKET_RECEIVED: return EVENT_IMPORTANCE_CORE; case TRA_PACKET_DROPPED: case TRA_PACKET_BUFFERED: return EVENT_IMPORTANCE_BASE; case TRA_PACKETS_ACKED: case TRA_DATAGRAM_DROPPED: case TRA_DATAGRAMS_SENT: case TRA_DATAGRAMS_RECEIVED: return EVENT_IMPORTANCE_EXTRA; case TRA_STREAM_STATE_UPDATED: return EVENT_IMPORTANCE_BASE; case TRA_FRAMES_PROCESSED: return EVENT_IMPORTANCE_EXTRA; case TRA_STREAM_DATA_MOVED: case TRA_DATAGRAM_DATA_MOVED: return EVENT_IMPORTANCE_BASE; case REC_METRICS_UPDATED: return EVENT_IMPORTANCE_EXTRA; case SEC_KEY_UPDATED: case SEC_KEY_RETIRED: return EVENT_IMPORTANCE_BASE; case REC_PARAMETERS_SET: return EVENT_IMPORTANCE_BASE; case REC_CONGESTION_STATE_UPDATED: return EVENT_IMPORTANCE_BASE; case REC_LOSS_TIMER_UPDATED: return EVENT_IMPORTANCE_EXTRA; case REC_PACKET_LOST: return EVENT_IMPORTANCE_CORE; case REC_MARKED_FOR_RETRANSMIT: return EVENT_IMPORTANCE_EXTRA; /* draft-ietf-quic-qlog-h3-events */ case HTTP_PARAMETERS_SET: case HTTP_PARAMETERS_RESTORED: case HTTP_STREAM_TYPE_SET: case HTTP_PRIORITY_UPDATED: return EVENT_IMPORTANCE_BASE; case HTTP_FRAME_PARSED: case HTTP_FRAME_CREATED: return EVENT_IMPORTANCE_CORE; case HTTP_PUSH_RESOLVED: return EVENT_IMPORTANCE_EXTRA; /* quic-qlog-h3-events have removed all qpack event definitions since draft 05*/ case QPACK_STATE_UPDATED: case QPACK_STREAM_STATE_UPDATED: case QPACK_DYNAMIC_TABLE_UPDATED: case QPACK_HEADERS_ENCODED: case QPACK_HEADERS_DECODED: case QPACK_INSTRUCTION_CREATED: case QPACK_INSTRUCTION_PARSED: return EVENT_IMPORTANCE_REMOVED; default: return EVENT_IMPORTANCE_EXTRA; } } xqc_log_level_t qlog_importance_2_log_level(xqc_log_type_t type){ if (type >= GEN_REPORT){ return xqc_log_type_2_level(type); } switch (type) { /* datagrame, packet, frame level event should be xqc_log_debug */ case HTTP_FRAME_PARSED: case HTTP_FRAME_CREATED: case TRA_PACKETS_ACKED: case TRA_DATAGRAM_DROPPED: case TRA_DATAGRAMS_SENT: case TRA_DATAGRAMS_RECEIVED: case TRA_PACKET_SENT: case TRA_PACKET_RECEIVED: case TRA_FRAMES_PROCESSED: case TRA_STREAM_DATA_MOVED: case TRA_DATAGRAM_DATA_MOVED: case REC_LOSS_TIMER_UPDATED: case REC_PACKET_LOST: case REC_MARKED_FOR_RETRANSMIT: case TRA_PACKET_DROPPED: case TRA_PACKET_BUFFERED: return XQC_LOG_DEBUG; default: return XQC_LOG_INFO; } } const char * xqc_log_type_str(xqc_log_type_t type) { static const char *event_type2str[] = { [CON_SERVER_LISTENING] = "server_listening", [CON_CONNECTION_STARTED] = "connection_started", [CON_CONNECTION_CLOSED] = "connection_closed", [CON_CONNECTION_ID_UPDATED] = "connection_id_updated", [CON_SPIN_BIM_UPDATED] = "spin_bin_updated", [CON_CONNECTION_STATE_UPDATED] = "connection_state_updated", [CON_PATH_ASSIGNED] = "path_assigned", [CON_MTU_UPDATED] = "mtu_updated", [SEC_KEY_UPDATED] = "key_updated", [SEC_KEY_RETIRED] = "key_retired", [TRA_VERSION_INFORMATION] = "version_information", [TRA_ALPN_INFORMATION] = "alpn_information", [TRA_PARAMETERS_SET] = "tra_parameters_set", [TRA_PARAMETERS_RESTORED] = "tra_parameters_restored", [TRA_PACKET_SENT] = "packet_sent", [TRA_PACKET_RECEIVED] = "packet_received", [TRA_PACKET_DROPPED] = "packet_dropped", [TRA_PACKET_BUFFERED] = "packet_buffered", [TRA_PACKETS_ACKED] = "packets_acked", [TRA_DATAGRAMS_SENT] = "datagrams_sent", [TRA_DATAGRAMS_RECEIVED] = "datagrams_received", [TRA_DATAGRAM_DROPPED] = "datagram_dropped", [TRA_STREAM_STATE_UPDATED] = "stream_state_updated", [TRA_FRAMES_PROCESSED] = "frames_processed", [TRA_STREAM_DATA_MOVED] = "stream_data_moved", [TRA_DATAGRAM_DATA_MOVED] = "datagram_data_moved", [TRA_STATELESS_RESET] = "stateless_reset", [REC_PARAMETERS_SET] = "rec_parameters_set", [REC_METRICS_UPDATED] = "rec_metrics_updated", [REC_CONGESTION_STATE_UPDATED] = "congestion_state_updated", [REC_LOSS_TIMER_UPDATED] = "loss_timer_updated", [REC_PACKET_LOST] = "packet_lost", [REC_MARKED_FOR_RETRANSMIT] = "marked_for_retransmit", [HTTP_PARAMETERS_SET] = "http_parameters_set", [HTTP_PARAMETERS_RESTORED] = "http_parameters_restored", [HTTP_STREAM_TYPE_SET] = "http_stream_type_set", [HTTP_PRIORITY_UPDATED] = "http_priority_updated", [HTTP_FRAME_CREATED] = "http_frame_created", [HTTP_FRAME_PARSED] = "http_frame_parsed", [HTTP_PUSH_RESOLVED] = "push_resolved", [QPACK_STATE_UPDATED] = "qpack_state_updated", [QPACK_STREAM_STATE_UPDATED] = "qpack_stream_state_updated", [QPACK_DYNAMIC_TABLE_UPDATED] = "dynamic_table_updated", [QPACK_HEADERS_ENCODED] = "headers_encoded", [QPACK_HEADERS_DECODED] = "headers_decoded", [QPACK_INSTRUCTION_CREATED] = "instruction_created", [QPACK_INSTRUCTION_PARSED] = "instruction_parsed", [GEN_REPORT] = "report", [GEN_FATAL] = "fatal", [GEN_ERROR] = "error", [GEN_WARN] = "warn", [GEN_STATS] = "stats", [GEN_INFO] = "info", [GEN_DEBUG] = "debug", }; return event_type2str[type]; } void xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...) { /* do nothing if switch is off */ if (log_disable) { return; } xqc_log_level_t level = xqc_log_type_2_level(type); if (level > log->log_level) { return; } unsigned char buf[XQC_MAX_LOG_LEN] = {0}; unsigned char *p = buf; unsigned char *last = buf + sizeof(buf); /* do not need time & level if use outside log format */ if (log->log_timestamp) { /* time */ char time[64]; xqc_log_time(time, sizeof(time)); p = xqc_sprintf(p, last, "[%s] ", time); } if (log->log_level_name) { /* log level */ p = xqc_sprintf(p, last, "[%s] ", xqc_log_type_str(type)); } if (log->scid != NULL) { p = xqc_sprintf(p, last, "|scid:%s|%s", log->scid, func); } else { p = xqc_sprintf(p, last, "|%s", func); } /* log */ va_list args; va_start(args, fmt); p = xqc_vsprintf(p, last, fmt, args); va_end(args); if (p + 1 < last) { /* may use printf("%s") outside, add '\0' and don't count into size */ *p = '\0'; } /* XQC_LOG_STATS & XQC_LOG_REPORT are levels for statistic */ if ((level == XQC_LOG_STATS || level == XQC_LOG_REPORT) && log->log_callbacks->xqc_log_write_stat) { log->log_callbacks->xqc_log_write_stat(level, buf, p - buf, log->user_data); } else if (log->log_callbacks->xqc_log_write_err) { log->log_callbacks->xqc_log_write_err(level, buf, p - buf, log->user_data); } /* if didn't set log callback, just return */ } void xqc_qlog_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...) { /* do nothing if switch is off */ if (log_disable) { return; } if (!log->log_event){ return; } qlog_event_importance_t event_imp = xqc_qlog_event_2_level(type); /* EVENT_IMPORTANCE_SELECTED: events will be emitted based on their map log level and cur log level */ xqc_log_level_t level = XQC_LOG_DEBUG; if (log->qlog_importance == EVENT_IMPORTANCE_SELECTED) { level = qlog_importance_2_log_level(type); if (level > log->log_level) { return; } } unsigned char buf[XQC_MAX_LOG_LEN] = {0}; unsigned char *p = buf; unsigned char *last = buf + sizeof(buf); /* do not need time & level if use outside log format */ if (log->log_timestamp) { /* time */ char time[64]; xqc_log_time(time, sizeof(time)); p = xqc_sprintf(p, last, "[%s] ", time); } if (log->log_level_name) { /* qlog event */ p = xqc_sprintf(p, last, "[%s] ", xqc_log_type_str(type)); } if (log->scid != NULL) { p = xqc_sprintf(p, last, "|scid:%s|%s", log->scid, func); } else { p = xqc_sprintf(p, last, "|%s", func); } /* log */ va_list args; va_start(args, fmt); p = xqc_vsprintf(p, last, fmt, args); va_end(args); if (p + 1 < last) { /* may use printf("%s") outside, add '\0' and don't count into size */ *p = '\0'; } /* EVENT_IMPORTANCE_SELECTED: event logs output with xqc_log via xqc_log_write_err callback */ if (log->qlog_importance == EVENT_IMPORTANCE_SELECTED) { if (log->log_callbacks->xqc_log_write_err) { log->log_callbacks->xqc_log_write_err(level, buf, p - buf, log->user_data); } } else if(log->log_callbacks->xqc_qlog_event_write) { log->log_callbacks->xqc_qlog_event_write(event_imp, buf, p - buf, log->user_data); } } void xqc_log_time(char *buf, size_t buf_len) { struct timeval tv; gettimeofday(&tv, NULL); struct tm tm; #ifdef XQC_SYS_WINDOWS time_t t = tv.tv_sec; #ifdef _USE_32BIT_TIME_T _localtime32_s(&tm, &t); #else _localtime64_s(&tm, &t); #endif #else localtime_r(&tv.tv_sec, &tm); #endif tm.tm_mon++; tm.tm_year += 1900; #ifdef __APPLE__ snprintf(buf, buf_len, "%4d/%02d/%02d %02d:%02d:%02d %06d", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); #else snprintf(buf, buf_len, "%4d/%02d/%02d %02d:%02d:%02d %06ld", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); #endif }