The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Travis CI build status AppVeyor CI build status Windows builds GitHub version License MIT

NAME

genericLogger - generic logging interface

SYNOPSIS

  #include <genericLogger.h>

  /* ---------------------------------- */
  /* User-defined logger implementation */
  /* ---------------------------------- */
  typedef void (*genericLoggerCallback_t)(void *userDatavp,
                                          genericLoggerLevel_t logLeveli,
                                          const char *msgs);

  /* ----------------------- */
  /* Creation, Cloning, Free */
  /* ----------------------- */
  genericLogger_t *genericLogger_newp  (genericLoggerCallback_t logCallbackp,
                                        void *userDatavp,
                                        genericLoggerLevel_t genericLoggerLeveli);
  genericLogger_t *genericLogger_clonep(genericLogger_t *genericLoggerp);
  void             genericLogger_freev (genericLogger_t **genericLoggerpp);

  /* ------- */
  /* Logging */
  /* ------- */
  void genericLogger_logv  (genericLogger_t *genericLoggerp,
                            genericLoggerLevel_t genericLoggerLeveli,
                            const char *fmts,
                            ...);
  void genericLogger_logapv(genericLogger_t *genericLoggerp,
                            genericLoggerLevel_t genericLoggerLeveli,
                            const char *fmts,
                            va_list ap);

  /* ---------------- */
  /* Level management */
  /* ---------------- */
  genericLoggerLevel_t genericLogger_logLevel_seti(genericLogger_t *genericLoggerp,
                                                   genericLoggerLevel_t logLeveli);
  genericLoggerLevel_t genericLogger_logLevel_geti(genericLogger_t *genericLoggerp);

  /* ------------------ */
  /* Context management */
  /* ------------------ */
  void *genericLogger_userDatavp_setp(genericLogger_t *genericLoggerp,
                                      void *userDatavp);
  void *genericLogger_userDatavp_getp(genericLogger_t *genericLoggerp);

DESCRIPTION

genericLogger is like a portable printf() with level filtering capability, designed to propagate already-formatted messages to user-defined log implementations.

METHODS

genericLogger_newp

  typedef void    (*genericLoggerCallback_t)(void *userDatavp,
                    genericLoggerLevel_t logLeveli,
                    const char *msgs);
  genericLogger_t  *genericLogger_newp(genericLoggerCallback_t logCallbackp,
                                       void *userDatavp,
                                       genericLoggerLevel_t genericLoggerLeveli);

Creates and return a generic logger.

The argument logCallbackp may be NULL, or a function pointer to a logging implementation. Such callback will be called with the argument userDatavp, untouched (one call that the callback context), the level, and a pre-formatted message.

The argument genericLoggerLeveli may be one of

GENERICLOGGER_LOGLEVEL_TRACE
GENERICLOGGER_LOGLEVEL_DEBUG
GENERICLOGGER_LOGLEVEL_INFO
GENERICLOGGER_LOGLEVEL_NOTICE
GENERICLOGGER_LOGLEVEL_WARNING
GENERICLOGGER_LOGLEVEL_ERROR
GENERICLOGGER_LOGLEVEL_CRITICAL
GENERICLOGGER_LOGLEVEL_ALERT
GENERICLOGGER_LOGLEVEL_EMERGENCY

it is guaranteed that logCallbackp will not be called whenever a message have a log level lower than genericLoggerLeveli.

If logCallbackp is NULL, then a default built-in implementation is used, with a hardcoded level set to GENERICLOGGER_LEVEL_TRACE (i.e. it will log everything), a hardcoded format string set to %d/%m/%Y %H:%M:%S %9s %s (i.e. date and time a-la-european style, a string giving the level, and the formatted message), and a hardcoded output to standard error.

Returns NULL on failure, system's errno will indicate the reason.

genericLogger_clonep

  genericLogger_t *genericLogger_clonep(genericLogger_t *genericLoggerp);

Clone the current generic logger and return a new one. The clone becomes independant, and must be freed using genericLogger_freev().

Returns NULL on failure, system's errno will indicate the reason.

genericLogger_freev

  void genericLogger_freev(genericLogger_t **genericLoggerpp);

Free the generic logger.

genericLogger_logv

  void genericLogger_logv(genericLogger_t *genericLoggerp,
                          genericLoggerLevel_t genericLoggerLeveli,
                          const char *fmts,
                          ...);

Format the message using fmts format string and eventual remaining parameters, and send it to the log implementation.

genericLogger_logapv

  void genericLogger_logapv(genericLogger_t *genericLoggerp,
                            genericLoggerLevel_t genericLoggerLeveli,
                            const char *fmts,
                            va_list ap);

va_list version of genericLogger_logv().

genericLogger_logLevel_seti

  genericLoggerLevel_t genericLogger_logLevel_seti(genericLogger_t *genericLoggerp,
                                                   genericLoggerLevel_t logLeveli);

