gst: info: Add a GstLogContext API
Add a new API to control logging behavior, particularly for implementing "log once" functionality and periodic logging. This helps avoid spamming logs with repetitive messages. The API provides: - Static and dynamic context creation - Configurable message identity calculation - Periodic reset capability - Context-aware logging macros - Element message variants with context support Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6855>
This commit is contained in:
parent
707024f940
commit
c796abbf0a
1219
girs/Gst-1.0.gir
1219
girs/Gst-1.0.gir
File diff suppressed because it is too large
Load Diff
@ -506,6 +506,25 @@ G_STMT_START { \
|
||||
("flow-return", G_TYPE_INT, flow_return, NULL));\
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_FLOW_ERROR_WITH_LOG_CTX:
|
||||
* @el: the element that generates the error
|
||||
* @log_ctx: the log context
|
||||
* @flow_return: the GstFlowReturn leading to that ERROR message
|
||||
*
|
||||
* Utility function that elements can use in case they encountered a fatal
|
||||
* data processing error due to wrong flow processing.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
#define GST_ELEMENT_FLOW_ERROR_WITH_LOG_CTX(el,log_ctx,flow_return) \
|
||||
G_STMT_START { \
|
||||
GST_ELEMENT_ERROR_WITH_DETAILS_AND_LOG_CTX (el, STREAM, FAILED, log_ctx, \
|
||||
("Internal data stream error."), \
|
||||
("streaming stopped, reason %s (%d)", gst_flow_get_name (flow_return), flow_return), \
|
||||
("flow-return", G_TYPE_INT, flow_return, NULL));\
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_ERROR_WITH_DETAILS:
|
||||
* @el: the element that generates the error
|
||||
@ -539,6 +558,40 @@ G_STMT_START { \
|
||||
GST_FUNCTION, __LINE__, GST_ELEMENT_MESSAGE_MAKE_DETAILS(args)); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_ERROR_WITH_DETAILS_AND_LOG_CTX:
|
||||
* @el: the element that generates the error
|
||||
* @domain: like CORE, LIBRARY, RESOURCE or STREAM (see [GstGError](gsterror))
|
||||
* @code: error code defined for that domain (see [GstGError](gsterror))
|
||||
* @log_ctx: the log context
|
||||
* @text: the message to display (format string and args enclosed in
|
||||
parentheses)
|
||||
* @debug: debugging information for the message (format string and args
|
||||
enclosed in parentheses)
|
||||
* @args: optional name, type, value triplets, which will be stored
|
||||
* in the associated GstStructure. NULL terminator required.
|
||||
* Must be enclosed within parentheses.
|
||||
*
|
||||
* Utility function that elements can use in case they encountered a fatal
|
||||
* data processing error. The pipeline will post an error message and the
|
||||
* application will be requested to stop further media processing.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
#define GST_ELEMENT_ERROR_WITH_DETAILS_AND_LOG_CTX(el,domain,code,log_ctx,text,debug,args) \
|
||||
G_STMT_START { \
|
||||
gchar *__txt = _gst_element_error_printf text; \
|
||||
gchar *__dbg = _gst_element_error_printf debug; \
|
||||
if (__txt) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "error: %s", __txt); \
|
||||
if (__dbg) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "error: %s", __dbg); \
|
||||
gst_element_message_full_with_details (GST_ELEMENT(el), \
|
||||
GST_MESSAGE_ERROR, GST_ ## domain ## _ERROR, \
|
||||
GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \
|
||||
GST_FUNCTION, __LINE__, GST_ELEMENT_MESSAGE_MAKE_DETAILS(args)); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_ERROR:
|
||||
* @el: the element that generates the error
|
||||
@ -567,6 +620,37 @@ G_STMT_START { \
|
||||
GST_FUNCTION, __LINE__); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_ERROR_WITH_LOG_CTX:
|
||||
* @el: the element that generates the error
|
||||
* @domain: like CORE, LIBRARY, RESOURCE or STREAM (see [GstGError](gsterror))
|
||||
* @code: error code defined for that domain (see [GstGError](gsterror))
|
||||
* @log_ctx: the log context
|
||||
* @text: the message to display (format string and args enclosed in
|
||||
parentheses)
|
||||
* @debug: debugging information for the message (format string and args
|
||||
enclosed in parentheses)
|
||||
*
|
||||
* Utility function that elements can use in case they encountered a fatal
|
||||
* data processing error. The pipeline will post an error message and the
|
||||
* application will be requested to stop further media processing.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
#define GST_ELEMENT_ERROR_WITH_LOG_CTX(el,domain,code,log_ctx,text,debug) \
|
||||
G_STMT_START { \
|
||||
gchar *__txt = _gst_element_error_printf text; \
|
||||
gchar *__dbg = _gst_element_error_printf debug; \
|
||||
if (__txt) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "error: %s", __txt); \
|
||||
if (__dbg) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "error: %s", __dbg); \
|
||||
gst_element_message_full (GST_ELEMENT(el), \
|
||||
GST_MESSAGE_ERROR, GST_ ## domain ## _ERROR, \
|
||||
GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \
|
||||
GST_FUNCTION, __LINE__); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_WARNING_WITH_DETAILS:
|
||||
* @el: the element that generates the warning
|
||||
@ -600,6 +684,71 @@ G_STMT_START { \
|
||||
GST_FUNCTION, __LINE__, GST_ELEMENT_MESSAGE_MAKE_DETAILS(args)); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_WARNING_WITH_DETAILS_AND_LOG_CTX:
|
||||
* @el: the element that generates the warning
|
||||
* @domain: like CORE, LIBRARY, RESOURCE or STREAM (see [GstGError](gsterror))
|
||||
* @code: error code defined for that domain (see [GstGError](gsterror))
|
||||
* @log_ctx: the log context
|
||||
* @text: the message to display (format string and args enclosed in
|
||||
parentheses)
|
||||
* @debug: debugging information for the message (format string and args
|
||||
enclosed in parentheses)
|
||||
* @args: optional name, type, value triplets, which will be stored
|
||||
* in the associated GstStructure. NULL terminator required.
|
||||
* Must be enclosed within parentheses.
|
||||
*
|
||||
* Utility function that elements can use in case they encountered a non-fatal
|
||||
* data processing problem. The pipeline will post a warning message and the
|
||||
* application will be informed.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
#define GST_ELEMENT_WARNING_WITH_DETAILS_AND_LOG_CTX(el, domain, code, log_ctx, text, debug, args)\
|
||||
G_STMT_START { \
|
||||
gchar *__txt = _gst_element_error_printf text; \
|
||||
gchar *__dbg = _gst_element_error_printf debug; \
|
||||
if (__txt) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "warning: %s", __txt); \
|
||||
if (__dbg) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "warning: %s", __dbg); \
|
||||
gst_element_message_full_with_details (GST_ELEMENT(el), \
|
||||
GST_MESSAGE_WARNING, GST_ ## domain ## _ERROR, \
|
||||
GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \
|
||||
GST_FUNCTION, __LINE__, GST_ELEMENT_MESSAGE_MAKE_DETAILS(args)); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_WARNING_WITH_LOG_CTX:
|
||||
* @el: the element that generates the warning
|
||||
* @domain: like CORE, LIBRARY, RESOURCE or STREAM (see [GstGError](gsterror))
|
||||
* @code: error code defined for that domain (see [GstGError](gsterror))
|
||||
* @log_ctx: the log context
|
||||
* @text: the message to display (format string and args enclosed in
|
||||
parentheses)
|
||||
* @debug: debugging information for the message (format string and args
|
||||
enclosed in parentheses)
|
||||
*
|
||||
* Utility function that elements can use in case they encountered a non-fatal
|
||||
* data processing problem. The pipeline will post a warning message and the
|
||||
* application will be informed.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
#define GST_ELEMENT_WARNING_WITH_LOG_CTX(el, domain, code, log_ctx, text, debug) \
|
||||
G_STMT_START { \
|
||||
gchar *__txt = _gst_element_error_printf text; \
|
||||
gchar *__dbg = _gst_element_error_printf debug; \
|
||||
if (__txt) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "warning: %s", __txt); \
|
||||
if (__dbg) \
|
||||
GST_CTX_WARNING_OBJECT (log_ctx, el, "warning: %s", __dbg); \
|
||||
gst_element_message_full (GST_ELEMENT(el), \
|
||||
GST_MESSAGE_WARNING, GST_ ## domain ## _ERROR, \
|
||||
GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \
|
||||
GST_FUNCTION, __LINE__); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_WARNING:
|
||||
* @el: the element that generates the warning
|
||||
@ -664,6 +813,43 @@ G_STMT_START { \
|
||||
GST_FUNCTION, __LINE__, GST_ELEMENT_MESSAGE_MAKE_DETAILS(args)); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_INFO_WITH_DETAILS_AND_LOG_CTX:
|
||||
* @el: the element that generates the information
|
||||
* @domain: like CORE, LIBRARY, RESOURCE or STREAM (see [GstGError](gsterror))
|
||||
* @code: error code defined for that domain (see [GstGError](gsterror))
|
||||
* @log_ctx: the log context
|
||||
* @text: the message to display (format string and args enclosed in
|
||||
parentheses)
|
||||
* @debug: debugging information for the message (format string and args
|
||||
enclosed in parentheses)
|
||||
* @args: optional name, type, value triplets, which will be stored
|
||||
* in the associated GstStructure. NULL terminator required.
|
||||
* Must be enclosed within parentheses.
|
||||
*
|
||||
* Utility function that elements can use in case they want to inform
|
||||
* the application of something noteworthy that is not an error.
|
||||
* The pipeline will post a info message and the
|
||||
* application will be informed.
|
||||
* Optional name, type, value triplets may be supplied, and will be stored
|
||||
* in the associated GstStructure. NULL terminator required.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
#define GST_ELEMENT_INFO_WITH_DETAILS_AND_LOG_CTX(el, domain, code, log_ctx, text, debug, args) \
|
||||
G_STMT_START { \
|
||||
gchar *__txt = _gst_element_error_printf text; \
|
||||
gchar *__dbg = _gst_element_error_printf debug; \
|
||||
if (__txt) \
|
||||
GST_CTX_INFO_OBJECT (log_ctx, el, "info: %s", __txt); \
|
||||
if (__dbg) \
|
||||
GST_CTX_INFO_OBJECT (log_ctx, el, "info: %s", __dbg); \
|
||||
gst_element_message_full_with_details (GST_ELEMENT(el), \
|
||||
GST_MESSAGE_INFO, GST_ ## domain ## _ERROR, \
|
||||
GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \
|
||||
GST_FUNCTION, __LINE__, GST_ELEMENT_MESSAGE_MAKE_DETAILS(args)); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_INFO:
|
||||
* @el: the element that generates the information
|
||||
@ -693,6 +879,38 @@ G_STMT_START { \
|
||||
GST_FUNCTION, __LINE__); \
|
||||
} G_STMT_END
|
||||
|
||||
/**
|
||||
* GST_ELEMENT_INFO_WITH_LOG_CTX:
|
||||
* @el: the element that generates the information
|
||||
* @domain: like CORE, LIBRARY, RESOURCE or STREAM (see [GstGError](gsterror))
|
||||
* @code: error code defined for that domain (see [GstGError](gsterror))
|
||||
* @log_ctx: the log context
|
||||
* @text: the message to display (format string and args enclosed in
|
||||
parentheses)
|
||||
* @debug: debugging information for the message (format string and args
|
||||
enclosed in parentheses)
|
||||
*
|
||||
* Utility function that elements can use in case they want to inform
|
||||
* the application of something noteworthy that is not an error.
|
||||
* The pipeline will post a info message and the
|
||||
* application will be informed.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
#define GST_ELEMENT_INFO_WITH_LOG_CTX(el, domain, code, log_ctx, text, debug) \
|
||||
G_STMT_START { \
|
||||
gchar *__txt = _gst_element_error_printf text; \
|
||||
gchar *__dbg = _gst_element_error_printf debug; \
|
||||
if (__txt) \
|
||||
GST_CTX_INFO_OBJECT (log_ctx, el, "info: %s", __txt); \
|
||||
if (__dbg) \
|
||||
GST_CTX_INFO_OBJECT (log_ctx, el, "info: %s", __dbg); \
|
||||
gst_element_message_full (GST_ELEMENT(el), \
|
||||
GST_MESSAGE_INFO, GST_ ## domain ## _ERROR, \
|
||||
GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \
|
||||
GST_FUNCTION, __LINE__); \
|
||||
} G_STMT_END
|
||||
|
||||
/* the state change mutexes and conds */
|
||||
/**
|
||||
* GST_STATE_GET_LOCK:
|
||||
|
@ -121,6 +121,19 @@ static char *gst_info_printf_pointer_extension_func (const char *format,
|
||||
# include <unistd.h> /* getpid on UNIX */
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#define GST_DISABLE_FORMAT_NONLITERAL_WARNING \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"")
|
||||
#define GST_ENABLE_FORMAT_NONLITERAL_WARNING \
|
||||
_Pragma("clang diagnostic pop")
|
||||
#else
|
||||
/* For non-clang compilers, these macros do nothing */
|
||||
#define GST_DISABLE_FORMAT_NONLITERAL_WARNING
|
||||
#define GST_ENABLE_FORMAT_NONLITERAL_WARNING
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
# define WIN32_LEAN_AND_MEAN /* prevents from including too many things */
|
||||
# include <windows.h> /* GetStdHandle, windows console */
|
||||
@ -316,6 +329,30 @@ struct _GstDebugMessage
|
||||
gchar tmp_id[32];
|
||||
};
|
||||
|
||||
struct _GstLogContext
|
||||
{
|
||||
GstLogContextHashFlags hash_flags;
|
||||
GstLogContextFlags flags;
|
||||
GstClockTime interval;
|
||||
GstDebugCategory *category;
|
||||
|
||||
GMutex lock;
|
||||
GHashTable *logged_messages;
|
||||
GstClockTime last_reset_time;
|
||||
};
|
||||
|
||||
struct _GstLogContextBuilder
|
||||
{
|
||||
GstLogContextHashFlags hash_flags;
|
||||
GstLogContextFlags flags;
|
||||
GstDebugCategory *category;
|
||||
GstClockTime interval;
|
||||
};
|
||||
|
||||
/* Global registry for cleanup */
|
||||
static GHashTable *_log_contexts_registry = NULL;
|
||||
static GMutex _log_contexts_registry_lock;
|
||||
|
||||
/* list of all name/level pairs from --gst-debug and GST_DEBUG */
|
||||
static GMutex __level_name_mutex;
|
||||
static GSList *__level_name = NULL;
|
||||
@ -584,10 +621,139 @@ gst_path_basename (const gchar * file_name)
|
||||
return file_name;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
_gst_log_ctx_get_id_literal (GstLogContext * ctx,
|
||||
const gchar * file, gint line, GObject * object, const gchar * object_id,
|
||||
const gchar * message)
|
||||
{
|
||||
return g_strdup_printf ("%s:%d/%p/%s/%s",
|
||||
(ctx->hash_flags & GST_LOG_CONTEXT_IGNORE_FILE) ? "" : file,
|
||||
(ctx->hash_flags & GST_LOG_CONTEXT_USE_LINE_NUMBER) ? line : -1,
|
||||
(ctx->hash_flags & GST_LOG_CONTEXT_IGNORE_OBJECT) ? 0 : object,
|
||||
(ctx->hash_flags & GST_LOG_CONTEXT_IGNORE_OBJECT) ? "" : object_id,
|
||||
(ctx->hash_flags & GST_LOG_CONTEXT_IGNORE_FORMAT) ? "" : message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Message hashing based on context flags */
|
||||
static gchar *
|
||||
_gst_log_ctx_get_id_valist (GstLogContext * ctx, const gchar * file, gint line,
|
||||
GObject * object, const gchar * object_id, const gchar * format,
|
||||
va_list args)
|
||||
{
|
||||
gchar *full_message = NULL;
|
||||
|
||||
if (ctx->hash_flags & GST_LOG_CONTEXT_USE_STRING_ARGS) {
|
||||
g_assert (!(ctx->hash_flags & GST_LOG_CONTEXT_IGNORE_FORMAT));
|
||||
|
||||
GST_DISABLE_FORMAT_NONLITERAL_WARNING;
|
||||
full_message = g_strdup_vprintf (format, args);
|
||||
GST_ENABLE_FORMAT_NONLITERAL_WARNING;
|
||||
}
|
||||
|
||||
gchar *res = _gst_log_ctx_get_id_literal (ctx, file, line, object, object_id,
|
||||
full_message ? full_message : format);
|
||||
|
||||
g_free (full_message);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_gst_log_ctx_check_id (GstLogContext * ctx, gchar * id)
|
||||
{
|
||||
/* If throttling is not enabled, always return TRUE to allow logging */
|
||||
if (!(ctx->flags & GST_LOG_CONTEXT_FLAG_THROTTLE))
|
||||
return TRUE;
|
||||
|
||||
g_mutex_lock (&ctx->lock);
|
||||
gboolean res = g_hash_table_add (ctx->logged_messages, id);
|
||||
g_mutex_unlock (&ctx->lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_debug_log_full_valist (GstDebugCategory * category, GstDebugLevel level,
|
||||
const gchar * file, const gchar * function, gint line,
|
||||
GObject * object, const gchar * id, const gchar * format, va_list args)
|
||||
_gst_log_context_reset_unlocked (GstLogContext * ctx)
|
||||
{
|
||||
if (ctx->logged_messages) {
|
||||
g_hash_table_remove_all (ctx->logged_messages);
|
||||
}
|
||||
|
||||
ctx->last_reset_time = gst_util_get_timestamp ();
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
_gst_log_ctx_check_periodic_reset (GstLogContext * ctx)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
|
||||
g_mutex_lock (&ctx->lock);
|
||||
if (ctx->interval == 0)
|
||||
goto done;
|
||||
|
||||
if (!GST_CLOCK_TIME_IS_VALID (ctx->last_reset_time)) {
|
||||
ctx->last_reset_time = gst_util_get_timestamp ();
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
GstClockTime now = gst_util_get_timestamp ();
|
||||
gint64 elapsed = GST_CLOCK_DIFF (ctx->last_reset_time, now);
|
||||
|
||||
if (elapsed >= ctx->interval) {
|
||||
_gst_log_context_reset_unlocked (ctx);
|
||||
|
||||
goto done;
|
||||
}
|
||||
ret = FALSE;
|
||||
|
||||
done:
|
||||
g_mutex_unlock (&ctx->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_gst_log_ctx_check_id_literal (GstLogContext * ctx,
|
||||
const gchar * file, gint line, GObject * object, const gchar * id,
|
||||
const gchar * message)
|
||||
{
|
||||
if (!ctx)
|
||||
return TRUE;
|
||||
|
||||
/* Check for periodic reset if needed */
|
||||
if (!_gst_log_ctx_check_periodic_reset (ctx))
|
||||
return FALSE;
|
||||
|
||||
return _gst_log_ctx_check_id (ctx, _gst_log_ctx_get_id_literal (ctx, file,
|
||||
line, object, id, message));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_gst_log_ctx_check_id_valist (GstLogContext * ctx,
|
||||
const gchar * file, gint line,
|
||||
GObject * object, const gchar * object_id, const gchar * format,
|
||||
va_list args)
|
||||
{
|
||||
if (!ctx)
|
||||
return TRUE;
|
||||
|
||||
if (!_gst_log_ctx_check_periodic_reset (ctx)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _gst_log_ctx_check_id (ctx, _gst_log_ctx_get_id_valist (ctx, file,
|
||||
line, object, object_id, format, args));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_debug_log_full_valist (GstDebugCategory * category, GstLogContext * ctx,
|
||||
GstDebugLevel level, const gchar * file, const gchar * function, gint line,
|
||||
GObject * object, const gchar * object_id, const gchar * format,
|
||||
va_list args)
|
||||
{
|
||||
GstDebugMessage message;
|
||||
LogFuncEntry *entry;
|
||||
@ -598,18 +764,31 @@ gst_debug_log_full_valist (GstDebugCategory * category, GstDebugLevel level,
|
||||
if (level > gst_debug_category_get_threshold (category))
|
||||
return;
|
||||
|
||||
if (ctx) {
|
||||
va_list arguments;
|
||||
|
||||
G_VA_COPY (arguments, args);
|
||||
if (!_gst_log_ctx_check_id_valist (ctx, file, line, object, object_id,
|
||||
format, arguments)) {
|
||||
va_end (arguments);
|
||||
return;
|
||||
}
|
||||
va_end (arguments);
|
||||
}
|
||||
|
||||
g_return_if_fail (file != NULL);
|
||||
g_return_if_fail (function != NULL);
|
||||
g_return_if_fail (format != NULL);
|
||||
|
||||
#ifdef GST_ENABLE_EXTRA_CHECKS
|
||||
g_return_if_fail (id != NULL || object == NULL || G_IS_OBJECT (object));
|
||||
g_return_if_fail (object_id != NULL || object == NULL
|
||||
|| G_IS_OBJECT (object));
|
||||
#endif
|
||||
|
||||
message.message = NULL;
|
||||
message.format = format;
|
||||
message.object = object;
|
||||
message.object_id = (gchar *) id;
|
||||
message.object_id = (gchar *) object_id;
|
||||
message.free_object_id = FALSE;
|
||||
|
||||
G_VA_COPY (message.arguments, args);
|
||||
@ -653,8 +832,8 @@ gst_debug_log_valist (GstDebugCategory * category, GstDebugLevel level,
|
||||
g_warn_if_fail (object == NULL || G_IS_OBJECT (object));
|
||||
#endif
|
||||
|
||||
gst_debug_log_full_valist (category, level, file, function, line, object,
|
||||
NULL, format, args);
|
||||
gst_debug_log_full_valist (category, NULL, level, file, function, line,
|
||||
object, NULL, format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -678,13 +857,13 @@ gst_debug_log_id_valist (GstDebugCategory * category, GstDebugLevel level,
|
||||
const gchar * file, const gchar * function, gint line,
|
||||
const gchar * id, const gchar * format, va_list args)
|
||||
{
|
||||
gst_debug_log_full_valist (category, level, file, function, line, NULL, id,
|
||||
format, args);
|
||||
gst_debug_log_full_valist (category, NULL, level, file, function, line, NULL,
|
||||
id, format, args);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_debug_log_literal_full (GstDebugCategory * category, GstDebugLevel level,
|
||||
const gchar * file, const gchar * function, gint line,
|
||||
gst_debug_log_literal_full (GstDebugCategory * category, GstLogContext * ctx,
|
||||
GstDebugLevel level, const gchar * file, const gchar * function, gint line,
|
||||
GObject * object, const gchar * id, const gchar * message_string)
|
||||
{
|
||||
GstDebugMessage message;
|
||||
@ -696,6 +875,12 @@ gst_debug_log_literal_full (GstDebugCategory * category, GstDebugLevel level,
|
||||
if (level > gst_debug_category_get_threshold (category))
|
||||
return;
|
||||
|
||||
if (ctx) {
|
||||
if (!_gst_log_ctx_check_id_literal (ctx, file, line, object, id,
|
||||
message_string))
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef GST_ENABLE_EXTRA_CHECKS
|
||||
g_return_if_fail (id != NULL || object == NULL || G_IS_OBJECT (object));
|
||||
#endif
|
||||
@ -747,8 +932,8 @@ gst_debug_log_literal (GstDebugCategory * category, GstDebugLevel level,
|
||||
g_warn_if_fail (object == NULL || G_IS_OBJECT (object));
|
||||
#endif
|
||||
|
||||
gst_debug_log_literal_full (category, level, file, function, line, object,
|
||||
NULL, message_string);
|
||||
gst_debug_log_literal_full (category, NULL, level, file, function, line,
|
||||
object, NULL, message_string);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -771,8 +956,8 @@ gst_debug_log_id_literal (GstDebugCategory * category, GstDebugLevel level,
|
||||
const gchar * file, const gchar * function, gint line,
|
||||
const gchar * id, const gchar * message_string)
|
||||
{
|
||||
gst_debug_log_literal_full (category, level, file, function, line, NULL, id,
|
||||
message_string);
|
||||
gst_debug_log_literal_full (category, NULL, level, file, function, line, NULL,
|
||||
id, message_string);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2532,9 +2717,421 @@ clear_level_names (void)
|
||||
g_mutex_unlock (&__level_name_mutex);
|
||||
}
|
||||
|
||||
/* Logging context implementation */
|
||||
|
||||
static void
|
||||
_gst_log_context_free (GstLogContext * ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
g_mutex_lock (&ctx->lock);
|
||||
if (ctx->logged_messages) {
|
||||
g_hash_table_remove_all (ctx->logged_messages);
|
||||
g_hash_table_unref (ctx->logged_messages);
|
||||
}
|
||||
g_mutex_unlock (&ctx->lock);
|
||||
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
_register_log_context (GstLogContext * ctx)
|
||||
{
|
||||
g_mutex_lock (&_log_contexts_registry_lock);
|
||||
if (!_log_contexts_registry) {
|
||||
_log_contexts_registry =
|
||||
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
|
||||
(GDestroyNotify) _gst_log_context_free);
|
||||
}
|
||||
|
||||
g_hash_table_add (_log_contexts_registry, ctx);
|
||||
g_mutex_unlock (&_log_contexts_registry_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_log_context_builder_new: (skip):
|
||||
* @category: the debug category to use
|
||||
* @flags: the flags to use for the log context
|
||||
*
|
||||
* Creates a new builder for configuring a #GstLogContext with the specified
|
||||
* debug category and flags.
|
||||
*
|
||||
* Returns: (transfer full): a new #GstLogContextBuilder
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
GstLogContextBuilder *
|
||||
gst_log_context_builder_new (GstDebugCategory * category,
|
||||
GstLogContextFlags flags)
|
||||
{
|
||||
GstLogContextBuilder *builder;
|
||||
|
||||
g_return_val_if_fail (category, NULL);
|
||||
|
||||
builder = g_new0 (GstLogContextBuilder, 1);
|
||||
builder->hash_flags = GST_LOG_CONTEXT_DEFAULT;
|
||||
builder->flags = flags;
|
||||
builder->interval = 0;
|
||||
builder->category = category;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_log_context_builder_set_category: (skip):
|
||||
* @builder: (transfer full): a #GstLogContextBuilder
|
||||
* @category: the debug category to use, or NULL for no specific category
|
||||
*
|
||||
* Sets the debug category for the log context being built.
|
||||
*
|
||||
* Returns: (transfer full): the same #GstLogContextBuilder
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
GstLogContextBuilder *
|
||||
gst_log_context_builder_set_category (GstLogContextBuilder * builder,
|
||||
GstDebugCategory * category)
|
||||
{
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
builder->category = category;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_log_context_builder_set_hash_flags: (skip):
|
||||
* @builder: (transfer full): a #GstLogContextBuilder
|
||||
* @flags: the hash flags to use for the log context
|
||||
*
|
||||
* Sets the hash flags for the log context being built. These determine how
|
||||
* message hashes are calculated for determining duplicates.
|
||||
*
|
||||
* Returns: (transfer full): the same #GstLogContextBuilder
|
||||
|
||||
* Since: 1.28
|
||||
*/
|
||||
GstLogContextBuilder *
|
||||
gst_log_context_builder_set_hash_flags (GstLogContextBuilder * builder,
|
||||
GstLogContextHashFlags flags)
|
||||
{
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
builder->hash_flags = flags;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_log_context_builder_set_interval: (skip):
|
||||
* @builder: (transfer full): a #GstLogContextBuilder
|
||||
* @interval: the interval in nanoseconds for automatic reset
|
||||
*
|
||||
* Sets the automatic reset interval for the log context being built.
|
||||
* If @interval is 0, no automatic reset will occur.
|
||||
*
|
||||
* Returns: (transfer full): the same #GstLogContextBuilder
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
GstLogContextBuilder *
|
||||
gst_log_context_builder_set_interval (GstLogContextBuilder * builder,
|
||||
GstClockTime interval)
|
||||
{
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
builder->interval = interval;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_log_context_builder_build: (skip):
|
||||
* @builder: (transfer full): a #GstLogContextBuilder
|
||||
*
|
||||
* Builds a #GstLogContext from the builder configuration.
|
||||
* The builder is consumed by this function and should not be used afterward.
|
||||
*
|
||||
* Returns: (transfer full): a new #GstLogContext
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
GstLogContext *
|
||||
gst_log_context_builder_build (GstLogContextBuilder * builder)
|
||||
{
|
||||
/* Create a new context */
|
||||
GstLogContext *ctx;
|
||||
|
||||
ctx = g_new0 (GstLogContext, 1);
|
||||
ctx->hash_flags = builder->hash_flags;
|
||||
ctx->flags = builder->flags;
|
||||
ctx->interval = builder->interval;
|
||||
ctx->logged_messages =
|
||||
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
ctx->last_reset_time = GST_CLOCK_TIME_NONE;
|
||||
ctx->category = builder->category;
|
||||
|
||||
/* Register for cleanup */
|
||||
_register_log_context (ctx);
|
||||
g_free (builder);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_log_context_get_category: (skip):
|
||||
* @context: a #GstLogContext
|
||||
*
|
||||
* Get the #GstDebugCategory associated with this log context.
|
||||
*
|
||||
* Returns: the #GstDebugCategory to which the context is bound
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
GstDebugCategory *
|
||||
gst_log_context_get_category (GstLogContext * context)
|
||||
{
|
||||
g_return_val_if_fail (context != NULL, NULL);
|
||||
|
||||
return context->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_log_context_reset:
|
||||
* @ctx: a #GstLogContext
|
||||
*
|
||||
* Resets the logging context, clearing all tracked messages.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_log_context_reset (GstLogContext * ctx)
|
||||
{
|
||||
g_return_if_fail (ctx != NULL);
|
||||
|
||||
g_mutex_lock (&ctx->lock);
|
||||
_gst_log_context_reset_unlocked (ctx);
|
||||
g_mutex_unlock (&ctx->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_log_context_free:
|
||||
* @ctx: a #GstLogContext
|
||||
*
|
||||
* Free the logging context, clearing all tracked messages.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_log_context_free (GstLogContext * ctx)
|
||||
{
|
||||
g_return_if_fail (ctx != NULL);
|
||||
|
||||
g_mutex_lock (&_log_contexts_registry_lock);
|
||||
if (!_log_contexts_registry) {
|
||||
g_warning ("Trying to free log context %p while was not registered", ctx);
|
||||
} else {
|
||||
if (!g_hash_table_remove (_log_contexts_registry, ctx)) {
|
||||
g_warning ("Trying to free log context %p while was not registered", ctx);
|
||||
}
|
||||
}
|
||||
g_mutex_unlock (&_log_contexts_registry_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_log_with_context:
|
||||
* @ctx: a #GstLogContext
|
||||
* @level: level of the message
|
||||
* @file: the file that emitted the message, usually the __FILE__ identifier
|
||||
* @function: the function that emitted the message
|
||||
* @line: the line that emitted the message, usually the __LINE__ identifier
|
||||
* @object: (nullable): the object this message relates to,
|
||||
* or %NULL if none
|
||||
* @format: a printf style format string
|
||||
* @...: optional arguments for the format string
|
||||
*
|
||||
* Logs a message with the specified context. If the context has already seen this
|
||||
* message based on its flags configuration, the message will not be logged.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_debug_log_with_context (GstLogContext * ctx,
|
||||
GstDebugLevel level,
|
||||
const gchar * file,
|
||||
const gchar * function,
|
||||
gint line, GObject * object, const gchar * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
gst_debug_log_full_valist (ctx->category, ctx, level, file, function, line,
|
||||
object, NULL, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_log_with_context_valist:
|
||||
* @ctx: a #GstLogContext
|
||||
* @level: level of the message
|
||||
* @file: the file that emitted the message, usually the __FILE__ identifier
|
||||
* @function: the function that emitted the message
|
||||
* @line: the line that emitted the message, usually the __LINE__ identifier
|
||||
* @object: (nullable): the object this message relates to,
|
||||
* or %NULL if none
|
||||
* @format: a printf style format string
|
||||
* @args: optional arguments for the format string
|
||||
*
|
||||
* Logs a message with the specified context using a va_list. If the context has
|
||||
* already seen this message based on its flags configuration, the message will
|
||||
* not be logged.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_debug_log_with_context_valist (GstLogContext * ctx,
|
||||
GstDebugLevel level,
|
||||
const gchar * file,
|
||||
const gchar * function,
|
||||
gint line, GObject * object, const gchar * format, va_list args)
|
||||
{
|
||||
gst_debug_log_full_valist (ctx->category, ctx, level, file, function, line,
|
||||
object, NULL, format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_log_literal_with_context:
|
||||
* @ctx: a #GstLogContext
|
||||
* @level: level of the message
|
||||
* @file: the file that emitted the message, usually the __FILE__ identifier
|
||||
* @function: the function that emitted the message
|
||||
* @line: the line that emitted the message, usually the __LINE__ identifier
|
||||
* @object: (nullable): the object this message relates to,
|
||||
* or %NULL if none
|
||||
* @message: message string
|
||||
*
|
||||
* Logs a literal message with the specified context. Depending on the context
|
||||
* state, the message may not be logged at all.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_debug_log_literal_with_context (GstLogContext * ctx,
|
||||
GstDebugLevel level,
|
||||
const gchar * file,
|
||||
const gchar * function, gint line, GObject * object, const gchar * message)
|
||||
{
|
||||
gst_debug_log_literal_full (ctx->category, ctx, level, file, function, line,
|
||||
object, NULL, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_log_id_with_context:
|
||||
* @ctx: a #GstLogContext
|
||||
* @level: level of the message
|
||||
* @file: the file that emitted the message, usually the __FILE__ identifier
|
||||
* @function: the function that emitted the message
|
||||
* @line: the line that emitted the message, usually the __LINE__ identifier
|
||||
* @id: (nullable): the contextual ID of the message
|
||||
* @format: a printf style format string
|
||||
* @...: optional arguments for the format string
|
||||
*
|
||||
* Logs a message with the specified context and ID. If the context has already
|
||||
* seen this message based on its flags configuration, the message will not be
|
||||
* logged.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_debug_log_id_with_context (GstLogContext * ctx,
|
||||
GstDebugLevel level,
|
||||
const gchar * file,
|
||||
const gchar * function,
|
||||
gint line, const gchar * id, const gchar * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
gst_debug_log_full_valist (ctx->category, ctx, level, file, function, line,
|
||||
NULL, id, format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_log_id_with_context_valist:
|
||||
* @ctx: a #GstLogContext
|
||||
* @level: level of the message
|
||||
* @file: the file that emitted the message, usually the __FILE__ identifier
|
||||
* @function: the function that emitted the message
|
||||
* @line: the line that emitted the message, usually the __LINE__ identifier
|
||||
* @id: (nullable): the contextual ID of the message
|
||||
* @format: a printf style format string
|
||||
* @args: optional arguments for the format string
|
||||
*
|
||||
* Logs a message with the specified context and ID. If the context has already
|
||||
* seen this message based on its flags configuration, the message will not be
|
||||
* logged.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_debug_log_id_with_context_valist (GstLogContext * ctx,
|
||||
GstDebugLevel level,
|
||||
const gchar * file,
|
||||
const gchar * function,
|
||||
gint line, const gchar * id, const gchar * format, va_list args)
|
||||
{
|
||||
gst_debug_log_full_valist (ctx->category, ctx, level, file, function, line,
|
||||
NULL, id, format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_log_id_literal_with_context:
|
||||
* @ctx: a #GstLogContext
|
||||
* @level: level of the message
|
||||
* @file: the file that emitted the message, usually the __FILE__ identifier
|
||||
* @function: the function that emitted the message
|
||||
* @line: the line that emitted the message, usually the __LINE__ identifier
|
||||
* @id: (nullable): the contextual ID of the message
|
||||
* @message: message string
|
||||
*
|
||||
* Logs a message with the specified context and ID. If the context has already
|
||||
* seen this message based on its flags configuration, the message will not be
|
||||
* logged.
|
||||
*
|
||||
* Since: 1.28
|
||||
*/
|
||||
void
|
||||
gst_debug_log_id_literal_with_context (GstLogContext * ctx,
|
||||
GstDebugLevel level,
|
||||
const gchar * file,
|
||||
const gchar * function, gint line, const gchar * id, const gchar * message)
|
||||
{
|
||||
gst_debug_log_literal_full (ctx->category, ctx, level, file, function, line,
|
||||
NULL, id, message);
|
||||
}
|
||||
|
||||
static void
|
||||
_gst_log_context_cleanup (void)
|
||||
{
|
||||
g_mutex_lock (&_log_contexts_registry_lock);
|
||||
|
||||
if (_log_contexts_registry) {
|
||||
g_hash_table_unref (_log_contexts_registry);
|
||||
_log_contexts_registry = NULL;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&_log_contexts_registry_lock);
|
||||
}
|
||||
|
||||
void
|
||||
_priv_gst_debug_cleanup (void)
|
||||
{
|
||||
/* Clean up our log contexts */
|
||||
_gst_log_context_cleanup ();
|
||||
|
||||
g_mutex_lock (&__dbg_functions_mutex);
|
||||
|
||||
if (__gst_function_pointers) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -558,6 +558,234 @@ GST_START_TEST (info_set_and_reset_string)
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static gint context_log_count = 0;
|
||||
|
||||
static void
|
||||
context_log_counter_func (GstDebugCategory * category,
|
||||
GstDebugLevel level, const gchar * file, const gchar * function,
|
||||
gint line, GObject * object, GstDebugMessage * message, gpointer user_data)
|
||||
{
|
||||
/* Track the number of messages received */
|
||||
context_log_count++;
|
||||
|
||||
/* Let the default log function handle it for output if needed */
|
||||
if (g_getenv ("GST_DEBUG")) {
|
||||
gst_debug_log_default (category, level, file, function, line, object,
|
||||
message, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
GST_START_TEST (info_context_log)
|
||||
{
|
||||
GstDebugCategory *cat = NULL;
|
||||
GstLogContext *ctx = NULL;
|
||||
|
||||
gst_debug_remove_log_function (gst_debug_log_default);
|
||||
gst_debug_add_log_function (context_log_counter_func, NULL, NULL);
|
||||
gst_debug_set_default_threshold (GST_LEVEL_DEBUG);
|
||||
GST_DEBUG_CATEGORY_INIT (cat, "contextcat", 0, "Log context test category");
|
||||
|
||||
GST_LOG_CONTEXT_INIT (ctx, GST_LOG_CONTEXT_FLAG_THROTTLE);
|
||||
context_log_count = 0;
|
||||
/* Test all the different logging macros with context and verify the log level is respected */
|
||||
GST_CTX_ERROR (ctx, "Error message with context");
|
||||
GST_CTX_WARNING (ctx, "Warning message with context");
|
||||
GST_CTX_FIXME (ctx, "Fixme message with context");
|
||||
GST_CTX_INFO (ctx, "Info message with context");
|
||||
GST_CTX_DEBUG (ctx, "Debug message with context");
|
||||
GST_CTX_LOG (ctx, "Log message with context");
|
||||
GST_CTX_TRACE (ctx, "Trace message with context");
|
||||
/* Since trace and log are above our threshold, it won't be counted */
|
||||
fail_unless_equals_int (context_log_count, 5);
|
||||
|
||||
gst_debug_set_default_threshold (GST_LEVEL_NONE);
|
||||
gst_debug_add_log_function (gst_debug_log_default, NULL, NULL);
|
||||
gst_debug_remove_log_function (context_log_counter_func);
|
||||
gst_log_context_free (ctx);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (info_context_log_once)
|
||||
{
|
||||
GstDebugCategory *cat = NULL;
|
||||
GstLogContext *ctx = NULL;
|
||||
|
||||
/* Set up our counting log function */
|
||||
gst_debug_remove_log_function (gst_debug_log_default);
|
||||
gst_debug_add_log_function (context_log_counter_func, NULL, NULL);
|
||||
|
||||
/* Enable debug logging to ensure our logs get processed */
|
||||
gst_debug_set_default_threshold (GST_LEVEL_DEBUG);
|
||||
GST_DEBUG_CATEGORY_INIT (cat, "contextcat", 0, "Log context test category");
|
||||
GST_LOG_CONTEXT_INIT (ctx, GST_LOG_CONTEXT_FLAG_THROTTLE);
|
||||
|
||||
context_log_count = 0;
|
||||
|
||||
/* Log the same message multiple times */
|
||||
GST_CTX_DEBUG (ctx, "This message should only appear once");
|
||||
GST_CTX_DEBUG (ctx, "This message should only appear once");
|
||||
GST_CTX_DEBUG (ctx, "This message should only appear once");
|
||||
|
||||
/* Different messages should appear */
|
||||
GST_CTX_DEBUG (ctx, "A different message");
|
||||
GST_CTX_DEBUG (ctx, "Another different message");
|
||||
|
||||
/* Should see 3 messages total */
|
||||
fail_unless_equals_int (context_log_count, 3);
|
||||
|
||||
/* Clean up */
|
||||
gst_debug_set_default_threshold (GST_LEVEL_NONE);
|
||||
gst_debug_add_log_function (gst_debug_log_default, NULL, NULL);
|
||||
gst_debug_remove_log_function (context_log_counter_func);
|
||||
gst_log_context_free (ctx);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (info_context_log_periodic)
|
||||
{
|
||||
GstDebugCategory *cat = NULL;
|
||||
GstLogContext *ctx = NULL;
|
||||
|
||||
gst_debug_remove_log_function (gst_debug_log_default);
|
||||
gst_debug_add_log_function (context_log_counter_func, NULL, NULL);
|
||||
gst_debug_set_default_threshold (GST_LEVEL_DEBUG);
|
||||
GST_DEBUG_CATEGORY_INIT (cat, "contextcat", 0, "Log context test category");
|
||||
|
||||
GST_LOG_CONTEXT_INIT (ctx, GST_LOG_CONTEXT_FLAG_THROTTLE, {
|
||||
GST_LOG_CONTEXT_BUILDER_SET_INTERVAL (10 * GST_MSECOND);
|
||||
}
|
||||
);
|
||||
|
||||
/* Reset the counter */
|
||||
context_log_count = 0;
|
||||
GST_CTX_DEBUG (ctx, "This message should appear the first time");
|
||||
GST_CTX_DEBUG (ctx, "This message should appear the first time");
|
||||
GST_CTX_DEBUG (ctx, "This message should appear the first time");
|
||||
|
||||
/* Should see the message only once, unless it took more than 10ms to print 3
|
||||
* debug message ... */
|
||||
fail_unless_equals_int (context_log_count, 1);
|
||||
|
||||
/* Sleep to ensure the reset interval passes */
|
||||
g_usleep (20000); /* 20ms */
|
||||
|
||||
/* Log the same message again - it should appear after the interval */
|
||||
GST_CTX_DEBUG (ctx, "This message should appear the first time");
|
||||
|
||||
/* Should see both messages now */
|
||||
fail_unless_equals_int (context_log_count, 2);
|
||||
|
||||
/* Clean up */
|
||||
gst_debug_set_default_threshold (GST_LEVEL_NONE);
|
||||
gst_debug_add_log_function (gst_debug_log_default, NULL, NULL);
|
||||
gst_debug_remove_log_function (context_log_counter_func);
|
||||
gst_log_context_free (ctx);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* Test the static context macros */
|
||||
GST_LOG_CONTEXT_STATIC_DEFINE (static_ctx, GST_LOG_CONTEXT_FLAG_THROTTLE);
|
||||
#define STATIC_CTX GST_LOG_CONTEXT_LAZY_INIT(static_ctx)
|
||||
GST_LOG_CONTEXT_STATIC_DEFINE (static_periodic_ctx,
|
||||
GST_LOG_CONTEXT_FLAG_THROTTLE, GST_LOG_CONTEXT_BUILDER_SET_INTERVAL (1);
|
||||
);
|
||||
#define STATIC_PERIODIC_CTX GST_LOG_CONTEXT_LAZY_INIT(static_periodic_ctx)
|
||||
|
||||
GST_START_TEST (info_context_log_static)
|
||||
{
|
||||
GstDebugCategory *cat = NULL;
|
||||
|
||||
gst_debug_remove_log_function (gst_debug_log_default);
|
||||
gst_debug_add_log_function (context_log_counter_func, NULL, NULL);
|
||||
gst_debug_set_default_threshold (GST_LEVEL_DEBUG);
|
||||
GST_DEBUG_CATEGORY_INIT (cat, "contextcat", 0, "Log context test category");
|
||||
|
||||
context_log_count = 0;
|
||||
|
||||
GST_CTX_DEBUG (STATIC_CTX, "Static context message");
|
||||
GST_CTX_DEBUG (STATIC_CTX, "Static context default category message");
|
||||
fail_unless_equals_int (context_log_count, 2);
|
||||
|
||||
context_log_count = 0;
|
||||
GST_CTX_DEBUG (STATIC_PERIODIC_CTX, "Static periodic context message");
|
||||
fail_unless_equals_int (context_log_count, 1);
|
||||
|
||||
/* Sleep to ensure the reset interval passes */
|
||||
g_usleep (2000); /* 2ms */
|
||||
GST_CTX_DEBUG (STATIC_PERIODIC_CTX, "Static periodic context message");
|
||||
fail_unless_equals_int (context_log_count, 2);
|
||||
|
||||
gst_debug_set_default_threshold (GST_LEVEL_NONE);
|
||||
gst_debug_add_log_function (gst_debug_log_default, NULL, NULL);
|
||||
gst_debug_remove_log_function (context_log_counter_func);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (info_context_log_flags)
|
||||
{
|
||||
GstDebugCategory *cat = NULL;
|
||||
GstElement *element;
|
||||
GstLogContext *ctx1 = NULL, *ctx2 = NULL, *ctx3 = NULL;
|
||||
|
||||
/* Set up our counting log function */
|
||||
gst_debug_remove_log_function (gst_debug_log_default);
|
||||
gst_debug_add_log_function (context_log_counter_func, NULL, NULL);
|
||||
|
||||
/* Enable debug logging to ensure our logs get processed */
|
||||
gst_debug_set_default_threshold (GST_LEVEL_DEBUG);
|
||||
GST_DEBUG_CATEGORY_INIT (cat, "contextcat", 0, "Log context test category");
|
||||
|
||||
/* Create an element for object-based logging */
|
||||
element = gst_element_factory_make ("identity", NULL);
|
||||
fail_unless (element != NULL);
|
||||
|
||||
/* Test DEFAULT context */
|
||||
GST_LOG_CONTEXT_INIT (ctx1, GST_LOG_CONTEXT_FLAG_THROTTLE);
|
||||
context_log_count = 0;
|
||||
GST_CTX_DEBUG_OBJECT (ctx1, element, "Test message with default context");
|
||||
GST_CTX_DEBUG_OBJECT (ctx1, NULL, "Test message with default context");
|
||||
/* Should see both messages since objects are different */
|
||||
fail_unless_equals_int (context_log_count, 2);
|
||||
|
||||
/* Test IGNORE_OBJECT context */
|
||||
GST_LOG_CONTEXT_INIT (ctx2, GST_LOG_CONTEXT_FLAG_THROTTLE, {
|
||||
GST_LOG_CONTEXT_BUILDER_SET_HASH_FLAGS (GST_LOG_CONTEXT_IGNORE_OBJECT);
|
||||
}
|
||||
);
|
||||
context_log_count = 0;
|
||||
GST_CTX_DEBUG_OBJECT (ctx2, element,
|
||||
"Test message with ignore object context");
|
||||
GST_CTX_DEBUG_OBJECT (ctx2, NULL, "Test message with ignore object context");
|
||||
/* Should see only one message since objects are ignored in hash calculation */
|
||||
fail_unless_equals_int (context_log_count, 1);
|
||||
|
||||
/* Test USE_LINE_NUMBER context */
|
||||
GST_LOG_CONTEXT_INIT (ctx3, GST_LOG_CONTEXT_FLAG_THROTTLE, {
|
||||
GST_LOG_CONTEXT_BUILDER_SET_HASH_FLAGS
|
||||
(GST_LOG_CONTEXT_USE_LINE_NUMBER);
|
||||
}
|
||||
);
|
||||
context_log_count = 0;
|
||||
GST_CTX_DEBUG (ctx3, "Test message with line context");
|
||||
GST_CTX_DEBUG (ctx3, "Test message with line context");
|
||||
/* Should see the 2 messages since line numbers are taken into account */
|
||||
fail_unless_equals_int (context_log_count, 2);
|
||||
|
||||
gst_object_unref (element);
|
||||
gst_debug_set_default_threshold (GST_LEVEL_NONE);
|
||||
gst_debug_add_log_function (gst_debug_log_default, NULL, NULL);
|
||||
gst_debug_remove_log_function (context_log_counter_func);
|
||||
gst_log_context_free (ctx1);
|
||||
gst_log_context_free (ctx2);
|
||||
gst_log_context_free (ctx3);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_info_suite (void)
|
||||
{
|
||||
@ -581,6 +809,12 @@ gst_info_suite (void)
|
||||
tcase_add_test (tc_chain, info_set_and_unset_multiple);
|
||||
tcase_add_test (tc_chain, info_post_gst_init_category_registration);
|
||||
tcase_add_test (tc_chain, info_set_and_reset_string);
|
||||
|
||||
tcase_add_test (tc_chain, info_context_log);
|
||||
tcase_add_test (tc_chain, info_context_log_once);
|
||||
tcase_add_test (tc_chain, info_context_log_periodic);
|
||||
tcase_add_test (tc_chain, info_context_log_static);
|
||||
tcase_add_test (tc_chain, info_context_log_flags);
|
||||
#endif
|
||||
|
||||
return s;
|
||||
|
Loading…
x
Reference in New Issue
Block a user