Logging Plugin API
==================

Servers and clients define a logger in their configuration. The logger is a
plugin. A default plugin that logs to ``stdout`` is provided as an example.
The logger plugin is stateful and can point to custom data. So it is possible
to keep open file handlers in the logger context.

Every log-message consists of a log-level, a log-category and a string
message content. The timestamp of the log-message is created within the
logger.

.. code-block:: c

   
   typedef enum {
       UA_LOGLEVEL_TRACE = 0,
       UA_LOGLEVEL_DEBUG,
       UA_LOGLEVEL_INFO,
       UA_LOGLEVEL_WARNING,
       UA_LOGLEVEL_ERROR,
       UA_LOGLEVEL_FATAL
   } UA_LogLevel;
   
   typedef enum {
       UA_LOGCATEGORY_NETWORK = 0,
       UA_LOGCATEGORY_SECURECHANNEL,
       UA_LOGCATEGORY_SESSION,
       UA_LOGCATEGORY_SERVER,
       UA_LOGCATEGORY_CLIENT,
       UA_LOGCATEGORY_USERLAND,
       UA_LOGCATEGORY_SECURITYPOLICY
   } UA_LogCategory;
   
   typedef struct {
       /* Log a message. The message string and following varargs are formatted
        * according to the rules of the printf command. Use the convenience macros
        * below that take the minimum log-level defined in ua_config.h into
        * account. */
       void (*log)(void *logContext, UA_LogLevel level, UA_LogCategory category,
                   const char *msg, va_list args);
   
       void *context; /* Logger state */
   
       void (*clear)(void *context); /* Clean up the logger plugin */
   } UA_Logger;
   
   static UA_INLINE UA_FORMAT(3,4) void
   UA_LOG_TRACE(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
   #if UA_LOGLEVEL <= 100
       if(!logger || !logger->log)
           return;
       va_list args; va_start(args, msg);
       logger->log(logger->context, UA_LOGLEVEL_TRACE, category, msg, args);
       va_end(args);
   #else
       (void) logger;
       (void) category;
       (void) msg;
   #endif
   }
   
   static UA_INLINE UA_FORMAT(3,4) void
   UA_LOG_DEBUG(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
   #if UA_LOGLEVEL <= 200
       if(!logger || !logger->log)
           return;
       va_list args; va_start(args, msg);
       logger->log(logger->context, UA_LOGLEVEL_DEBUG, category, msg, args);
       va_end(args);
   #else
       (void) logger;
       (void) category;
       (void) msg;
   #endif
   }
   
   static UA_INLINE UA_FORMAT(3,4) void
   UA_LOG_INFO(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
   #if UA_LOGLEVEL <= 300
       if(!logger || !logger->log)
           return;
       va_list args; va_start(args, msg);
       logger->log(logger->context, UA_LOGLEVEL_INFO, category, msg, args);
       va_end(args);
   #else
       (void) logger;
       (void) category;
       (void) msg;
   #endif
   }
   
   static UA_INLINE UA_FORMAT(3,4) void
   UA_LOG_WARNING(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
   #if UA_LOGLEVEL <= 400
       if(!logger || !logger->log)
           return;
       va_list args; va_start(args, msg);
       logger->log(logger->context, UA_LOGLEVEL_WARNING, category, msg, args);
       va_end(args);
   #else
       (void) logger;
       (void) category;
       (void) msg;
   #endif
   }
   
   static UA_INLINE UA_FORMAT(3,4) void
   UA_LOG_ERROR(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
   #if UA_LOGLEVEL <= 500
       if(!logger || !logger->log)
           return;
       va_list args; va_start(args, msg);
       logger->log(logger->context, UA_LOGLEVEL_ERROR, category, msg, args);
       va_end(args);
   #else
       (void) logger;
       (void) category;
       (void) msg;
   #endif
   }
   
   static UA_INLINE UA_FORMAT(3,4) void
   UA_LOG_FATAL(const UA_Logger *logger, UA_LogCategory category, const char *msg, ...) {
   #if UA_LOGLEVEL <= 600
       if(!logger || !logger->log)
           return;
       va_list args; va_start(args, msg);
       logger->log(logger->context, UA_LOGLEVEL_FATAL, category, msg, args);
       va_end(args);
   #else
       (void) logger;
       (void) category;
       (void) msg;
   #endif
   }