Set the log level to leveLeveli and returns previous value.

genericLogger_logLevel_geti

  genericLoggerLevel_t genericLogger_logLevel_geti(genericLogger_t *genericLoggerp);

Return the current log level.

genericLogger_userDatavp_setp

  void *genericLogger_userDatavp_setp(genericLogger_t *genericLoggerp,
                                      void *userDatavp);

Set the context to userDatavp and returns previous value.

genericLogger_userDatavp_getp

  void *genericLogger_userDatavp_getp(genericLogger_t *genericLoggerp);

Return the current context.

genericLogger_versions

  const char *genericLogger_versions();

Return the version number.

CONVENIENCE MACROS

GENERICLOGGER_NEW

maps to genericLogger_newp.

GENERICLOGGER_CUSTOM

maps to genericLogger_newp with a custom log implementation.

GENERICLOGGER_CLONE

maps to genericLogger_clonep.

GENERICLOGGER_XXX

GENERICLOGGER_XXXF

GENERICLOGGER_XXXAP

maps to all log levels, where XXX is one of

TRACE
DEBUG
INFO
NOTICE
WARN
ERROR
CRITICAL
ALERT
EMERGENCY

For portability reasons, there are two different versions, depending if there are arguments or not: XXX or XXXF, respectively. The XXXAP is when the argument is a va_list.

The XXX and XXXF macros maps to genericLogger_logv(), while XXXAP maps to genericLogger_logapv(), and they all hardcode the level, so that the programmer do not have to write the later.

GENERICLOGGER_LEVEL_SET

maps to genericLogger_logLevel_seti.

GENERICLOGGER_LEVEL_GET

maps to genericLogger_logLevel_geti.

EXAMPLE

  #include <stdlib.h>
  #include <stdio.h>
  #include <errno.h>
  #include <string.h>
  #include <stdarg.h>
  #include <genericLogger.h>

  typedef struct localStruct { char *where; } localStruct_t;

  static void localLogger(void *userDatavp, genericLoggerLevel_t logLeveli, const char *msgs);
  static void forceTrace(genericLogger_t *loggerp, localStruct_t *localStructp, const char *fmts, ...);

  int main() {
    genericLogger_t *loggerp;
    localStruct_t    localStruct;

    loggerp = GENERICLOGGER_CUSTOM(localLogger, &localStruct, GENERICLOGGER_LOGLEVEL_WARNING);
    if (loggerp == NULL) { perror("GENERICLOGGER_CUSTOM"); exit(1); }

    localStruct.where = "main";
    GENERICLOGGER_TRACE(loggerp, "Nothing is logged");
    {
      genericLogger_t *clonep = GENERICLOGGER_CLONE(loggerp);
      if (clonep == NULL) { perror("GENERICLOGGER_CLONE"); exit(1); }

      GENERICLOGGER_LEVEL_SET(clonep, GENERICLOGGER_LOGLEVEL_WARNING)
      GENERICLOGGER_WARNF(loggerp, "Clone is warning, current level is %d", GENERICLOGGER_LEVEL_GET(loggerp));
      forceTrace(clonep, &localStruct, "Clone is forced to trace");
      GENERICLOGGER_FREE(clonep);
    }
    GENERICLOGGER_TRACE(loggerp, "Parent is still not logging");
    GENERICLOGGER_LEVEL_SET(loggerp, GENERICLOGGER_LOGLEVEL_DEBUG)
    GENERICLOGGER_DEBUGF(loggerp, "Parent is logging, current level is %d", GENERICLOGGER_LEVEL_GET(loggerp));
    forceTrace(loggerp, &localStruct, "Parent is forced to trace");
    GENERICLOGGER_FREE(loggerp);

    return 0;
  }

  static void forceTrace(genericLogger_t *loggerp, localStruct_t *localStructp, const char *fmts, ...) {
    va_list ap;
    char *previousWhere = localStructp->where;
    int previousLevel = GENERICLOGGER_LEVEL_GET(loggerp);

    localStructp->where = "mainap";
    va_start(ap, fmts);

    GENERICLOGGER_LEVEL_SET(loggerp, GENERICLOGGER_LOGLEVEL_TRACE)
    GENERICLOGGER_TRACEAP  (loggerp, fmts, ap);
    GENERICLOGGER_LEVEL_SET(loggerp, previousLevel);

    va_end(ap);
    localStructp->where = previousWhere;
  }

  static void localLogger(void *userDatavp, genericLoggerLevel_t logLeveli, const char *msgs) {
    localStruct_t *localStructp = (localStruct_t *) userDatavp;

    fprintf(stderr, "[%-6s] msgs = %s\n", localStructp->where, msgs);
  }

  /*
  [main  ] msgs = Clone is warning, current level is 4
  [mainap] msgs = Clone is forced to trace
  [main  ] msgs = Parent is logging, current level is 1
  [mainap] msgs = Parent is forced to trace
  */