wslog: Add support for domain filtering

A domain filter can be given in the environment variable
'WS_LOG_DOMAINS' or in a command-line options "--log-domains".

The filter is specified as a comma separated case insensitive list,
for example:

    ./tshark  --log-domains=main,capture

Domain data type switches from an enum to a string. There is no
constaint on adding new domains, neither in code or at runtime.
The string format is arbitrary, only positive matches will produce
output.
This commit is contained in:
João Valverde 2021-06-11 13:39:16 +01:00
parent 82739fc4f5
commit 5a662ba3fb
16 changed files with 153 additions and 96 deletions

View File

@ -150,7 +150,7 @@ capture_opts_cleanup(capture_options *capture_opts)
/* log content of capture_opts */ /* log content of capture_opts */
void void
capture_opts_log(enum ws_log_domain log_domain, enum ws_log_level log_level, capture_options *capture_opts) { capture_opts_log(const char *log_domain, enum ws_log_level log_level, capture_options *capture_opts) {
guint i; guint i;
ws_log(log_domain, log_level, "CAPTURE OPTIONS :"); ws_log(log_domain, log_level, "CAPTURE OPTIONS :");

View File

@ -339,7 +339,7 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg)
/* log content of capture_opts */ /* log content of capture_opts */
extern void extern void
capture_opts_log(enum ws_log_domain domain, enum ws_log_level level, capture_options *capture_opts); capture_opts_log(const char *domain, enum ws_log_level level, capture_options *capture_opts);
enum caps_query { enum caps_query {
CAPS_QUERY_LINK_TYPES = 0x1, CAPS_QUERY_LINK_TYPES = 0x1,

View File

@ -227,7 +227,6 @@ libwsutil.so.0 libwsutil0 #MINVER#
ws_init_sockets@Base 3.1.0 ws_init_sockets@Base 3.1.0
ws_log@Base 3.5.0 ws_log@Base 3.5.0
ws_log_add_custom_file@Base 3.5.0 ws_log_add_custom_file@Base 3.5.0
ws_log_domain_to_string@Base 3.5.0
ws_log_fprint@Base 3.5.0 ws_log_fprint@Base 3.5.0
ws_log_full@Base 3.5.0 ws_log_full@Base 3.5.0
ws_log_get_level@Base 3.5.0 ws_log_get_level@Base 3.5.0
@ -235,6 +234,8 @@ libwsutil.so.0 libwsutil0 #MINVER#
ws_log_init_with_data@Base 3.5.0 ws_log_init_with_data@Base 3.5.0
ws_log_level_is_active@Base 3.5.0 ws_log_level_is_active@Base 3.5.0
ws_log_level_to_string@Base 3.5.0 ws_log_level_to_string@Base 3.5.0
ws_log_set_domain_filter_args@Base 3.5.0
ws_log_set_domain_filter_str@Base 3.5.0
ws_log_set_level@Base 3.5.0 ws_log_set_level@Base 3.5.0
ws_log_set_level_args@Base 3.5.0 ws_log_set_level_args@Base 3.5.0
ws_log_set_level_str@Base 3.5.0 ws_log_set_level_str@Base 3.5.0

View File

@ -329,7 +329,7 @@ static gboolean need_timeout_workaround;
static void static void
dumpcap_log_writer(const char *format, va_list ap, dumpcap_log_writer(const char *format, va_list ap,
const char *prefix, const char *prefix,
enum ws_log_domain domain, const char *domain,
enum ws_log_level level, enum ws_log_level level,
void *user_data); void *user_data);
@ -4859,6 +4859,7 @@ main(int argc, char *argv[])
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
exit (1); exit (1);
} }
ws_log_set_domain_filter_args(&argc, argv);
#ifdef _WIN32 #ifdef _WIN32
create_app_running_mutex(); create_app_running_mutex();
@ -5572,7 +5573,7 @@ main(int argc, char *argv[])
static void static void
dumpcap_log_writer(const char *format, va_list ap, dumpcap_log_writer(const char *format, va_list ap,
const char *prefix, const char *prefix,
enum ws_log_domain domain _U_, const char *domain _U_,
enum ws_log_level level _U_, enum ws_log_level level _U_,
void *user_data _U_) void *user_data _U_)
{ {

View File

@ -2540,6 +2540,7 @@ int main(int argc, char *argv[]) {
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
ws_log_set_domain_filter_args(&argc, argv);
/* /*
* Get credential information for later use. * Get credential information for later use.

View File

@ -163,6 +163,7 @@ int main(int argc, char *argv[])
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
ws_log_set_domain_filter_args(&argc, argv);
/* /*
* Get credential information for later use. * Get credential information for later use.

View File

@ -459,6 +459,7 @@ main(int argc, char *argv[])
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
return INVALID_OPTION; return INVALID_OPTION;
} }
ws_log_set_domain_filter_args(&argc, argv);
/* Initialize the version information. */ /* Initialize the version information. */
ws_init_version_info("Rawshark (Wireshark)", NULL, ws_init_version_info("Rawshark (Wireshark)", NULL,

View File

@ -126,6 +126,7 @@ main(int argc, char *argv[])
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
return INIT_FAILED; return INIT_FAILED;
} }
ws_log_set_domain_filter_args(&argc, argv);
/* /*
* Get credential information for later use, and drop privileges * Get credential information for later use, and drop privileges

View File

@ -359,6 +359,7 @@ main(int argc, char *argv[])
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
return INVALID_OPTION; return INVALID_OPTION;
} }
ws_log_set_domain_filter_args(&argc, argv);
#ifdef _WIN32 #ifdef _WIN32
create_app_running_mutex(); create_app_running_mutex();

View File

@ -784,6 +784,7 @@ main(int argc, char *argv[])
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
return INVALID_OPTION; return INVALID_OPTION;
} }
ws_log_set_domain_filter_args(&argc, argv);
ws_debug("tshark started with %d args", argc); ws_debug("tshark started with %d args", argc);

View File

@ -20,7 +20,7 @@
void void
console_log_writer(const char *format, va_list ap, console_log_writer(const char *format, va_list ap,
const char *prefix, enum ws_log_domain domain _U_, const char *prefix, const char *domain _U_,
enum ws_log_level level _U_, void *ptr _U_) enum ws_log_level level _U_, void *ptr _U_)
{ {
gboolean fatal = level == LOG_LEVEL_ERROR; gboolean fatal = level == LOG_LEVEL_ERROR;

View File

@ -27,7 +27,7 @@ extern "C" {
*/ */
void void
console_log_writer(const char *format, va_list ap, console_log_writer(const char *format, va_list ap,
const char *prefix, enum ws_log_domain domain, const char *prefix, const char *domain,
enum ws_log_level level, void *ptr); enum ws_log_level level, void *ptr);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -587,6 +587,7 @@ int main(int argc, char *qt_argv[])
cmdarg_err("Invalid log level \"%s\"", opt_err_val); cmdarg_err("Invalid log level \"%s\"", opt_err_val);
exit_application(INVALID_OPTION); exit_application(INVALID_OPTION);
} }
ws_log_set_domain_filter_args(&argc, argv);
/* /*
* Get credential information for later use, and drop privileges * Get credential information for later use, and drop privileges

View File

@ -11,22 +11,21 @@
#ifndef __WS_LOG_DOMAINS_H__ #ifndef __WS_LOG_DOMAINS_H__
#define __WS_LOG_DOMAINS_H__ #define __WS_LOG_DOMAINS_H__
enum ws_log_domain { /* Null domain */
#define LOG_DOMAIN_NONE "(notset)"
/* Default domain */ /* Default domain */
LOG_DOMAIN_DEFAULT, #define LOG_DOMAIN_DEFAULT "Default"
/* Main execution domain (wireshark, tshark, etc) */ /* Main execution domain (wireshark, tshark, etc) */
LOG_DOMAIN_MAIN, #define LOG_DOMAIN_MAIN "Main"
/* Capture domain (except for capture child, see below) */ /* Capture domain (except for capture child, see below) */
LOG_DOMAIN_CAPTURE, #define LOG_DOMAIN_CAPTURE "Capture"
/* Capture child domain (the capture child might also contain /* Capture child domain (the capture child might also contain
* file domain messages!) */ * file domain messages!) */
LOG_DOMAIN_CAPCHILD, #define LOG_DOMAIN_CAPCHILD "Capchild"
LOG_DOMAIN_WIRETAP, #define LOG_DOMAIN_WIRETAP "Wiretap"
LOG_DOMAIN_EPAN, #define LOG_DOMAIN_EPAN "Epan"
LOG_DOMAIN_WSUTIL, #define LOG_DOMAIN_WSUTIL "WSUtil"
LOG_DOMAIN_QTUI, #define LOG_DOMAIN_QTUI "GUI"
_LOG_DOMAIN_LAST
};
#endif /* __WS_LOG_DOMAINS_H__ */ #endif /* __WS_LOG_DOMAINS_H__ */

