wireshark/wsutil/wslog.c

1381 lines
39 KiB
C
Raw Normal View History

/*
2021-07-09 14:48:38 +00:00
* Copyright 2021, João Valverde <j@v6e.pt>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
2021-07-09 14:48:38 +00:00
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include "wslog.h"
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
#include <stdlib.h>
#include <string.h>
#include <errno.h>
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
#include <time.h>
/* Because ws_assert() dependes on ws_error() we do not use it
* here and fall back on assert() instead. */
#include <assert.h>
2021-06-12 11:41:50 +00:00
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef _WIN32
#include <process.h>
#include <windows.h>
#include <conio.h>
#endif
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
#include "file_util.h"
#include "time_util.h"
#include "to_str.h"
#include "strtoi.h"
#ifdef _WIN32
#include "console_win32.h"
#endif
2022-10-06 17:41:17 +00:00
#define ASSERT(expr) assert(expr)
/* Runtime log level. */
#define ENV_VAR_LEVEL "WIRESHARK_LOG_LEVEL"
/* Log domains enabled/disabled. */
#define ENV_VAR_DOMAIN "WIRESHARK_LOG_DOMAIN"
/* Alias "domain" and "domains". */
#define ENV_VAR_DOMAIN_S "WIRESHARK_LOG_DOMAINS"
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
/* Log level that generates a trap and aborts. Can be "critical"
* or "warning". */
#define ENV_VAR_FATAL "WIRESHARK_LOG_FATAL"
/* Log domains that are fatal. */
#define ENV_VAR_FATAL_DOMAIN "WIRESHARK_LOG_FATAL_DOMAIN"
/* Alias "domain" and "domains". */
#define ENV_VAR_FATAL_DOMAIN_S "WIRESHARK_LOG_FATAL_DOMAINS"
/* Domains that will produce debug output, regardless of log level or
* domain filter. */
#define ENV_VAR_DEBUG "WIRESHARK_LOG_DEBUG"
/* Domains that will produce noisy output, regardless of log level or
* domain filter. */
#define ENV_VAR_NOISY "WIRESHARK_LOG_NOISY"
#define DEFAULT_LOG_LEVEL LOG_LEVEL_MESSAGE
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
#define DEFAULT_PROGNAME "PID"
2021-06-19 00:57:09 +00:00
2021-06-19 21:03:31 +00:00
#define DOMAIN_UNDEFED(domain) ((domain) == NULL || *(domain) == '\0')
#define DOMAIN_DEFINED(domain) (!DOMAIN_UNDEFED(domain))
/*
* Note: I didn't measure it but I assume using a string array is faster than
* a GHashTable for small number N of domains.
*/
typedef struct {
char **domainv;
2021-12-28 23:41:35 +00:00
bool positive; /* positive or negative match */
enum ws_log_level min_level; /* for level filters */
2021-06-19 21:03:31 +00:00
} log_filter_t;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
/* If the module is not initialized by calling ws_log_init() all messages
* will be printed regardless of log level. This is a feature, not a bug. */
static enum ws_log_level current_log_level = LOG_LEVEL_NONE;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
2021-12-28 23:41:35 +00:00
static bool stdout_color_enabled = false;
2021-12-28 23:41:35 +00:00
static bool stderr_color_enabled = false;
/* Use stdout for levels "info" and below, for backward compatibility
* with GLib. */
2021-12-28 23:41:35 +00:00
static bool stdout_logging_enabled = false;
static const char *registered_progname = DEFAULT_PROGNAME;
2021-06-12 11:41:50 +00:00
/* List of domains to filter. */
2021-06-19 21:03:31 +00:00
static log_filter_t *domain_filter = NULL;
/* List of domains to output debug level unconditionally. */
2021-06-19 21:03:31 +00:00
static log_filter_t *debug_filter = NULL;
/* List of domains to output noisy level unconditionally. */
2021-06-19 21:03:31 +00:00
static log_filter_t *noisy_filter = NULL;
/* List of domains that are fatal. */
static log_filter_t *fatal_filter = NULL;
static ws_log_writer_cb *registered_log_writer = NULL;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
static void *registered_log_writer_data = NULL;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
static ws_log_writer_free_data_cb *registered_log_writer_data_free = NULL;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
static FILE *custom_log = NULL;
static enum ws_log_level fatal_log_level = LOG_LEVEL_ERROR;
2021-12-28 23:41:35 +00:00
static bool init_complete = false;
ws_log_console_open_pref ws_log_console_open = LOG_CONSOLE_OPEN_NEVER;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
static void print_err(void (*vcmdarg_err)(const char *, va_list ap),
int exit_failure,
const char *fmt, ...) G_GNUC_PRINTF(3,4);
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
static void ws_log_cleanup(void);
const char *ws_log_level_to_string(enum ws_log_level level)
{
switch (level) {
case LOG_LEVEL_NONE:
return "(zero)";
case LOG_LEVEL_ECHO:
return "ECHO";
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
case LOG_LEVEL_ERROR:
return "ERROR";
case LOG_LEVEL_CRITICAL:
return "CRITICAL";
case LOG_LEVEL_WARNING:
return "WARNING";
case LOG_LEVEL_MESSAGE:
return "MESSAGE";
case LOG_LEVEL_INFO:
return "INFO";
case LOG_LEVEL_DEBUG:
return "DEBUG";
case LOG_LEVEL_NOISY:
return "NOISY";
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
default:
return "(BOGUS LOG LEVEL)";
}
}
static enum ws_log_level string_to_log_level(const char *str_level)
{
if (!str_level)
return LOG_LEVEL_NONE;
if (g_ascii_strcasecmp(str_level, "noisy") == 0)
return LOG_LEVEL_NOISY;
else if (g_ascii_strcasecmp(str_level, "debug") == 0)
return LOG_LEVEL_DEBUG;
else if (g_ascii_strcasecmp(str_level, "info") == 0)
return LOG_LEVEL_INFO;
else if (g_ascii_strcasecmp(str_level, "message") == 0)
return LOG_LEVEL_MESSAGE;
else if (g_ascii_strcasecmp(str_level, "warning") == 0)
return LOG_LEVEL_WARNING;
else if (g_ascii_strcasecmp(str_level, "critical") == 0)
return LOG_LEVEL_CRITICAL;
else if (g_ascii_strcasecmp(str_level, "error") == 0)
return LOG_LEVEL_ERROR;
else if (g_ascii_strcasecmp(str_level, "echo") == 0)
return LOG_LEVEL_ECHO;
else
return LOG_LEVEL_NONE;
}
WS_RETNONNULL
static inline const char *domain_to_string(const char *domain)
{
return DOMAIN_UNDEFED(domain) ? "(none)" : domain;
}
2021-12-28 23:41:35 +00:00
static inline bool filter_contains(log_filter_t *filter,
const char *domain)
{
if (filter == NULL || DOMAIN_UNDEFED(domain))
2021-12-28 23:41:35 +00:00
return false;
for (char **domv = filter->domainv; *domv != NULL; domv++) {
2021-06-19 21:03:31 +00:00
if (g_ascii_strcasecmp(*domv, domain) == 0) {
2021-12-28 23:41:35 +00:00
return true;
}
}
2021-12-28 23:41:35 +00:00
return false;
}
2021-12-28 23:41:35 +00:00
static inline bool level_filter_matches(log_filter_t *filter,
2021-06-19 21:03:31 +00:00
const char *domain,
enum ws_log_level level,
2021-12-28 23:41:35 +00:00
bool *active_ptr)
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
{
if (filter == NULL || DOMAIN_UNDEFED(domain))
2021-12-28 23:41:35 +00:00
return false;
2021-06-29 14:27:04 +00:00
if (!filter_contains(filter, domain))
2021-12-28 23:41:35 +00:00
return false;
2021-06-19 21:03:31 +00:00
if (filter->positive) {
if (active_ptr)
*active_ptr = level >= filter->min_level;
2021-12-28 23:41:35 +00:00
return true;
2021-06-19 21:03:31 +00:00
}
2021-06-19 21:03:31 +00:00
/* negative match */
if (level <= filter->min_level) {
if (active_ptr)
2021-12-28 23:41:35 +00:00
*active_ptr = false;
return true;
2021-06-19 21:03:31 +00:00
}
2021-12-28 23:41:35 +00:00
return false;
2021-06-19 21:03:31 +00:00
}
2021-12-28 23:41:35 +00:00
bool ws_log_msg_is_active(const char *domain, enum ws_log_level level)
{
/*
* Higher numerical levels have higher priority. Critical and above
* are always enabled.
*/
if (level >= LOG_LEVEL_CRITICAL)
2021-12-28 23:41:35 +00:00
return true;
/*
* Check if the level has been configured as fatal.
*/
if (level >= fatal_log_level)
2021-12-28 23:41:35 +00:00
return true;
/*
* Check if the domain has been configured as fatal.
*/
if (DOMAIN_DEFINED(domain) && fatal_filter != NULL) {
if (filter_contains(fatal_filter, domain) && fatal_filter->positive) {
return true;
}
}
2021-06-19 21:03:31 +00:00
/*
* The debug/noisy filter overrides the other parameters.
*/
if (DOMAIN_DEFINED(domain)) {
2021-12-28 23:41:35 +00:00
bool active;
if (level_filter_matches(noisy_filter, domain, level, &active))
2021-06-19 21:03:31 +00:00
return active;
if (level_filter_matches(debug_filter, domain, level, &active))
2021-06-19 21:03:31 +00:00
return active;
}
/*
* If the priority is lower than the current minimum drop the
* message.
*/
if (level < current_log_level)
2021-12-28 23:41:35 +00:00
return false;
2021-06-19 21:03:31 +00:00
/*
* If we don't have domain filtering enabled we are done.
*/
if (domain_filter == NULL)
2021-12-28 23:41:35 +00:00
return true;
2021-06-19 21:03:31 +00:00
/*
* We have a filter but we don't use it with the undefined domain,
* pretty much every permanent call to ws_log should be using a
* chosen domain.
*/
if (DOMAIN_UNDEFED(domain))
2021-12-28 23:41:35 +00:00
return true;
2021-06-19 21:03:31 +00:00
/* Check if the domain filter matches. */
if (filter_contains(domain_filter, domain))
return domain_filter->positive;
2021-06-19 21:03:31 +00:00
/* We have a domain filter but it didn't match. */
return !domain_filter->positive;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
enum ws_log_level ws_log_get_level(void)
{
return current_log_level;
}
enum ws_log_level ws_log_set_level(enum ws_log_level level)
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
{
if (level <= LOG_LEVEL_NONE || level >= _LOG_LEVEL_LAST)
return LOG_LEVEL_NONE;
if (level > LOG_LEVEL_CRITICAL)
level = LOG_LEVEL_CRITICAL;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
current_log_level = level;
return current_log_level;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
enum ws_log_level ws_log_set_level_str(const char *str_level)
{
enum ws_log_level level;
level = string_to_log_level(str_level);
return ws_log_set_level(level);
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
static const char *opt_level = "--log-level";
static const char *opt_domain = "--log-domain";
/* Alias "domain" and "domains". */
static const char *opt_domain_s = "--log-domains";
static const char *opt_file = "--log-file";
static const char *opt_fatal = "--log-fatal";
static const char *opt_fatal_domain = "--log-fatal-domain";
/* Alias "domain" and "domains". */
static const char *opt_fatal_domain_s = "--log-fatal-domains";
static const char *opt_debug = "--log-debug";
static const char *opt_noisy = "--log-noisy";
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
static void print_err(void (*vcmdarg_err)(const char *, va_list ap),
int exit_failure,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (vcmdarg_err)
vcmdarg_err(fmt, ap);
else
vfprintf(stderr, fmt, ap);
va_end(ap);
if (exit_failure != LOG_ARGS_NOEXIT)
exit(exit_failure);
}
/*
* This tries to convert old log level preference to a wslog
* configuration. The string must start with "console.log.level:"
* It receives an argv for { '-o', 'console.log.level:nnn', ...} or
* { '-oconsole.log.level:nnn', ...}.
*/
static void
parse_console_compat_option(char *argv[],
void (*vcmdarg_err)(const char *, va_list ap),
int exit_failure)
{
const char *mask_str;
2021-12-28 23:41:35 +00:00
uint32_t mask;
enum ws_log_level level;
2022-10-06 17:41:17 +00:00
ASSERT(argv != NULL);
if (argv[0] == NULL)
return;
if (strcmp(argv[0], "-o") == 0) {
if (argv[1] == NULL ||
!g_str_has_prefix(argv[1], "console.log.level:")) {
/* Not what we were looking for. */
return;
}
mask_str = argv[1] + strlen("console.log.level:");
}
else if (g_str_has_prefix(argv[0], "-oconsole.log.level:")) {
mask_str = argv[0] + strlen("-oconsole.log.level:");
}
else {
/* Not what we were looking for. */
return;
}
print_err(vcmdarg_err, LOG_ARGS_NOEXIT,
"Option 'console.log.level' is deprecated, consult '--help' "
"for diagnostic message options.");
if (*mask_str == '\0') {
print_err(vcmdarg_err, exit_failure,
"Missing value to 'console.log.level' option.");
return;
}
if (!ws_basestrtou32(mask_str, NULL, &mask, 10)) {
print_err(vcmdarg_err, exit_failure,
"%s is not a valid decimal number.", mask_str);
return;
}
/*
* The lowest priority bit in the mask defines the level.
*/
if (mask & G_LOG_LEVEL_DEBUG)
level = LOG_LEVEL_DEBUG;
else if (mask & G_LOG_LEVEL_INFO)
level = LOG_LEVEL_INFO;
else if (mask & G_LOG_LEVEL_MESSAGE)
level = LOG_LEVEL_MESSAGE;
else if (mask & G_LOG_LEVEL_WARNING)
level = LOG_LEVEL_WARNING;
else if (mask & G_LOG_LEVEL_CRITICAL)
level = LOG_LEVEL_CRITICAL;
else if (mask & G_LOG_LEVEL_ERROR)
level = LOG_LEVEL_ERROR;
else
level = LOG_LEVEL_NONE;
if (level == LOG_LEVEL_NONE) {
/* Some values (like zero) might not contain any meaningful bits.
* Throwing an error in that case seems appropriate. */
print_err(vcmdarg_err, exit_failure,
"Value %s is not a valid log mask.", mask_str);
return;
}
ws_log_set_level(level);
}
/* Match "arg_name=value" or "arg_name value" to opt_name. */
static bool optequal(const char *arg, const char *opt)
{
2022-10-06 17:41:17 +00:00
ASSERT(arg);
ASSERT(opt);
#define ARGEND(arg) (*(arg) == '\0' || *(arg) == ' ' || *(arg) == '=')
while (!ARGEND(arg) && *opt != '\0') {
if (*arg != *opt) {
return false;
}
arg += 1;
opt += 1;
}
if (ARGEND(arg) && *opt == '\0') {
return true;
}
return false;
}
int ws_log_parse_args(int *argc_ptr, char *argv[],
void (*vcmdarg_err)(const char *, va_list ap),
int exit_failure)
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
{
char **ptr = argv;
int count = *argc_ptr;
int ret = 0;
size_t optlen;
const char *option, *value;
int extra;
if (argc_ptr == NULL || argv == NULL)
return -1;
2022-10-06 17:41:17 +00:00
/* Assert ws_log_init() was called before ws_log_parse_args(). */
ASSERT(init_complete);
/* Configure from command line. */
while (*ptr != NULL) {
if (optequal(*ptr, opt_level)) {
option = opt_level;
optlen = strlen(opt_level);
}
else if (optequal(*ptr, opt_domain)) {
option = opt_domain;
optlen = strlen(opt_domain);
}
else if (optequal(*ptr, opt_domain_s)) {
option = opt_domain; /* Alias */
optlen = strlen(opt_domain_s);
}
else if (optequal(*ptr, opt_fatal_domain)) {
option = opt_fatal_domain;
optlen = strlen(opt_fatal_domain);
}
else if (optequal(*ptr, opt_fatal_domain_s)) {
option = opt_fatal_domain; /* Alias */
optlen = strlen(opt_fatal_domain_s);
}
else if (optequal(*ptr, opt_file)) {
option = opt_file;
optlen = strlen(opt_file);
}
else if (optequal(*ptr, opt_fatal)) {
option = opt_fatal;
optlen = strlen(opt_fatal);
}
else if (optequal(*ptr, opt_debug)) {
option = opt_debug;
optlen = strlen(opt_debug);
}
else if (optequal(*ptr, opt_noisy)) {
option = opt_noisy;
optlen = strlen(opt_noisy);
}
else {
/* Check is we have the old '-o console.log.level' flag,
* or '-oconsole.log.level', for backward compatibility.
* Then if we do ignore it after processing and let the
* preferences module handle it later. */
if (*(*ptr + 0) == '-' && *(*ptr + 1) == 'o') {
parse_console_compat_option(ptr, vcmdarg_err, exit_failure);
}
ptr += 1;
count -= 1;
continue;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
value = *ptr + optlen;
/* Two possibilities:
* --<option> <value>
* or
* --<option>=<value>
*/
if (value[0] == '\0') {
/* value is separated with blank space */
value = *(ptr + 1);
extra = 1;
if (value == NULL || !*value || *value == '-') {
2021-06-14 18:10:57 +00:00
/* If the option value after the blank starts with '-' assume
* it is another option. */
print_err(vcmdarg_err, exit_failure,
"Option \"%s\" requires a value.\n", *ptr);
option = NULL;
extra = 0;
2021-06-14 18:10:57 +00:00
ret += 1;
}
}
else if (value[0] == '=') {
/* value is after equals */
value += 1;
extra = 0;
}
else {
2021-06-14 18:10:57 +00:00
/* Option isn't known. */
ptr += 1;
count -= 1;
continue;
}
if (option == opt_level) {
if (ws_log_set_level_str(value) == LOG_LEVEL_NONE) {
print_err(vcmdarg_err, exit_failure,
"Invalid log level \"%s\".\n", value);
ret += 1;
}
}
else if (option == opt_domain) {
ws_log_set_domain_filter(value);
}
else if (option == opt_fatal_domain) {
ws_log_set_fatal_domain_filter(value);
}
else if (value && option == opt_file) {
FILE *fp = ws_fopen(value, "w");
if (fp == NULL) {
print_err(vcmdarg_err, exit_failure,
"Error opening file '%s' for writing: %s.\n",
value, g_strerror(errno));
ret += 1;
}
else {
ws_log_add_custom_file(fp);
}
}
else if (option == opt_fatal) {
if (ws_log_set_fatal_level_str(value) == LOG_LEVEL_NONE) {
print_err(vcmdarg_err, exit_failure,
"Fatal log level must be \"critical\" or "
"\"warning\", not \"%s\".\n", value);
ret += 1;
}
}
else if (option == opt_debug) {
ws_log_set_debug_filter(value);
}
else if (option == opt_noisy) {
ws_log_set_noisy_filter(value);
}
2021-06-14 18:10:57 +00:00
else {
/* Option value missing or invalid, do nothing. */
}
/*
* We found a log option. We will remove it from
* the argv by moving up the other strings in the array. This is
* so that it doesn't generate an unrecognized option
* error further along in the initialization process.
*/
/* Include the terminating NULL in the memmove. */
memmove(ptr, ptr + 1 + extra, (count - extra) * sizeof(*ptr));
/* No need to increment ptr here. */
count -= (1 + extra);
*argc_ptr -= (1 + extra);
}
return ret;
}
2021-06-19 21:03:31 +00:00
static void free_log_filter(log_filter_t **filter_ptr)
{
if (filter_ptr == NULL || *filter_ptr == NULL)
2021-06-19 21:03:31 +00:00
return;
g_strfreev((*filter_ptr)->domainv);
g_free(*filter_ptr);
*filter_ptr = NULL;
}
static void tokenize_filter_str(log_filter_t **filter_ptr,
const char *str_filter,
enum ws_log_level min_level)
2021-06-19 21:03:31 +00:00
{
const char *sep = ",;";
2021-12-28 23:41:35 +00:00
bool negated = false;
2021-06-19 21:03:31 +00:00
log_filter_t *filter;
2022-10-06 17:41:17 +00:00
ASSERT(filter_ptr);
ASSERT(*filter_ptr == NULL);
2021-06-19 21:03:31 +00:00
if (str_filter == NULL)
return;
2021-06-19 21:03:31 +00:00
if (str_filter[0] == '!') {
2021-12-28 23:41:35 +00:00
negated = true;
2021-06-19 21:03:31 +00:00
str_filter += 1;
}
2021-06-19 21:03:31 +00:00
if (*str_filter == '\0')
return;
filter = g_new(log_filter_t, 1);
filter->domainv = g_strsplit_set(str_filter, sep, -1);
2021-06-19 21:03:31 +00:00
filter->positive = !negated;
filter->min_level = min_level;
2021-06-19 21:03:31 +00:00
*filter_ptr = filter;
}
void ws_log_set_domain_filter(const char *str_filter)
{
2021-06-19 21:03:31 +00:00
free_log_filter(&domain_filter);
tokenize_filter_str(&domain_filter, str_filter, LOG_LEVEL_NONE);
}
void ws_log_set_fatal_domain_filter(const char *str_filter)
{
free_log_filter(&fatal_filter);
tokenize_filter_str(&fatal_filter, str_filter, LOG_LEVEL_NONE);
}
void ws_log_set_debug_filter(const char *str_filter)
{
2021-06-19 21:03:31 +00:00
free_log_filter(&debug_filter);
tokenize_filter_str(&debug_filter, str_filter, LOG_LEVEL_DEBUG);
}
void ws_log_set_noisy_filter(const char *str_filter)
{
2021-06-19 21:03:31 +00:00
free_log_filter(&noisy_filter);
tokenize_filter_str(&noisy_filter, str_filter, LOG_LEVEL_NOISY);
}
enum ws_log_level ws_log_set_fatal_level(enum ws_log_level level)
{
if (level <= LOG_LEVEL_NONE || level >= _LOG_LEVEL_LAST)
return LOG_LEVEL_NONE;
if (level > LOG_LEVEL_ERROR)
level = LOG_LEVEL_ERROR;
if (level < LOG_LEVEL_WARNING)
level = LOG_LEVEL_WARNING;
fatal_log_level = level;
return fatal_log_level;
}
enum ws_log_level ws_log_set_fatal_level_str(const char *str_level)
{
enum ws_log_level level;
level = string_to_log_level(str_level);
return ws_log_set_fatal_level(level);
}
void ws_log_set_writer(ws_log_writer_cb *writer)
{
if (registered_log_writer_data_free)
registered_log_writer_data_free(registered_log_writer_data);
registered_log_writer = writer;
registered_log_writer_data = NULL;
registered_log_writer_data_free = NULL;
}
void ws_log_set_writer_with_data(ws_log_writer_cb *writer,
void *user_data,
ws_log_writer_free_data_cb *free_user_data)
{
if (registered_log_writer_data_free)
registered_log_writer_data_free(registered_log_writer_data);
registered_log_writer = writer;
registered_log_writer_data = user_data;
registered_log_writer_data_free = free_user_data;
}
static void glib_log_handler(const char *domain, GLogLevelFlags flags,
const char *message, gpointer user_data _U_)
{
enum ws_log_level level;
/*
* The highest priority bit in the mask defines the level. We
* ignore the GLib fatal log level mask and use our own fatal
* log level setting instead.
*/
if (flags & G_LOG_LEVEL_ERROR)
level = LOG_LEVEL_ERROR;
else if (flags & G_LOG_LEVEL_CRITICAL)
level = LOG_LEVEL_CRITICAL;
else if (flags & G_LOG_LEVEL_WARNING)
level = LOG_LEVEL_WARNING;
else if (flags & G_LOG_LEVEL_MESSAGE)
level = LOG_LEVEL_MESSAGE;
else if (flags & G_LOG_LEVEL_INFO)
level = LOG_LEVEL_INFO;
else if (flags & G_LOG_LEVEL_DEBUG)
level = LOG_LEVEL_DEBUG;
else
level = LOG_LEVEL_NONE; /* Should not happen. */
ws_log(domain, level, "%s", message);
}
#ifdef _WIN32
2023-01-13 16:24:20 +00:00
static void load_registry(void)
{
LONG lResult;
DWORD ptype;
DWORD data;
DWORD data_size = sizeof(DWORD);
lResult = RegGetValueA(HKEY_CURRENT_USER,
"Software\\Wireshark",
LOG_HKCU_CONSOLE_OPEN,
RRF_RT_REG_DWORD,
&ptype,
&data,
&data_size);
if (lResult != ERROR_SUCCESS || ptype != REG_DWORD) {
return;
}
ws_log_console_open = (ws_log_console_open_pref)data;
}
#endif
/*
* We can't write to stderr in ws_log_init() because dumpcap uses stderr
2021-06-26 02:14:08 +00:00
* to communicate with the parent and it will block. We have to use
* vcmdarg_err to report errors.
*/
void ws_log_init(const char *progname,
void (*vcmdarg_err)(const char *, va_list ap))
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
{
const char *env;
int fd;
if (progname != NULL) {
registered_progname = progname;
g_set_prgname(progname);
}
2021-06-12 11:41:50 +00:00
current_log_level = DEFAULT_LOG_LEVEL;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
if ((fd = fileno(stdout)) >= 0)
stdout_color_enabled = g_log_writer_supports_color(fd);
if ((fd = fileno(stderr)) >= 0)
stderr_color_enabled = g_log_writer_supports_color(fd);
/* Set the GLib log handler for the default domain. */
g_log_set_handler(NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL,
glib_log_handler, NULL);
/* Set the GLib log handler for GLib itself. */
g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL,
glib_log_handler, NULL);
#ifdef _WIN32
2023-01-13 16:24:20 +00:00
load_registry();
/* if the user wants a console to be always there, well, we should open one for him */
if (ws_log_console_open == LOG_CONSOLE_OPEN_ALWAYS) {
create_console();
}
#endif
atexit(ws_log_cleanup);
/* Configure from environment. */
env = g_getenv(ENV_VAR_LEVEL);
if (env != NULL) {
if (ws_log_set_level_str(env) == LOG_LEVEL_NONE) {
print_err(vcmdarg_err, LOG_ARGS_NOEXIT,
"Ignoring invalid environment value %s=\"%s\"",
ENV_VAR_LEVEL, env);
}
}
env = g_getenv(ENV_VAR_FATAL);
if (env != NULL) {
if (ws_log_set_fatal_level_str(env) == LOG_LEVEL_NONE) {
print_err(vcmdarg_err, LOG_ARGS_NOEXIT,
"Ignoring invalid environment value %s=\"%s\"",
ENV_VAR_FATAL, env);
}
}
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
/* Alias "domain" and "domains". The plural form wins. */
if ((env = g_getenv(ENV_VAR_DOMAIN_S)) != NULL)
ws_log_set_domain_filter(env);
else if ((env = g_getenv(ENV_VAR_DOMAIN)) != NULL)
ws_log_set_domain_filter(env);
/* Alias "domain" and "domains". The plural form wins. */
if ((env = g_getenv(ENV_VAR_FATAL_DOMAIN_S)) != NULL)
ws_log_set_fatal_domain_filter(env);
else if ((env = g_getenv(ENV_VAR_FATAL_DOMAIN)) != NULL)
ws_log_set_fatal_domain_filter(env);
env = g_getenv(ENV_VAR_DEBUG);
if (env != NULL)
ws_log_set_debug_filter(env);
env = g_getenv(ENV_VAR_NOISY);
if (env != NULL)
ws_log_set_noisy_filter(env);
2021-12-28 23:41:35 +00:00
init_complete = true;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
void ws_log_init_with_writer(const char *progname,
ws_log_writer_cb *writer,
void (*vcmdarg_err)(const char *, va_list ap))
{
registered_log_writer = writer;
ws_log_init(progname, vcmdarg_err);
}
void ws_log_init_with_writer_and_data(const char *progname,
ws_log_writer_cb *writer,
void *user_data,
ws_log_writer_free_data_cb *free_user_data,
void (*vcmdarg_err)(const char *, va_list ap))
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
{
registered_log_writer_data = user_data;
registered_log_writer_data_free = free_user_data;
ws_log_init_with_writer(progname, writer, vcmdarg_err);
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
2021-06-20 19:29:46 +00:00
#define MAGENTA "\033[35m"
#define BLUE "\033[34m"
#define CYAN "\033[36m"
#define GREEN "\033[32m"
#define YELLOW "\033[33m"
#define RED "\033[31m"
#define RESET "\033[0m"
2021-12-28 23:41:35 +00:00
static inline const char *level_color_on(bool enable, enum ws_log_level level)
2021-06-14 21:29:15 +00:00
{
2021-06-20 19:29:46 +00:00
if (!enable)
return "";
switch (level) {
case LOG_LEVEL_NOISY:
case LOG_LEVEL_DEBUG:
return GREEN;
case LOG_LEVEL_INFO:
case LOG_LEVEL_MESSAGE:
return CYAN;
case LOG_LEVEL_WARNING:
return YELLOW;
case LOG_LEVEL_CRITICAL:
return MAGENTA;
case LOG_LEVEL_ERROR:
return RED;
case LOG_LEVEL_ECHO:
return YELLOW;
default:
break;
}
return "";
2021-06-14 21:29:15 +00:00
}
2021-12-28 23:41:35 +00:00
static inline const char *color_off(bool enable)
2021-06-14 21:29:15 +00:00
{
2021-06-20 19:29:46 +00:00
return enable ? RESET : "";
2021-06-14 21:29:15 +00:00
}
#define NANOSECS_IN_MICROSEC 1000
/*
* We must not call anything that might log a message
* in the log handler context (GLib might log a message if we register
* our own handler for the GLib domain).
*/
2021-12-28 23:41:35 +00:00
static void log_write_do_work(FILE *fp, bool use_color,
struct tm *when, long nanosecs,
const char *domain, enum ws_log_level level,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
const char *user_format, va_list user_ap)
{
if (!init_complete)
fputs(" ** (noinit)", fp);
/* Process */
fprintf(fp, " ** (%s:%ld) ", registered_progname, (long)getpid());
/* Timestamp */
if (when != NULL && nanosecs >= 0)
fprintf(fp, "%02d:%02d:%02d.%06ld ",
when->tm_hour, when->tm_min, when->tm_sec,
nanosecs / NANOSECS_IN_MICROSEC);
else if (when != NULL)
fprintf(fp, "%02d:%02d:%02d ",
when->tm_hour, when->tm_min, when->tm_sec);
else
fputs("(notime) ", fp);
/* Domain/level */
fprintf(fp, "[%s %s%s%s] ", domain_to_string(domain),
level_color_on(use_color, level),
ws_log_level_to_string(level),
color_off(use_color));
2021-06-20 19:29:46 +00:00
/* File/line */
if (file != NULL && line >= 0)
2022-01-04 01:23:10 +00:00
fprintf(fp, "%s:%ld ", file, line);
else if (file != NULL)
2021-06-20 19:29:46 +00:00
fprintf(fp, "%s ", file);
/* Any formatting changes here need to be synced with ui/capture.c:capture_input_closed. */
2021-06-20 19:29:46 +00:00
fputs("-- ", fp);
/* Function name */
if (func != NULL)
2021-06-20 19:29:46 +00:00
fprintf(fp, "%s(): ", func);
2021-06-20 19:29:46 +00:00
/* User message */
vfprintf(fp, user_format, user_ap);
fputc('\n', fp);
fflush(fp);
}
static inline struct tm *get_localtime(time_t unix_time, struct tm **cookie)
{
if (unix_time == (time_t)-1)
return NULL;
if (cookie && *cookie)
return *cookie;
struct tm *when = localtime(&unix_time);
if (cookie)
*cookie = when;
return when;
}
static inline FILE *console_file(enum ws_log_level level)
{
if (level <= LOG_LEVEL_INFO && stdout_logging_enabled)
return stdout;
return stderr;
}
static inline bool console_color_enabled(enum ws_log_level level)
{
if (level <= LOG_LEVEL_INFO && stdout_logging_enabled)
return stdout_color_enabled;
return stderr_color_enabled;
}
/*
* We must not call anything that might log a message
* in the log handler context (GLib might log a message if we register
* our own handler for the GLib domain).
*/
static void log_write_dispatch(const char *domain, enum ws_log_level level,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
const char *user_format, va_list user_ap)
{
struct timespec tstamp;
struct tm *cookie = NULL;
bool fatal_event = false;
if (level >= fatal_log_level && level != LOG_LEVEL_ECHO) {
fatal_event = true;
}
else if (fatal_filter != NULL) {
if (filter_contains(fatal_filter, domain) && fatal_filter->positive) {
fatal_event = true;
}
}
ws_clock_get_realtime(&tstamp);
#ifdef _WIN32
if (fatal_event || ws_log_console_open != LOG_CONSOLE_OPEN_NEVER) {
/* the user wants a console or the application will terminate immediately */
create_console();
}
#endif /* _WIN32 */
if (custom_log) {
va_list user_ap_copy;
2021-12-12 11:34:48 +00:00
va_copy(user_ap_copy, user_ap);
2021-12-28 23:41:35 +00:00
log_write_do_work(custom_log, false,
get_localtime(tstamp.tv_sec, &cookie),
tstamp.tv_nsec,
domain, level, file, line, func,
user_format, user_ap_copy);
va_end(user_ap_copy);
}
if (registered_log_writer) {
registered_log_writer(domain, level, tstamp, file, line, func,
user_format, user_ap, registered_log_writer_data);
}
else {
log_write_do_work(console_file(level), console_color_enabled(level),
get_localtime(tstamp.tv_sec, &cookie),
tstamp.tv_nsec,
domain, level, file, line, func,
user_format, user_ap);
}
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
#ifdef _WIN32
if (fatal_event) {
/* wait for a key press before the following error handler will terminate the program
this way the user at least can read the error message */
printf("\n\nPress any key to exit\n");
_getch();
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
#endif /* _WIN32 */
if (fatal_event) {
abort();
}
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
void ws_logv(const char *domain, enum ws_log_level level,
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
const char *format, va_list ap)
{
2021-06-29 14:27:04 +00:00
if (!ws_log_msg_is_active(domain, level))
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
return;
log_write_dispatch(domain, level, NULL, -1, NULL, format, ap);
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
2021-06-14 23:01:25 +00:00
void ws_logv_full(const char *domain, enum ws_log_level level,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
2021-06-14 23:01:25 +00:00
const char *format, va_list ap)
{
2021-06-29 14:27:04 +00:00
if (!ws_log_msg_is_active(domain, level))
2021-06-14 23:01:25 +00:00
return;
log_write_dispatch(domain, level, file, line, func, format, ap);
}
void ws_log(const char *domain, enum ws_log_level level,
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
const char *format, ...)
{
2021-06-29 14:27:04 +00:00
if (!ws_log_msg_is_active(domain, level))
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
return;
va_list ap;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
va_start(ap, format);
log_write_dispatch(domain, level, NULL, -1, NULL, format, ap);
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
va_end(ap);
}
void ws_log_full(const char *domain, enum ws_log_level level,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
const char *format, ...)
{
2021-06-29 14:27:04 +00:00
if (!ws_log_msg_is_active(domain, level))
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
return;
va_list ap;
va_start(ap, format);
log_write_dispatch(domain, level, file, line, func, format, ap);
va_end(ap);
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
2022-01-04 12:20:21 +00:00
void ws_log_fatal_full(const char *domain, enum ws_log_level level,
const char *file, long line, const char *func,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
log_write_dispatch(domain, level, file, line, func, format, ap);
va_end(ap);
abort();
}
void ws_log_write_always_full(const char *domain, enum ws_log_level level,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
log_write_dispatch(domain, level, file, line, func, format, ap);
va_end(ap);
}
static void
append_trailer(const char *src, size_t src_length, wmem_strbuf_t *display, wmem_strbuf_t *underline)
{
gunichar ch;
size_t hex_len;
while (src_length > 0) {
ch = g_utf8_get_char_validated(src, src_length);
if (ch == (gunichar)-1 || ch == (gunichar)-2) {
wmem_strbuf_append_hex(display, *src);
wmem_strbuf_append_c_count(underline, '^', 4);
src += 1;
src_length -= 1;
}
else {
if (g_unichar_isprint(ch)) {
wmem_strbuf_append_unichar(display, ch);
wmem_strbuf_append_c_count(underline, ' ', 1);
}
else {
hex_len = wmem_strbuf_append_hex_unichar(display, ch);
wmem_strbuf_append_c_count(underline, ' ', hex_len);
}
const char *tmp = g_utf8_next_char(src);
src_length -= tmp - src;
src = tmp;
}
}
}
static char *
make_utf8_display(const char *src, size_t src_length, size_t good_length)
{
wmem_strbuf_t *display;
wmem_strbuf_t *underline;
2022-10-15 09:11:00 +00:00
gunichar ch;
size_t hex_len;
display = wmem_strbuf_create(NULL);
underline = wmem_strbuf_create(NULL);
2022-10-15 09:11:00 +00:00
for (const char *s = src; s < src + good_length; s = g_utf8_next_char(s)) {
ch = g_utf8_get_char(s);
if (g_unichar_isprint(ch)) {
wmem_strbuf_append_unichar(display, ch);
wmem_strbuf_append_c(underline, ' ');
}
2022-10-15 09:11:00 +00:00
else {
hex_len = wmem_strbuf_append_hex_unichar(display, ch);
wmem_strbuf_append_c_count(underline, ' ', hex_len);
2022-10-15 09:11:00 +00:00
}
}
2022-10-15 09:11:00 +00:00
append_trailer(&src[good_length], src_length - good_length, display, underline);
wmem_strbuf_append_c(display, '\n');
wmem_strbuf_append(display, underline->str);
wmem_strbuf_destroy(underline);
return wmem_strbuf_finalize(display);
}
void ws_log_utf8_full(const char *domain, enum ws_log_level level,
const char *file, long line, const char *func,
const char *string, ssize_t _length, const char *endptr)
{
if (!ws_log_msg_is_active(domain, level))
return;
char *display;
size_t length;
size_t good_length;
if (_length < 0)
length = strlen(string);
else
length = _length;
if (endptr == NULL || endptr < string) {
/* Find the pointer to the first invalid byte. */
if (g_utf8_validate(string, length, &endptr)) {
/* Valid string - should not happen. */
return;
}
}
good_length = endptr - string;
display = make_utf8_display(string, length, good_length);
ws_log_write_always_full(domain, level, file, line, func,
"Invalid UTF-8 at address %p offset %zu (length = %zu):\n%s",
string, good_length, length, display);
g_free(display);
}
void ws_log_buffer_full(const char *domain, enum ws_log_level level,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
2021-12-28 23:41:35 +00:00
const uint8_t *ptr, size_t size, size_t max_bytes_len,
const char *msg)
{
if (!ws_log_msg_is_active(domain, level))
return;
char *bufstr = bytes_to_str_maxlen(NULL, ptr, size, max_bytes_len);
if (G_UNLIKELY(msg == NULL))
ws_log_write_always_full(domain, level, file, line, func,
"<buffer:%p>: %s (%zu bytes)",
ptr, bufstr, size);
else
ws_log_write_always_full(domain, level, file, line, func,
"%s: %s (%zu bytes)",
msg, bufstr, size);
wmem_free(NULL, bufstr);
}
void ws_log_file_writer(FILE *fp, const char *domain, enum ws_log_level level,
struct timespec timestamp,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
const char *user_format, va_list user_ap)
{
2021-12-28 23:41:35 +00:00
log_write_do_work(fp, false,
get_localtime(timestamp.tv_sec, NULL),
timestamp.tv_nsec,
domain, level, file, line, func,
user_format, user_ap);
}
void ws_log_console_writer(const char *domain, enum ws_log_level level,
struct timespec timestamp,
2022-01-04 01:23:10 +00:00
const char *file, long line, const char *func,
const char *user_format, va_list user_ap)
{
log_write_do_work(console_file(level), console_color_enabled(level),
get_localtime(timestamp.tv_sec, NULL),
timestamp.tv_nsec,
domain, level, file, line, func,
user_format, user_ap);
}
WS_DLL_PUBLIC
void ws_log_console_writer_set_use_stdout(bool use_stdout)
{
stdout_logging_enabled = use_stdout;
}
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
static void ws_log_cleanup(void)
{
if (registered_log_writer_data_free) {
registered_log_writer_data_free(registered_log_writer_data);
registered_log_writer_data = NULL;
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
if (custom_log) {
fclose(custom_log);
custom_log = NULL;
}
2021-06-19 21:03:31 +00:00
free_log_filter(&domain_filter);
free_log_filter(&debug_filter);
free_log_filter(&noisy_filter);
2022-10-04 09:56:40 +00:00
free_log_filter(&fatal_filter);
Refactor our logging and extend the wslog API Experience has shown that: 1. The current logging methods are not very reliable or practical. A logging bitmask makes little sense as the user-facing interface (who would want debug but not crtical messages for example?); it's computer-friendly and user-unfriendly. More importantly the console log level preference is initialized too late in the startup process to be used for the logging subsystem and that fact raises a number of annoying and hard-to-fix usability issues. 2. Coding around G_MESSAGES_DEBUG to comply with our log level mask and not clobber the user's settings or not create unexpected log misses is unworkable and generally follows the principle of most surprise. The fact that G_MESSAGES_DEBUG="all" can leak to other programs using GLib is also annoying. 3. The non-structured GLib logging API is very opinionated and lacks configurability beyond replacing the log handler. 4. Windows GUI has some special code to attach to a console, but it would be nice to abstract away the rest under a single interface. 5. Using this logger seems to be noticeably faster. Deprecate the console log level preference and extend our API to implement a log handler in wsutil/wslog.h to provide easy-to-use, flexible and dependable logging during all execution phases. Log levels have a hierarchy, from most verbose to least verbose (debug to error). When a given level is set everything above that is also enabled. The log level can be set with an environment variable or a command line option (parsed as soon as possible but still later than the environment). The default log level is "message". Dissector logging is not included because it is not clear what log domain they should use. An explosion to thousands of domains is not desirable and putting everything in a single domain is probably too coarse and noisy. For now I think it makes sense to let them do their own thing using g_log_default_handler() and continue using the G_MESSAGES_DEBUG mechanism with specific domains for each individual dissector. In the future a mechanism may be added to selectively enable these domains at runtime while trying to avoid the problems introduced by G_MESSAGES_DEBUG.
2021-06-08 01:46:52 +00:00
}
void ws_log_add_custom_file(FILE *fp)
{
if (custom_log != NULL) {
fclose(custom_log);
}
custom_log = fp;
}
2021-06-15 21:50:46 +00:00
#define USAGE_LEVEL \
"sets the active log level (\"critical\", \"warning\", etc.)"
#define USAGE_FATAL \
"sets level to abort the program (\"critical\" or \"warning\")"
#define USAGE_DOMAINS \
2022-10-04 10:15:42 +00:00
"comma-separated list of the active log domains"
#define USAGE_FATAL_DOMAINS \
"list of domains that cause the program to abort"
#define USAGE_DEBUG \
2022-10-04 10:15:42 +00:00
"list of domains with \"debug\" level"
#define USAGE_NOISY \
2022-10-04 10:15:42 +00:00
"list of domains with \"noisy\" level"
#define USAGE_FILE \
"file to output messages to (in addition to stderr)"
2021-06-15 21:50:46 +00:00
void ws_log_print_usage(FILE *fp)
{
fprintf(fp, "Diagnostic output:\n");
fprintf(fp, " --log-level <level> " USAGE_LEVEL "\n");
fprintf(fp, " --log-fatal <level> " USAGE_FATAL "\n");
fprintf(fp, " --log-domains <[!]list> " USAGE_DOMAINS "\n");
2022-10-04 10:15:42 +00:00
fprintf(fp, " --log-fatal-domains <list>\n");
fprintf(fp, " " USAGE_FATAL_DOMAINS "\n");
fprintf(fp, " --log-debug <[!]list> " USAGE_DEBUG "\n");
fprintf(fp, " --log-noisy <[!]list> " USAGE_NOISY "\n");
fprintf(fp, " --log-file <path> " USAGE_FILE "\n");
2021-06-15 21:50:46 +00:00
}