feature: add JsonSockLogLevel directive for configurable log levels

- New directive: JsonSockLogLevel (DEBUG, INFO, WARNING, ERROR, EMERG)
- Default level: WARNING
- Controls verbosity of module logs in Apache error_log
- DEBUG: Log header skipping, buffer truncation, size limits
- Updates conf/mod_reqin_log.conf with example configuration

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Jacquin Antoine
2026-03-01 02:31:16 +01:00
parent c61774f8ec
commit 3d2e4f8e70
3 changed files with 67 additions and 8 deletions

View File

@ -54,6 +54,9 @@
} \
} while(0)
/* Helper macro to check if a log level should be emitted */
#define SHOULD_LOG(srv_conf, level) ((srv_conf) && (srv_conf)->log_level <= (level))
/* Default sensitive headers blacklist - prevents accidental logging of credentials */
static const char *const DEFAULT_SENSITIVE_HEADERS[] = {
"Authorization",
@ -84,10 +87,20 @@ typedef struct {
int connect_failed;
} reqin_log_child_state_t;
/* Log levels */
typedef enum {
REQIN_LOG_LEVEL_DEBUG = 0,
REQIN_LOG_LEVEL_INFO = 1,
REQIN_LOG_LEVEL_WARNING = 2,
REQIN_LOG_LEVEL_ERROR = 3,
REQIN_LOG_LEVEL_EMERG = 4
} reqin_log_level_t;
/* Module server configuration structure */
typedef struct {
reqin_log_config_t *config;
reqin_log_child_state_t child_state;
reqin_log_level_t log_level;
} reqin_log_server_conf_t;
/* Forward declarations for helper functions */
@ -107,6 +120,7 @@ static const char *cmd_set_max_headers(cmd_parms *cmd, void *dummy, const char *
static const char *cmd_set_max_header_value_len(cmd_parms *cmd, void *dummy, const char *arg);
static const char *cmd_set_reconnect_interval(cmd_parms *cmd, void *dummy, const char *arg);
static const char *cmd_set_error_report_interval(cmd_parms *cmd, void *dummy, const char *arg);
static const char *cmd_set_log_level(cmd_parms *cmd, void *dummy, const char *arg);
/* Forward declarations for hooks */
static int reqin_log_post_read_request(request_rec *r);
@ -130,6 +144,8 @@ static const command_rec reqin_log_cmds[] = {
"Reconnect interval in seconds (default: 10)"),
AP_INIT_TAKE1("JsonSockLogErrorReportInterval", cmd_set_error_report_interval, NULL, RSRC_CONF,
"Error report interval in seconds (default: 10)"),
AP_INIT_TAKE1("JsonSockLogLevel", cmd_set_log_level, NULL, RSRC_CONF,
"Log level: DEBUG, INFO, WARNING, ERROR, EMERG (default: WARNING)"),
{ NULL }
};
@ -170,6 +186,8 @@ static void *reqin_log_create_server_conf(apr_pool_t *pool, server_rec *s)
srv_conf->child_state.last_error_report = 0;
srv_conf->child_state.connect_failed = 0;
srv_conf->log_level = REQIN_LOG_LEVEL_WARNING;
return srv_conf;
}
@ -413,6 +431,32 @@ static const char *cmd_set_error_report_interval(cmd_parms *cmd, void *dummy, co
return NULL;
}
static const char *cmd_set_log_level(cmd_parms *cmd, void *dummy, const char *arg)
{
(void)dummy;
reqin_log_server_conf_t *srv_conf = get_server_conf(cmd->server);
if (srv_conf == NULL) {
return "Internal error: server configuration not available";
}
if (arg == NULL || arg[0] == '\0') {
return "JsonSockLogLevel must be a non-empty string";
}
if (strcasecmp(arg, "DEBUG") == 0) {
srv_conf->log_level = REQIN_LOG_LEVEL_DEBUG;
} else if (strcasecmp(arg, "INFO") == 0) {
srv_conf->log_level = REQIN_LOG_LEVEL_INFO;
} else if (strcasecmp(arg, "WARNING") == 0) {
srv_conf->log_level = REQIN_LOG_LEVEL_WARNING;
} else if (strcasecmp(arg, "ERROR") == 0) {
srv_conf->log_level = REQIN_LOG_LEVEL_ERROR;
} else if (strcasecmp(arg, "EMERG") == 0) {
srv_conf->log_level = REQIN_LOG_LEVEL_EMERG;
} else {
return "JsonSockLogLevel must be one of: DEBUG, INFO, WARNING, ERROR, EMERG";
}
return NULL;
}
/* ============== Socket Functions ============== */
/**
@ -612,7 +656,7 @@ static const char *get_header(request_rec *r, const char *name)
return NULL;
}
static void log_request(request_rec *r, reqin_log_config_t *cfg, reqin_log_child_state_t *state)
static void log_request(request_rec *r, reqin_log_config_t *cfg, reqin_log_child_state_t *state, reqin_log_server_conf_t *srv_conf)
{
apr_pool_t *pool;
server_rec *s;
@ -736,8 +780,10 @@ static void log_request(request_rec *r, reqin_log_config_t *cfg, reqin_log_child
/* Check buffer size before adding headers to prevent memory exhaustion */
if (buf.len >= MAX_JSON_SIZE) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
MOD_REQIN_LOG_NAME ": JSON buffer size limit reached before headers");
if (SHOULD_LOG(srv_conf, REQIN_LOG_LEVEL_DEBUG)) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
MOD_REQIN_LOG_NAME ": JSON buffer size limit reached before headers");
}
return;
}
@ -753,8 +799,10 @@ static void log_request(request_rec *r, reqin_log_config_t *cfg, reqin_log_child
/* Skip sensitive headers to prevent credential leakage */
if (is_sensitive_header(header_name)) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
MOD_REQIN_LOG_NAME ": Skipping sensitive header: %s", header_name);
if (SHOULD_LOG(srv_conf, REQIN_LOG_LEVEL_DEBUG)) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
MOD_REQIN_LOG_NAME ": Skipping sensitive header: %s", header_name);
}
continue;
}
@ -766,8 +814,10 @@ static void log_request(request_rec *r, reqin_log_config_t *cfg, reqin_log_child
char *truncated;
if (buf.len + header_contrib >= MAX_JSON_SIZE) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
MOD_REQIN_LOG_NAME ": JSON size limit reached, truncating headers");
if (SHOULD_LOG(srv_conf, REQIN_LOG_LEVEL_DEBUG)) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
MOD_REQIN_LOG_NAME ": JSON size limit reached, truncating headers");
}
break;
}
@ -824,7 +874,7 @@ static int reqin_log_post_read_request(request_rec *r)
return DECLINED;
}
log_request(r, srv_conf->config, &srv_conf->child_state);
log_request(r, srv_conf->config, &srv_conf->child_state, srv_conf);
return DECLINED;
}