1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_logger.h -- logging functions and macros. 4 * 5 * Usage (this assumes MY_MODULE) is a part of enum lsquic_logger_module): 6 * #define LSQUIC_LOGGER_MODULE MY_MODULE 7 * #include "lsquic_logger.h" 8 * LSQ_INFO("info message"); 9 * 10 * If you want log messages from your module to contain connection ID, #define 11 * LSQUIC_LOG_CONN_ID so that it evaluates to connection ID. If, in addition, 12 * you want stream ID to be logged, #define LSQUIC_LOG_STREAM_ID similarly. 13 * See existing code for examples. 14 * 15 * To add a module: 16 * 1. Add entry to enum lsquic_logger_module. 17 * 2. Update lsqlm_to_str. 18 * 3. Update lsq_log_levels. 19 */ 20 21#ifndef LSQUIC_LOGGER_H 22#define LSQUIC_LOGGER_H 23 24#include <stdint.h> 25#include <stdio.h> 26 27#include "lsquic_shared_support.h" 28 29#ifdef __cplusplus 30extern "C" { 31#endif 32 33#ifndef LSQUIC_LOWEST_LOG_LEVEL 34# define LSQUIC_LOWEST_LOG_LEVEL LSQ_LOG_DEBUG 35#endif 36 37/* Same levels as in sys/syslog.h: */ 38enum lsq_log_level { 39 LSQ_LOG_EMERG, 40 LSQ_LOG_ALERT, 41 LSQ_LOG_CRIT, 42 LSQ_LOG_ERROR, 43 LSQ_LOG_WARN, 44 LSQ_LOG_NOTICE, 45 LSQ_LOG_INFO, 46 LSQ_LOG_DEBUG, 47 N_LSQUIC_LOG_LEVELS 48}; 49 50enum lsquic_logger_module { 51 LSQLM_NOMODULE, 52 LSQLM_LOGGER, 53 LSQLM_EVENT, 54 LSQLM_ENGINE, 55 LSQLM_CONN, 56 LSQLM_STREAM, 57 LSQLM_PARSE, 58 LSQLM_CFCW, 59 LSQLM_SFCW, 60 LSQLM_SENDCTL, 61 LSQLM_ALARMSET, 62 LSQLM_CRYPTO, 63 LSQLM_HANDSHAKE, 64 LSQLM_HSK_ADAPTER, 65 LSQLM_BBR, 66 LSQLM_CUBIC, 67 LSQLM_ADAPTIVE_CC, 68 LSQLM_HEADERS, 69 LSQLM_FRAME_WRITER, 70 LSQLM_FRAME_READER, 71 LSQLM_MINI_CONN, 72 LSQLM_TOKGEN, 73 LSQLM_ENG_HIST, 74 LSQLM_SPI, 75 LSQLM_HPI, 76 LSQLM_DI, 77 LSQLM_PRQ, 78 LSQLM_PACER, 79 LSQLM_HTTP1X, 80 LSQLM_QLOG, 81 LSQLM_TRAPA, 82 LSQLM_PURGA, 83 LSQLM_HCSI_READER, 84 LSQLM_HCSO_WRITER, 85 LSQLM_QENC_HDL, 86 LSQLM_QDEC_HDL, 87 LSQLM_QPACK_ENC, 88 LSQLM_QPACK_DEC, 89 LSQLM_PRIO, 90 LSQLM_BW_SAMPLER, 91 LSQLM_PACKET_RESIZE, 92 LSQLM_CONN_STATS, 93 N_LSQUIC_LOGGER_MODULES 94}; 95 96/* Each module has its own log level. 97 */ 98 99LSQUIC_EXTERN enum lsq_log_level lsq_log_levels[N_LSQUIC_LOGGER_MODULES]; 100 101extern const char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES]; 102 103extern const char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS]; 104 105#define LSQ_LOG_ENABLED_EXT(level, module) ( \ 106 level <= LSQUIC_LOWEST_LOG_LEVEL && level <= lsq_log_levels[module]) 107 108#define LSQ_LOG_ENABLED(level) LSQ_LOG_ENABLED_EXT(level, LSQUIC_LOGGER_MODULE) 109 110struct lsquic_cid; 111 112/* The functions that perform actual logging are void. This is an 113 * optimization. In majority of cases the calls will succeed; even if 114 * they fail, there is nothing (at least, nothing simple) to be done to 115 * handle logging failure. 116 */ 117 118/* There are four levels of log functions, depending on whether they take 119 * the following arguments: 120 * 1. Logger module 121 * 2. Connection ID 122 * 3. Stream ID 123 * 124 * Each level of logging function supports one additional argument, as seen 125 * below. LSQ_LOG is set to one of LSQ_LOG0, LSQ_LOG1, LSQ_LOG2, or LSQ_LOG3. 126 * You can still use LSQ_LOG{0..3} directly. 127 */ 128 129void 130lsquic_logger_log3 (enum lsq_log_level, enum lsquic_logger_module, 131 const struct lsquic_cid *conn_id, 132 lsquic_stream_id_t stream_id, const char *format, ...) 133#if __GNUC__ 134 __attribute__((format(printf, 5, 6))) 135#endif 136; 137# define LSQ_LOG3(level, ...) do { \ 138 if (LSQ_LOG_ENABLED(level)) \ 139 lsquic_logger_log3(level, LSQUIC_LOGGER_MODULE, \ 140 LSQUIC_LOG_CONN_ID, LSQUIC_LOG_STREAM_ID, __VA_ARGS__); \ 141 } while (0) 142 143 144void 145lsquic_logger_log2 (enum lsq_log_level, enum lsquic_logger_module, 146 const struct lsquic_cid *conn_id, const char *format, ...) 147#if __GNUC__ 148 __attribute__((format(printf, 4, 5))) 149#endif 150; 151# define LSQ_LOG2(level, ...) do { \ 152 if (LSQ_LOG_ENABLED(level)) \ 153 lsquic_logger_log2(level, LSQUIC_LOGGER_MODULE, \ 154 LSQUIC_LOG_CONN_ID, __VA_ARGS__); \ 155 } while (0) 156# define LSQ_LOG2C(level, ...) do { \ 157 if (LSQ_LOG_ENABLED(level)) \ 158 { \ 159 char cidbuf_[MAX_CID_LEN * 2 + 1]; \ 160 lsquic_logger_log2(level, LSQUIC_LOGGER_MODULE, \ 161 LSQUIC_LOG_CONN_ID, __VA_ARGS__); \ 162 } \ 163 } while (0) 164 165void 166lsquic_logger_log1 (enum lsq_log_level, enum lsquic_logger_module, 167 const char *format, ...) 168#if __GNUC__ 169 __attribute__((format(printf, 3, 4))) 170#endif 171; 172# define LSQ_LOG1(level, ...) do { \ 173 if (LSQ_LOG_ENABLED(level)) \ 174 lsquic_logger_log1(level, LSQUIC_LOGGER_MODULE, __VA_ARGS__); \ 175 } while (0) 176# define LSQ_LOG1C(level, ...) do { \ 177 if (LSQ_LOG_ENABLED(level)) \ 178 { \ 179 char cidbuf_[MAX_CID_LEN * 2 + 1]; \ 180 lsquic_logger_log1(level, LSQUIC_LOGGER_MODULE, __VA_ARGS__); \ 181 } \ 182 } while (0) 183 184void 185lsquic_logger_log0 (enum lsq_log_level, const char *format, ...) 186#if __GNUC__ 187 __attribute__((format(printf, 2, 3))) 188#endif 189; 190# define LSQ_LOG0(level, ...) do { \ 191 if (LSQ_LOG_ENABLED(level)) \ 192 lsquic_logger_log0(level, __VA_ARGS__); \ 193 } while (0) 194# define LSQ_LOG0C(level, ...) do { \ 195 if (LSQ_LOG_ENABLED(level)) \ 196 { \ 197 char cidbuf_[MAX_CID_LEN * 2 + 1]; \ 198 lsquic_logger_log0(level, __VA_ARGS__); \ 199 } \ 200 } while (0) 201 202#if defined(LSQUIC_LOGGER_MODULE) 203#if defined(LSQUIC_LOG_CONN_ID) 204#if defined(LSQUIC_LOG_STREAM_ID) 205# define LSQ_LOG LSQ_LOG3 206#else 207# define LSQ_LOG LSQ_LOG2 208# define LSQ_LOGC LSQ_LOG2C 209#endif 210#else 211# define LSQ_LOG LSQ_LOG1 212# define LSQ_LOGC LSQ_LOG1C 213#endif 214#else 215# define LSQ_LOG LSQ_LOG0 216# define LSQ_LOGC LSQ_LOG0C 217# define LSQUIC_LOGGER_MODULE LSQLM_NOMODULE 218#endif 219 220#define LSQ_DEBUG(...) LSQ_LOG(LSQ_LOG_DEBUG, __VA_ARGS__) 221#define LSQ_WARN(...) LSQ_LOG(LSQ_LOG_WARN, __VA_ARGS__) 222#define LSQ_ALERT(...) LSQ_LOG(LSQ_LOG_ALERT, __VA_ARGS__) 223#define LSQ_CRIT(...) LSQ_LOG(LSQ_LOG_CRIT, __VA_ARGS__) 224#define LSQ_ERROR(...) LSQ_LOG(LSQ_LOG_ERROR, __VA_ARGS__) 225#define LSQ_NOTICE(...) LSQ_LOG(LSQ_LOG_NOTICE, __VA_ARGS__) 226#define LSQ_INFO(...) LSQ_LOG(LSQ_LOG_INFO, __VA_ARGS__) 227#define LSQ_EMERG(...) LSQ_LOG(LSQ_LOG_EMERG, __VA_ARGS__) 228 229#define LSQ_DEBUGC(...) LSQ_LOGC(LSQ_LOG_DEBUG, __VA_ARGS__) 230#define LSQ_WARNC(...) LSQ_LOGC(LSQ_LOG_WARN, __VA_ARGS__) 231#define LSQ_ALERTC(...) LSQ_LOGC(LSQ_LOG_ALERT, __VA_ARGS__) 232#define LSQ_CRITC(...) LSQ_LOGC(LSQ_LOG_CRIT, __VA_ARGS__) 233#define LSQ_ERRORC(...) LSQ_LOGC(LSQ_LOG_ERROR, __VA_ARGS__) 234#define LSQ_NOTICEC(...) LSQ_LOGC(LSQ_LOG_NOTICE, __VA_ARGS__) 235#define LSQ_INFOC(...) LSQ_LOGC(LSQ_LOG_INFO, __VA_ARGS__) 236#define LSQ_EMERGC(...) LSQ_LOGC(LSQ_LOG_EMERG, __VA_ARGS__) 237 238/* Shorthand for printing to file streams using internal lsquic_logger_if 239 */ 240void 241lsquic_log_to_fstream (FILE *, unsigned llts); 242 243enum lsquic_logger_module 244lsquic_str_to_logger_module (const char *); 245 246enum lsq_log_level 247lsquic_str_to_log_level (const char *); 248 249/* Parse and set log levels passed via -l flag. If an error is encountered, 250 * an error message is printed to stderr and negative value is returned. 251 */ 252int 253lsquic_logger_lopt (const char *optarg); 254 255#define CID_FMT ".*s" 256 257#define CID_BITS_B(cid, b) 2 * (int) (cid)->len, \ 258 (lsquic_cid2str(cid, b), b) 259 260#define CID_BITS(cid) CID_BITS_B(cid, cidbuf_) 261 262void 263lsquic_cid2str (const struct lsquic_cid *, char *out); 264 265const struct lsquic_cid * 266lsquic_conn_log_cid (const struct lsquic_conn *); 267 268#ifdef __cplusplus 269} 270#endif 271 272#endif 273