View File

@ -20,13 +20,16 @@
#define PREFIX_BUFSIZE 128 #define PREFIX_BUFSIZE 128
#define LOGENVVAR "WS_LOG_LEVEL" #define _ENV_LEVEL "WS_LOG_LEVEL"
#define _ENV_DOMAINS "WS_LOG_DOMAINS"
/* TODO: Add filtering by domain. */ /* TODO: Add filtering by domain. */
static enum ws_log_level current_log_level = LOG_LEVEL_MESSAGE; static enum ws_log_level current_log_level = LOG_LEVEL_MESSAGE;
GPtrArray *domain_filter = NULL;
static ws_log_writer_cb *registered_log_writer = NULL; static ws_log_writer_cb *registered_log_writer = NULL;
static void *registered_log_writer_data = NULL; static void *registered_log_writer_data = NULL;
@ -73,37 +76,33 @@ const char *ws_log_level_to_string(enum ws_log_level level)
} }
const char *ws_log_domain_to_string(enum ws_log_domain domain)
{
switch (domain) {
case LOG_DOMAIN_DEFAULT:
return "Default";
case LOG_DOMAIN_MAIN:
return "Main";
case LOG_DOMAIN_CAPTURE:
return "Capture";
case LOG_DOMAIN_CAPCHILD:
return "CapChild";
case LOG_DOMAIN_WIRETAP:
return "Wiretap";
case LOG_DOMAIN_EPAN:
return "Epan";
case LOG_DOMAIN_WSUTIL:
return "Util";
case LOG_DOMAIN_QTUI:
return "GUI";
default:
return "(BOGUS LOG DOMAIN)";
}
}
gboolean ws_log_level_is_active(enum ws_log_level level) gboolean ws_log_level_is_active(enum ws_log_level level)
{ {
return level <= current_log_level; return level <= current_log_level;
} }
gboolean ws_log_domain_is_active(const char *domain)
{
if (domain_filter == NULL)
return TRUE;
for (guint i = 0; i < domain_filter->len; i++) {
if (g_ascii_strcasecmp(domain_filter->pdata[i], domain) == 0) {
return TRUE;
}
}
return FALSE;
}
static gboolean log_drop_message(const char *domain, enum ws_log_level level)
{
return !ws_log_level_is_active(level) || !ws_log_domain_is_active(domain);
}
enum ws_log_level ws_log_get_level(void) enum ws_log_level ws_log_get_level(void)
{ {
return current_log_level; return current_log_level;
@ -146,14 +145,11 @@ enum ws_log_level ws_log_set_level_str(const char *str_level)
} }
static const char *set_level_and_prune_argv(int count, char **ptr, int prune_extra, static const char *log_prune_argv(int count, char **ptr, int prune_extra,
const char *optarg, int *ret_argc) const char *optarg, int *ret_argc)
{ {
if (optarg && ws_log_set_level_str(optarg) != LOG_LEVEL_NONE)
optarg = NULL; /* success */
/* /*
* We found a "--log-level" option. We will remove it from * We found a log option. We will remove it from
* the argv by moving up the other strings in the array. This is * the argv by moving up the other strings in the array. This is
* so that it doesn't generate an unrecognized option * so that it doesn't generate an unrecognized option
* error further along in the initialization process. * error further along in the initialization process.
@ -165,21 +161,20 @@ static const char *set_level_and_prune_argv(int count, char **ptr, int prune_ext
return optarg; return optarg;
} }
const char *ws_log_set_level_args(int *argc_ptr, char *argv[]) const char *log_parse_args(int *argc_ptr, char *argv[], const char *optstr)
{ {
char **p; char **p;
int c; int c;
const char *opt = "--log-level"; size_t optlen = strlen(optstr);
size_t len = strlen(opt);
const char *optarg; const char *optarg;
for (p = argv, c = *argc_ptr; *p != NULL; p++, c--) { for (p = argv, c = *argc_ptr; *p != NULL; p++, c--) {
if (strncmp(*p, opt, len) == 0) { if (strncmp(*p, optstr, optlen) == 0) {
optarg = *p + len; optarg = *p + optlen;
/* Two possibilities: /* Two possibilities:
* --log_level <level> * --<option> <value>
* or * or
* --log-level=<level> * --<option>=<value>
*/ */
if (optarg[0] == '\0') { if (optarg[0] == '\0') {
/* value is separated with blank space */ /* value is separated with blank space */
@ -188,14 +183,14 @@ const char *ws_log_set_level_args(int *argc_ptr, char *argv[])
/* If the option value after the blank is missing or stars with '-' just ignore it. /* If the option value after the blank is missing or stars with '-' just ignore it.
* But we should probably signal an error (missing required value). */ * But we should probably signal an error (missing required value). */
if (optarg == NULL || !*optarg || *optarg == '-') { if (optarg == NULL || !*optarg || *optarg == '-') {
return set_level_and_prune_argv(c, p, 0, NULL, argc_ptr); return log_prune_argv(c, p, 0, NULL, argc_ptr);
} }
return set_level_and_prune_argv(c, p, 1, optarg, argc_ptr); return log_prune_argv(c, p, 1, optarg, argc_ptr);
} }
else if (optarg[0] == '=') { else if (optarg[0] == '=') {
/* value is after equals */ /* value is after equals */
optarg += 1; optarg += 1;
return set_level_and_prune_argv(c, p, 0, optarg, argc_ptr); return log_prune_argv(c, p, 0, optarg, argc_ptr);
} }
/* we didn't find what we want */ /* we didn't find what we want */
} }
@ -204,17 +199,72 @@ const char *ws_log_set_level_args(int *argc_ptr, char *argv[])
} }
const char *ws_log_set_level_args(int *argc_ptr, char *argv[])
{
const char *optval = NULL;
enum ws_log_level level;
optval = log_parse_args(argc_ptr, argv, "--log-level");
if (optval == NULL)
return NULL;
level = ws_log_set_level_str(optval);
if (level == LOG_LEVEL_NONE)
return optval;
return NULL;
}
void ws_log_set_domain_filter_str(const char *str_filter)
{
char *tok;
const char *sep = ",;";
char *str;
if (domain_filter != NULL)
g_ptr_array_free(domain_filter, TRUE);
domain_filter = g_ptr_array_new_with_free_func(g_free);
str = g_strdup(str_filter);
for (tok = strtok(str, sep); tok != NULL; tok = strtok(NULL, sep)) {
g_ptr_array_add(domain_filter, g_strdup(tok));
}
g_free(str);
}
void ws_log_set_domain_filter_args(int *argc_ptr, char *argv[])
{
const char *optval = NULL;
optval = log_parse_args(argc_ptr, argv, "--log-domains");
if (optval == NULL)
return;
ws_log_set_domain_filter_str(optval);
}
void ws_log_init(ws_log_writer_cb *_writer) void ws_log_init(ws_log_writer_cb *_writer)
{ {
if (_writer) { if (_writer) {
registered_log_writer = _writer; registered_log_writer = _writer;
} }
const char *env = g_getenv(LOGENVVAR); const char *env;
env = g_getenv(_ENV_LEVEL);
if (env && ws_log_set_level_str(env) == LOG_LEVEL_NONE) { if (env && ws_log_set_level_str(env) == LOG_LEVEL_NONE) {
fprintf(stderr, "Ignoring invalid environment value %s=\"%s\"\n", LOGENVVAR, env); fprintf(stderr, "Ignoring invalid environment value %s=\"%s\"\n", _ENV_LEVEL, env);
} }
env = g_getenv(_ENV_DOMAINS);
if (env)
ws_log_set_domain_filter_str(env);
atexit(ws_log_cleanup); atexit(ws_log_cleanup);
} }
@ -244,23 +294,6 @@ static inline const char *_lvl_to_str(enum ws_log_level level)
} }
static inline const char *_dom_to_str(enum ws_log_domain domain)
{
switch (domain) {
case LOG_DOMAIN_DEFAULT: return "Dflt";
case LOG_DOMAIN_MAIN: return "Main";
case LOG_DOMAIN_CAPTURE: return "Capt";
case LOG_DOMAIN_CAPCHILD: return "CChd";
case LOG_DOMAIN_WIRETAP: return "Wtap";
case LOG_DOMAIN_EPAN: return "Epan";
case LOG_DOMAIN_WSUTIL: return "Util";
case LOG_DOMAIN_QTUI: return "Qtui";
default:
return "(BOGUS LOG DOMAIN)";
}
}
struct logstr { struct logstr {
char buffer[PREFIX_BUFSIZE]; char buffer[PREFIX_BUFSIZE];
char *ptr; char *ptr;
@ -328,12 +361,12 @@ static void create_log_time(struct logstr *str)
static void logstr_prefix_print(struct logstr *str, static void logstr_prefix_print(struct logstr *str,
enum ws_log_domain domain, enum ws_log_level level, const char *domain, enum ws_log_level level,
const char *file, int line, const char *func) const char *file, int line, const char *func)
{ {
create_log_time(str); create_log_time(str);
logstr_snprintf(str, " [%s-%s]", _dom_to_str(domain), _lvl_to_str(level)); logstr_snprintf(str, " [%s-%s]", domain, _lvl_to_str(level));
if (func) if (func)
logstr_snprintf(str, " %s()", func); logstr_snprintf(str, " %s()", func);
@ -346,7 +379,7 @@ static void logstr_prefix_print(struct logstr *str,
} }
static void log_internal_write(enum ws_log_domain domain, enum ws_log_level level, static void log_internal_write(const char *domain, enum ws_log_level level,
const char *file, int line, const char *func, const char *file, int line, const char *func,
const char *user_format, va_list user_ap) const char *user_format, va_list user_ap)
{ {
@ -377,22 +410,22 @@ static void log_internal_write(enum ws_log_domain domain, enum ws_log_level leve
} }
void ws_logv(enum ws_log_domain domain, enum ws_log_level level, void ws_logv(const char *domain, enum ws_log_level level,
const char *format, va_list ap) const char *format, va_list ap)
{ {
if (!ws_log_level_is_active(level)) if (log_drop_message(domain, level))
return; return;
log_internal_write(domain, level, NULL, -1, NULL, format, ap); log_internal_write(domain, level, NULL, -1, NULL, format, ap);
} }
void ws_log(enum ws_log_domain domain, enum ws_log_level level, void ws_log(const char *domain, enum ws_log_level level,
const char *format, ...) const char *format, ...)
{ {
va_list ap; va_list ap;
if (!ws_log_level_is_active(level)) if (log_drop_message(domain, level))
return; return;
va_start(ap, format); va_start(ap, format);
@ -401,13 +434,13 @@ void ws_log(enum ws_log_domain domain, enum ws_log_level level,
} }
void ws_log_full(enum ws_log_domain domain, enum ws_log_level level, void ws_log_full(const char *domain, enum ws_log_level level,
const char *file, int line, const char *func, const char *file, int line, const char *func,
const char *format, ...) const char *format, ...)
{ {
va_list ap; va_list ap;
if (!ws_log_level_is_active(level)) if (log_drop_message(domain, level))
return; return;
va_start(ap, format); va_start(ap, format);
@ -426,6 +459,10 @@ static void ws_log_cleanup(void)
fclose(custom_log); fclose(custom_log);
custom_log = NULL; custom_log = NULL;
} }
if (domain_filter) {
g_ptr_array_free(domain_filter, TRUE);
domain_filter = NULL;
}
} }

View File

@ -43,7 +43,7 @@ enum ws_log_level {
/** Callback for registering a log writer. */ /** Callback for registering a log writer. */
typedef void (ws_log_writer_cb)(const char *format, va_list ap, typedef void (ws_log_writer_cb)(const char *format, va_list ap,
const char *prefix, const char *prefix,
enum ws_log_domain domain, const char *domain,
enum ws_log_level level, enum ws_log_level level,
void *user_data); void *user_data);
@ -63,11 +63,6 @@ WS_DLL_PUBLIC
const char *ws_log_level_to_string(enum ws_log_level level); const char *ws_log_level_to_string(enum ws_log_level level);
/** Convert a numerical domain to its string representation. */
WS_DLL_PUBLIC
const char *ws_log_domain_to_string(enum ws_log_domain domain);
/** Checks if the active log level would discard a message for the given /** Checks if the active log level would discard a message for the given
* log domain. * log domain.
* *
@ -108,6 +103,23 @@ WS_DLL_PUBLIC
const char *ws_log_set_level_args(int *argcp, char **argv); const char *ws_log_set_level_args(int *argcp, char **argv);
/** Set a domain filter from a string.
*
* Domain filter is a case insensitive list separated by ',' or ';'. Only
* the domains in the filter will generate output; the others will be muted.
*/
WS_DLL_PUBLIC
void ws_log_set_domain_filter_str(const char *domain_filter);
/** Set the active domain from an argv vector.
*
* Same as above but parses the filter from the command line arguments.
*/
WS_DLL_PUBLIC
void ws_log_set_domain_filter_args(int *argcp, char **argv);
/** Initializes the logging code. /** Initializes the logging code.
* *
* Must be called at startup before using the log API. If provided the * Must be called at startup before using the log API. If provided the
@ -134,7 +146,7 @@ void ws_log_init_with_data(ws_log_writer_cb *writer, void *user_data,
* Takes a format string and a variable number of arguments. * Takes a format string and a variable number of arguments.
*/ */
WS_DLL_PUBLIC WS_DLL_PUBLIC
void ws_log(enum ws_log_domain domain, enum ws_log_level level, void ws_log(const char *domain, enum ws_log_level level,
const char *format, ...) G_GNUC_PRINTF(3,4); const char *format, ...) G_GNUC_PRINTF(3,4);
/** This function is called to output a message to the log. /** This function is called to output a message to the log.
@ -142,7 +154,7 @@ void ws_log(enum ws_log_domain domain, enum ws_log_level level,
* Takes a format string and a 'va_list'. * Takes a format string and a 'va_list'.
*/ */
WS_DLL_PUBLIC WS_DLL_PUBLIC
void ws_logv(enum ws_log_domain domain, enum ws_log_level level, void ws_logv(const char *domain, enum ws_log_level level,
const char *format, va_list ap); const char *format, va_list ap);
@ -152,7 +164,7 @@ void ws_logv(enum ws_log_domain domain, enum ws_log_level level,
* information. 'func' may be NULL. * information. 'func' may be NULL.
*/ */
WS_DLL_PUBLIC WS_DLL_PUBLIC
void ws_log_full(enum ws_log_domain domain, enum ws_log_level level, void ws_log_full(const char *domain, enum ws_log_level level,
const char *file, int line, const char *func, const char *file, int line, const char *func,
const char *format, ...) G_GNUC_PRINTF(6,7); const char *format, ...) G_GNUC_PRINTF(6,7);