mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-06 02:28:02 +02:00
log: allow dynamic log levels for WpLogTopic
Change design of WpLogTopic so that it allows for changing their log levels at runtime. Add wp_log_topic_register/unregister functions to track lifetime of the topics. Auto-register statically defined log topics. Make the topic registration threadsafe, in case it is done from constructors that run in a different thread than main thread.
This commit is contained in:
parent
2ec202dfa1
commit
7c28c226b8
2 changed files with 154 additions and 65 deletions
186
lib/wp/log.c
186
lib/wp/log.c
|
|
@ -188,12 +188,15 @@ static struct {
|
|||
gint global_log_level;
|
||||
GLogLevelFlags global_log_level_flags;
|
||||
struct log_topic_pattern *patterns;
|
||||
GPtrArray *log_topics;
|
||||
GMutex log_topics_lock;
|
||||
} log_state = {
|
||||
.use_color = FALSE,
|
||||
.output_is_journal = FALSE,
|
||||
.global_log_level = 4 /* MESSAGE */,
|
||||
.global_log_level_flags = G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR,
|
||||
.patterns = NULL,
|
||||
.log_topics = NULL,
|
||||
};
|
||||
|
||||
/* reference: https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit */
|
||||
|
|
@ -260,6 +263,8 @@ level_index_from_flags (GLogLevelFlags log_level)
|
|||
static G_GNUC_CONST inline GLogLevelFlags
|
||||
level_index_to_flag (gint lvl_index)
|
||||
{
|
||||
if (lvl_index < 0 || lvl_index >= (gint) G_N_ELEMENTS (log_level_info))
|
||||
return 0;
|
||||
return log_level_info [lvl_index].log_level_flags;
|
||||
}
|
||||
|
||||
|
|
@ -300,6 +305,8 @@ level_index_from_spa (gint spa_lvl, gboolean warn_to_notice)
|
|||
static G_GNUC_CONST inline gint
|
||||
level_index_to_spa (gint lvl_index)
|
||||
{
|
||||
if (lvl_index < 0 || lvl_index >= (gint) G_N_ELEMENTS (log_level_info))
|
||||
return 0;
|
||||
return log_level_info [lvl_index].spa_level;
|
||||
}
|
||||
|
||||
|
|
@ -325,6 +332,74 @@ level_index_from_string (const char *str, gint *lvl)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
find_topic_log_level (const gchar *log_topic, bool *has_custom_level)
|
||||
{
|
||||
struct log_topic_pattern *pttrn = log_state.patterns;
|
||||
guint len;
|
||||
g_autofree gchar *reverse_topic = NULL;
|
||||
gint log_level = log_state.global_log_level;
|
||||
|
||||
/* reverse string and length required for pattern match */
|
||||
len = strlen (log_topic);
|
||||
reverse_topic = g_strreverse (g_strndup (log_topic, len));
|
||||
|
||||
while (pttrn && pttrn->spec &&
|
||||
!g_pattern_match (pttrn->spec, len, log_topic, reverse_topic))
|
||||
pttrn++;
|
||||
|
||||
if (pttrn && pttrn->spec) {
|
||||
if (has_custom_level)
|
||||
*has_custom_level = true;
|
||||
log_level = pttrn->log_level;
|
||||
} else if (has_custom_level) {
|
||||
*has_custom_level = false;
|
||||
}
|
||||
|
||||
return log_level;
|
||||
}
|
||||
|
||||
static void
|
||||
log_topic_update_level (WpLogTopic *topic)
|
||||
{
|
||||
gint log_level = find_topic_log_level (topic->topic_name, NULL);
|
||||
gint flags = topic->flags & ~WP_LOG_TOPIC_LEVEL_MASK;
|
||||
|
||||
flags |= level_index_to_full_flags (log_level);
|
||||
|
||||
topic->flags = flags;
|
||||
}
|
||||
|
||||
static void
|
||||
update_log_topic_levels (void)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_mutex_lock (&log_state.log_topics_lock);
|
||||
|
||||
if (log_state.log_topics)
|
||||
for (i = 0; i < log_state.log_topics->len; ++i)
|
||||
log_topic_update_level (g_ptr_array_index (log_state.log_topics, i));
|
||||
|
||||
g_mutex_unlock (&log_state.log_topics_lock);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wp_log_set_global_level (const gchar *log_level)
|
||||
{
|
||||
gint level;
|
||||
if (level_index_from_string (log_level, &level)) {
|
||||
log_state.global_log_level = level;
|
||||
log_state.global_log_level_flags = level_index_to_full_flags (level);
|
||||
wp_spa_log_get_instance()->level = level_index_to_spa (level);
|
||||
pw_log_set_level (level_index_to_spa (level));
|
||||
update_log_topic_levels ();
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* private, called from wp_init() */
|
||||
void
|
||||
wp_log_init (gint flags)
|
||||
|
|
@ -383,10 +458,12 @@ wp_log_init (gint flags)
|
|||
|
||||
pw_free_strv (tokens);
|
||||
|
||||
g_mutex_lock (&log_state.log_topics_lock);
|
||||
log_state.patterns = patterns;
|
||||
log_state.global_log_level = global_log_level;
|
||||
log_state.global_log_level_flags =
|
||||
level_index_to_full_flags (global_log_level);
|
||||
g_mutex_unlock (&log_state.log_topics_lock);
|
||||
|
||||
/* set the log level also on the spa_log */
|
||||
wp_spa_log_get_instance()->level = level_index_to_spa (global_log_level);
|
||||
|
|
@ -410,46 +487,63 @@ wp_log_init (gint flags)
|
|||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
wp_log_set_global_level (const gchar *log_level)
|
||||
static void
|
||||
log_topic_register (WpLogTopic *topic)
|
||||
{
|
||||
gint level;
|
||||
if (level_index_from_string (log_level, &level)) {
|
||||
log_state.global_log_level = level;
|
||||
log_state.global_log_level_flags = level_index_to_full_flags (level);
|
||||
wp_spa_log_get_instance()->level = level_index_to_spa (level);
|
||||
pw_log_set_level (level_index_to_spa (level));
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
if (!log_state.log_topics)
|
||||
log_state.log_topics = g_ptr_array_new ();
|
||||
|
||||
g_ptr_array_add (log_state.log_topics, topic);
|
||||
|
||||
log_topic_update_level (topic);
|
||||
topic->flags |= WP_LOG_TOPIC_FLAG_INITIALIZED;
|
||||
}
|
||||
|
||||
static void
|
||||
log_topic_unregister (WpLogTopic *topic)
|
||||
{
|
||||
if (!log_state.log_topics)
|
||||
return;
|
||||
|
||||
g_ptr_array_remove_fast (log_state.log_topics, topic);
|
||||
|
||||
if (log_state.log_topics->len == 0) {
|
||||
g_ptr_array_free (log_state.log_topics, TRUE);
|
||||
log_state.log_topics = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
find_topic_log_level (const gchar *log_topic, bool *has_custom_level)
|
||||
/*!
|
||||
* \brief Registers a log topic.
|
||||
*
|
||||
* The log topic must be unregistered using \ref wp_log_topic_unregister
|
||||
* before its lifetime ends.
|
||||
*
|
||||
* This function is threadsafe.
|
||||
*
|
||||
* \ingroup wplog
|
||||
*/
|
||||
void
|
||||
wp_log_topic_register (WpLogTopic *topic)
|
||||
{
|
||||
struct log_topic_pattern *pttrn = log_state.patterns;
|
||||
guint len;
|
||||
g_autofree gchar *reverse_topic = NULL;
|
||||
gint log_level = log_state.global_log_level;
|
||||
g_mutex_lock (&log_state.log_topics_lock);
|
||||
log_topic_register (topic);
|
||||
g_mutex_unlock (&log_state.log_topics_lock);
|
||||
}
|
||||
|
||||
/* reverse string and length required for pattern match */
|
||||
len = strlen (log_topic);
|
||||
reverse_topic = g_strreverse (g_strndup (log_topic, len));
|
||||
|
||||
while (pttrn && pttrn->spec &&
|
||||
!g_pattern_match (pttrn->spec, len, log_topic, reverse_topic))
|
||||
pttrn++;
|
||||
|
||||
if (pttrn && pttrn->spec) {
|
||||
if (has_custom_level)
|
||||
*has_custom_level = true;
|
||||
log_level = pttrn->log_level;
|
||||
} else if (has_custom_level) {
|
||||
*has_custom_level = false;
|
||||
}
|
||||
|
||||
return log_level;
|
||||
/*!
|
||||
* \brief Unregisters a log topic.
|
||||
*
|
||||
* This function is threadsafe.
|
||||
*
|
||||
* \ingroup wplog
|
||||
*/
|
||||
void
|
||||
wp_log_topic_unregister (WpLogTopic *topic)
|
||||
{
|
||||
g_mutex_lock (&log_state.log_topics_lock);
|
||||
log_topic_unregister (topic);
|
||||
g_mutex_unlock (&log_state.log_topics_lock);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -459,21 +553,17 @@ find_topic_log_level (const gchar *log_topic, bool *has_custom_level)
|
|||
void
|
||||
wp_log_topic_init (WpLogTopic *topic)
|
||||
{
|
||||
g_bit_lock (&topic->flags, 30);
|
||||
if ((topic->flags & (1u << 31)) == 0) {
|
||||
bool has_custom_level;
|
||||
gint log_level = find_topic_log_level (topic->topic_name, &has_custom_level);
|
||||
|
||||
gint flags = topic->flags;
|
||||
flags |= level_index_to_full_flags (log_level);
|
||||
flags |= (1u << 31); /* initialized = true */
|
||||
if (has_custom_level)
|
||||
flags |= (1u << 29); /* has_custom_level = true */
|
||||
|
||||
topic->global_flags = &log_state.global_log_level_flags;
|
||||
topic->flags = flags;
|
||||
g_mutex_lock (&log_state.log_topics_lock);
|
||||
if ((topic->flags & WP_LOG_TOPIC_FLAG_INITIALIZED) == 0) {
|
||||
if (topic->flags & WP_LOG_TOPIC_FLAG_STATIC) {
|
||||
/* Auto-register log topics that have infinite lifetime */
|
||||
log_topic_register (topic);
|
||||
} else {
|
||||
log_topic_update_level (topic);
|
||||
topic->flags |= WP_LOG_TOPIC_FLAG_INITIALIZED;
|
||||
}
|
||||
}
|
||||
g_bit_unlock (&topic->flags, 30);
|
||||
g_mutex_unlock (&log_state.log_topics_lock);
|
||||
}
|
||||
|
||||
typedef struct _WpLogFields WpLogFields;
|
||||
|
|
|
|||
33
lib/wp/log.h
33
lib/wp/log.h
|
|
@ -33,24 +33,26 @@ struct _WpLogTopic {
|
|||
/*< private >*/
|
||||
/*
|
||||
* lower 16 bits: GLogLevelFlags
|
||||
* bit 29: has_custom_level
|
||||
* bit 30: a g_bit_lock
|
||||
* bit 30: static log topic (infinite lifetime)
|
||||
* bit 31: 1 - initialized, 0 - not initialized
|
||||
*/
|
||||
gint flags;
|
||||
gint *global_flags;
|
||||
WP_PADDING(2)
|
||||
WP_PADDING(3)
|
||||
};
|
||||
|
||||
#define WP_LOG_TOPIC_FLAG_STATIC (1u << 30)
|
||||
#define WP_LOG_TOPIC_FLAG_INITIALIZED (1u << 31)
|
||||
#define WP_LOG_TOPIC_LEVEL_MASK (0xFFFF)
|
||||
|
||||
#define WP_LOG_TOPIC_EXTERN(var) \
|
||||
extern WpLogTopic * var;
|
||||
|
||||
#define WP_LOG_TOPIC(var, t) \
|
||||
WpLogTopic var##_struct = { .topic_name = t, .flags = 0 }; \
|
||||
WpLogTopic var##_struct = { .topic_name = t, .flags = WP_LOG_TOPIC_FLAG_STATIC }; \
|
||||
WpLogTopic * var = &(var##_struct);
|
||||
|
||||
#define WP_LOG_TOPIC_STATIC(var, t) \
|
||||
static WpLogTopic var##_struct = { .topic_name = t, .flags = 0 }; \
|
||||
static WpLogTopic var##_struct = { .topic_name = t, .flags = WP_LOG_TOPIC_FLAG_STATIC }; \
|
||||
static G_GNUC_UNUSED WpLogTopic * var = &(var##_struct);
|
||||
|
||||
#define WP_DEFINE_LOCAL_LOG_TOPIC(t) \
|
||||
|
|
@ -65,16 +67,16 @@ struct _WpLogTopic {
|
|||
WP_API
|
||||
void wp_log_topic_init (WpLogTopic *topic);
|
||||
|
||||
WP_API
|
||||
void wp_log_topic_register (WpLogTopic *topic);
|
||||
|
||||
WP_API
|
||||
void wp_log_topic_unregister (WpLogTopic *topic);
|
||||
|
||||
static inline gboolean
|
||||
wp_log_topic_is_initialized (WpLogTopic *topic)
|
||||
{
|
||||
return (topic->flags & (1u << 31)) != 0;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
wp_log_topic_has_custom_level (WpLogTopic *topic)
|
||||
{
|
||||
return (topic->flags & (1u << 29)) != 0;
|
||||
return (topic->flags & WP_LOG_TOPIC_FLAG_INITIALIZED) != 0;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
|
|
@ -84,10 +86,7 @@ wp_log_topic_is_enabled (WpLogTopic *topic, GLogLevelFlags log_level)
|
|||
if (G_UNLIKELY (!wp_log_topic_is_initialized (topic)))
|
||||
wp_log_topic_init (topic);
|
||||
|
||||
if (wp_log_topic_has_custom_level (topic))
|
||||
return (topic->flags & (log_level & 0xFFFF)) != 0;
|
||||
else
|
||||
return (*topic->global_flags & (log_level & 0xFFFF)) != 0;
|
||||
return (topic->flags & log_level & WP_LOG_TOPIC_LEVEL_MASK) != 0;
|
||||
}
|
||||
|
||||
#define wp_local_log_topic_is_enabled(log_level) \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue