[libvirt] [PATCH 09/12] Add a JSON properties parameter to virLog{, V}Message

Miloslav Trmac mitr at redhat.com
Mon Oct 8 19:07:56 UTC 2012


Thanks for the review.

----- Original Message -----
> On Thu, Sep 20, 2012 at 08:24:08PM +0200, Miloslav Trmač wrote:
> > ... and update all users.  No change in functionality, the parameter
> > will be used in later patches.
> > 
> > diff --git a/src/util/logging.h b/src/util/logging.h
> > index a66f5dc..14b7b7c 100644
> > --- a/src/util/logging.h
> > +++ b/src/util/logging.h
> > @@ -141,13 +142,13 @@ extern int virLogParseFilters(const char
> > *filters);
> >  extern int virLogParseOutputs(const char *output);
> >  extern void virLogMessage(const char *category, int priority,
> >                            const char *funcname, long long linenr,
> > -                          unsigned int flags,
> > -                          const char *fmt, ...)
> > ATTRIBUTE_FMT_PRINTF(6, 7);
> > +                          virJSONObjectPtr properties, unsigned
> > int flags,
> > +                          const char *fmt, ...)
> 
> Definite NACK to this change, since it is exposing the impl details
> of the Lumberjack log output function to all users of the libvirt
> logging API, not to mention the general unpleasant usability aspects
> of having to build up JSON objects simply to pass a few extra metadata
> fields.

I didn't think adding an abstraction for a single user was worth it, but you're right, the result did end up rather uglier than I expected.


> I'm all for allowing more metadata properties to be passed into the
> logging functions, but we need a simpler API along the lines of the
> systemd journal  sd_journal_send() style which allows for a set of
> key=value pairs to be passed in. I'd not try to shoe-horn it into
> the existing virLogMessage() APIs. In the same way that there is
> sd_journal_print() for simple string messages, vis sd_journal_send()
> for arbitrary key=value pair log messages, I'd create a new API
> for this called virLogMetadata and virLogVMetadata. eg to allow
> sending a message with an error no
> 
>    virLogMetadata(__FILE__, VIR_LOG_WARN,
>                   __FUNC__, __LINE__,
>                   0,
>                   "MESSAGE=Unable to open file %s: %s", "/some/file",
>                   strerror(errno),
>                   "ERRNO=%d", errno,
>                   NULL);

I'm afraid this is not possible to implement portably and reliably without reimplementing 50% of sprintf(), especially in the presence of translations and the associated %5$s formats.[1][2]

One problem with the above is that it is possible to send a log event without the MESSAGE field, which would leave non-structured formats with nothing to log.  I can see three options:

1) as proposed above, silently failing if the MESSAGE field is missing (or if there is a typo in the field name); with type fields added to represent JSON integers as integers.

2) MESSAGE is mandatory, everything pre-formatted
    virAsprintf(&msg, "Unable to open file %s: %s", "/some/file", strerror(errno));
    virLogMetadata(... __LINE__, msg,
                   "ERRNO", VIR_LOG_INT, errno,
                   NULL)

3) MESSAGE is printf-like, everything else in an array.

    struct virLogMetadata meta[2] = { { "ERRNO", VIR_LOG_INT, .i = errno }, { NULL, } };
    virLogMetadata(... __LINE__, meta, 
                   "Unable to open file %s: %s", "/some/file", strerror(errno));

   or equivalently:
    virLogMetadata(... __LINE__, 
                   &(struct virLogMetadata []) {
                      { "ERRNO", VIR_LOG_INT, .i = errno },
                      { NULL, }
                   },
                   "Unable to open file %s: %s", "/some/file", strerror(errno));
   which could be hidden by macros:
    virLogMetadata(VIR_LOG_INT("ERRNO", errno"),
                   VIR_LOG_END,
                   "Unable to open file %s: %s", "/some/file", strerror(errno));


Do you have any preference?  I'm leaning towards the first variant of 3) for now, we can add fancy macros later when/if more callers of virLogMetadata are added.

Thanks again,
   Mirek


[1] The unportable way to do this is to use parse_printf_format() from glibc.
[2] The logging API could implement only a subset of the printf formats, but it would be rather difficult to notice if a newly added caller used an unsupported format a few years later, especially when translators can use different formats than the original string.




More information about the libvir-list mailing list