[vlc-devel] [PATCH 1/2] libvlc: added a formatted log callback

Romain Vimont rom1v at videolabs.io
Fri May 17 11:14:43 CEST 2019


On Fri, May 17, 2019 at 10:05:00AM +0200, Jérémy VIGNELLES wrote:
> ---
>  include/vlc/libvlc.h | 64 ++++++++++++++++++++++++++++++++++++++++++++
>  lib/libvlc.sym       |  3 +++
>  lib/log.c            | 55 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 122 insertions(+)
> 
> diff --git a/include/vlc/libvlc.h b/include/vlc/libvlc.h
> index 1c2550fe3b..1b21c2da66 100644
> --- a/include/vlc/libvlc.h
> +++ b/include/vlc/libvlc.h
> @@ -433,6 +433,26 @@ LIBVLC_API void libvlc_log_get_object(const libvlc_log_t *ctx,
>  typedef void (*libvlc_log_cb)(void *data, int level, const libvlc_log_t *ctx,
>                                const char *fmt, va_list args);
>  
> +/**
> + * Callback prototype for LibVLC preformatted log message handler.
> + *
> + * \param data data pointer as given to libvlc_log_set()
> + * \param level message level (@ref libvlc_log_level)
> + * \param ctx message context (meta-information about the message)
> + * \param message the message, already formatted
> + * \note Log message handlers <b>must</b> be thread-safe.
> + * \warning The message context pointer, and the message string parameters
> + *          are only valid until the callback returns.
> + */
> +typedef void (*libvlc_log_preformatted_cb)(void *data, int level, const libvlc_log_t *ctx,
> +                              const char *message);
> +
> +/** 
> + * Structure that represents the context to pass to the @ref libvlc_log_set_preformatted function
> + * \note This structure is opaque, use @ref libvlc_log_preformatted_context_new to allocate one
> + */
> +typedef struct libvlc_log_preformatted_context_t libvlc_log_preformatted_context_t;
> +
>  /**
>   * Unsets the logging callback.
>   *
> @@ -468,6 +488,50 @@ LIBVLC_API void libvlc_log_unset( libvlc_instance_t *p_instance );
>  LIBVLC_API void libvlc_log_set( libvlc_instance_t *p_instance,
>                                  libvlc_log_cb cb, void *data );
>  
> +/**
> + * Creates a structure for formatted log data
> + *
> + * \param p_instance libvlc instance
> + * \param min_level the callback will only be called if the message level is above this level, 0 means "get all messages"
> + * \param cb callback function pointer
> + * \param data opaque data pointer for the callback function
> + *
> + * \note You must release the result at the end of the logging, with @ref libvlc_log_preformatted_context_release
> + *
> + * \version LibVLC 4.0.0 or later
> + */
> +LIBVLC_API libvlc_log_preformatted_context_t* libvlc_log_preformatted_context_new (libvlc_instance_t *p_instance, int min_level,
> +                                            libvlc_log_preformatted_cb cb, void *data );
> +
> +/**
> + * Destroys a structure for formatted log data created with @ref libvlc_log_preformatted_context_new
> + *
> + * \param p_instance libvlc instance
> + * \param data The log context for the preformatted callback, allocated with @ref libvlc_log_preformatted_context_new
> + *
> + * \version LibVLC 4.0.0 or later
> + */
> +LIBVLC_API void libvlc_log_preformatted_context_release (libvlc_instance_t *p_instance, libvlc_log_preformatted_context_t* data);
> +
> +/**
> + * Sets the logging callback for a LibVLC instance, that takes a preformatted message as input.
> + *
> + * This function is thread-safe: it will wait for any pending callbacks
> + * invocation to complete.
> + *
> + * \param p_instance libvlc instance
> + * \param min_level the callback will only be called if the message level is above this level, 0 means "get all messages"
> + * \param cb callback function pointer
> + * \param data opaque context pointer for the callback function
> + *
> + * \note Some log messages (especially debug) are emitted by LibVLC while
> + * is being initialized. These messages cannot be captured with this interface.
> + *
> + * \warning A deadlock may occur if this function is called from the callback.
> + *
> + * \version LibVLC 4.0.0 or later
> + */
> +LIBVLC_API void libvlc_log_set_preformatted (libvlc_instance_t *p_instance, libvlc_log_preformatted_context_t* data );
>  
>  /**
>   * Sets up logging to a file.
> diff --git a/lib/libvlc.sym b/lib/libvlc.sym
> index 51a45688de..04fae622a9 100644
> --- a/lib/libvlc.sym
> +++ b/lib/libvlc.sym
> @@ -56,8 +56,11 @@ libvlc_get_fullscreen
>  libvlc_get_version
>  libvlc_log_get_context
>  libvlc_log_get_object
> +libvlc_log_preformatted_context_new
> +libvlc_log_preformatted_context_release
>  libvlc_log_set
>  libvlc_log_set_file
> +libvlc_log_set_preformatted
>  libvlc_log_unset
>  libvlc_media_add_option
>  libvlc_media_add_option_flag
> diff --git a/lib/log.c b/lib/log.c
> index 66e0d996d1..62d88ce064 100644
> --- a/lib/log.c
> +++ b/lib/log.c
> @@ -93,6 +93,61 @@ void libvlc_log_set (libvlc_instance_t *inst, libvlc_log_cb cb, void *data)
>      vlc_LogSet(inst->p_libvlc_int, &libvlc_log_ops, inst);
>  }
>  
> +/*** Helpers for logging to preformatted callback ***/
> +typedef struct libvlc_log_preformatted_context_t {
> +    libvlc_log_preformatted_cb cb;
> +    void* original_data;
> +    int min_level;
> +} libvlc_log_preformatted_context_t;
> +
> +/**
> + * The real log callback, that takes a format+va_list as input, formats the message, and pass it to the preformatted callback
> + */
> +static void libvlc_preformatted_log (void *data, int level, const libvlc_log_t *log,
> +                             const char *fmt, va_list ap)
> +{
> +    libvlc_log_preformatted_context_t *log_data = (libvlc_log_preformatted_context_t *)data;
> +    if(level >= log_data->min_level)
> +    {
> +        char* msg;
> +        int msgSize = vasprintf(&msg, fmt, ap);
> +        if (unlikely(msgSize < 0))
> +            return;
> +
> +        log_data->cb(log_data->original_data, level, log, msg);
> +        free(msg);
> +    }
> +}
> +
> +libvlc_log_preformatted_context_t* libvlc_log_preformatted_context_new (libvlc_instance_t *p_instance, int min_level,
> +                                            libvlc_log_preformatted_cb cb, void *data )
> +{
> +    (void)p_instance;
> +    libvlc_log_preformatted_context_t *p_new = malloc (sizeof (*p_new));
> +    if (unlikely(p_new == NULL))
> +        return NULL;
> +
> +    p_new->cb = cb;
> +    p_new->min_level = min_level;
> +    p_new->original_data = data;
> +
> +    return p_new;
> +}
> +
> +void libvlc_log_preformatted_context_release (libvlc_instance_t *p_instance, libvlc_log_preformatted_context_t* data)
> +{
> +    if(p_instance->log.data == data)
> +    {// The log context is currently in use, unset the log before
> +        libvlc_log_unset (p_instance);
> +    }
> +    free(data);
> +}
> +
> +void libvlc_log_set_preformatted (libvlc_instance_t *p_instance, libvlc_log_preformatted_context_t* data )
> +{
> +    libvlc_log_set (p_instance, libvlc_preformatted_log, data);
> +}

Would it be possible not to expose libvlc_log_preformatted_context_t?

For example:

    void libvlc_log_set_preformatted(libvlc_instance_t *p_instance,
                                     int min_level,
                                     libvlc_log_preformatted_cb cb,
                                     void *data);

and handle the destruction internally when the logger is replaced or
libvlc_instance_t is destroyed?

> +
>  /*** Helpers for logging to files ***/
>  static void libvlc_log_file (void *data, int level, const libvlc_log_t *log,
>                               const char *fmt, va_list ap)
> -- 
> 2.21.0.windows.1
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list