/*

  silclog.h

  Author: Pekka Riikonen <priikone@silcnet.org>

  Copyright (C) 1997 - 2006 Pekka Riikonen

  The contents of this file are subject to one of the Licenses specified 
  in the COPYING file;  You may not use this file except in compliance 
  with the License.

  The software distributed under the License is distributed on an "AS IS"
  basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
  KIND, either expressed or implied.  See the COPYING file for more
  information.

*/

/****h* silcutil/SILC Logging Interface
 *
 * DESCRIPTION
 *
 * The SILC logging APIs provide a powerful and easy-to-use interface to
 * the logging system and debugging output.
 *
 ***/

#ifndef SILCLOG_H
#define SILCLOG_H

/****d* silcutil/SilcLogAPI/SilcLogType
 *
 * NAME
 *
 *    typedef enum { ... } SilcLogType;
 *
 * DESCRIPTION
 *
 *    The log type.  This can be given to various silc_log_* routines.
 *
 * SOURCE
 */
typedef enum {
  SILC_LOG_INFO       = 1,	/* Generic info */
  SILC_LOG_WARNING    = 2,      /* Warnings and non-critical failures */
  SILC_LOG_ERROR      = 3,      /* Generic error and critical failure */
  SILC_LOG_FATAL      = 4,	/* Fatal error */
} SilcLogType;
/***/

#include "silclog_i.h"

/****f* silcutil/SilcLogAPI/SilcLogCb
 *
 * SYNOPSIS
 *
 *    typedef SilcBool (*SilcLogCb)(SilcLogType type, char *message,
 *                                  void *context);
 *
 * DESCRIPTION
 *
 *    The logging custom callback function.  The `type' is the channel ID
 *    that triggered the event, which allows you to use the same callback
 *    function for multiple logging channels.
 *
 *    The `message' parameter points to a null-terminated buffer containing
 *    the received message, while `context' is the caller-specified context.
 *    The message must not be modified or freed by the callback function.
 *    If the function returns TRUE, SilcLog will assume the message was
 *    handled and won't run its default handler.
 *
 * SEE ALSO
 *    silc_log_set_callback
 *
 ***/
typedef SilcBool (*SilcLogCb)(SilcLogType type, char *message, void *context);

/****f* silcutil/SilcLogAPI/SilcLogDebugCb
 *
 * SYNOPSIS
 *
 *    typedef SilcBool (*SilcLogDebugCb)(char *file, char *function, int line,
 *                                       char *message, void *context);
 *
 * DESCRIPTION
 *
 *    The debug logging callback function.  The default behaviour is to
 *    output messages to stderr.  `file', `function', and `line' are the
 *    corresponding offsets in the source files.  `message' points to a
 *    null-terminated buffer containing the debugging message, and `context'
 *    is the caller-specified context.
 *
 *    The message must not be modified or freed by the callback function.
 *    If the function returns TRUE, SilcLog will assume the message as handled
 *    and won't run its default handler.
 *
 * SEE ALSO
 *    silc_debug, silc_log_set_debug_callbacks
 *
 ***/
typedef SilcBool (*SilcLogDebugCb)(char *file, char *function, int line,
				   char *message, void *context);

/****f* silcutil/SilcLogAPI/SilcLogHexdumpCb
 *
 * SYNOPSIS
 *
 *    typedef SilcBool
 *    (*SilcDebugHexdumpCb)(char *file, char *function, int line,
 *                          unsigned char *data,
 *                          SilcUInt32 data_len,
 *                          char *message, void *context;
 *
 * DESCRIPTION
 *
 *    The hexdump logging callback function.  The default behaviour is to
 *    print a formatted hexdump to stderr, and is commonly what you would
 *    like it to be.  `file', `function', and `line' are the corresponding
 *    offsets in the source files.  `data' is the begin of the buffer that
 *    should be hexdumped, which is `data_len' bytes long.
 *
 *    The `message' parameter points to a null-terminated buffer containing
 *    the received message, while `context' is the caller-specified context.
 *    The message must not be modified or freed by the callback function.
 *    If the function returns TRUE, SilcLog will assume the message as handled
 *    and won't run its default handler.
 *
 * SEE ALSO
 *    silc_debug_hexdump, silc_log_set_debug_callbacks
 *
 ***/
typedef SilcBool (*SilcLogHexdumpCb)(char *file, char *function, int line,
				     unsigned char *data, SilcUInt32 data_len,
				     char *message, void *context);

/* Macros */

/****d* silcutil/SilcLogAPI/SILC_LOG_INFO
 *
 * NAME
 *
 *    #define SILC_LOG_INFO(...)
 *
 * DESCRIPTION
 *
 *    This macro is a wrapper to the main logging function.
 *    It supports variable argument list formatting, and *automatically*
 *    appends newline at the end of the string.
 *
 * NOTES
 *
 *    This macro requires double parenthesis to ensure that the VA list
 *    formatting would work correctly.
 *
 * EXAMPLE
 *
 *    SILC_LOG_INFO(("Today i feel %s", core->mood));
 *
 * SOURCE
 */
#define SILC_LOG_INFO(fmt) silc_log_output(SILC_LOG_INFO, silc_format fmt)
/***/

/****d* silcutil/SilcLogAPI/SILC_LOG_WARNING
 *
 * NAME
 *
 *    #define SILC_LOG_WARNING(...)
 *
 * DESCRIPTION
 *
 *    Wrapper to the WARNING logging channel.
 *    Please see the SILC_LOG_INFO macro.
 *
 * SEE ALSO
 *    SILC_LOG_INFO
 *
 * SOURCE
 */
#define SILC_LOG_WARNING(fmt) silc_log_output(SILC_LOG_WARNING, silc_format fmt)
/***/

/****d* silcutil/SilcLogAPI/SILC_LOG_ERROR
 *
 * NAME
 *
 *    #define SILC_LOG_ERROR(...)
 *
 * DESCRIPTION
 *
 *    Wrapper to the ERROR logging channel.
 *    Please see the SILC_LOG_INFO macro.
 *
 * SEE ALSO
 *    SILC_LOG_INFO
 *
 * SOURCE
 */
#define SILC_LOG_ERROR(fmt) silc_log_output(SILC_LOG_ERROR, silc_format fmt)
/***/

/****d* silcutil/SilcLogAPI/SILC_LOG_FATAL
 *
 * NAME
 *
 *    #define SILC_LOG_FATAL(...)
 *
 * DESCRIPTION
 *
 *    Wrapper to the FATAL logging channel.
 *    Please see the SILC_LOG_INFO macro.
 *
 * SEE ALSO
 *    SILC_LOG_INFO
 *
 * SOURCE
 */
#define SILC_LOG_FATAL(fmt) silc_log_output(SILC_LOG_FATAL, silc_format fmt)
/***/

/****d* silcutil/SilcLogAPI/SILC_LOG_DEBUG
 *
 * NAME
 *
 *    #define SILC_LOG_DEBUG(...)
 *
 * DESCRIPTION
 *
 *    This is a special wrapper to the debugging output (usually stderr).
 *    The standard behaviour is the same as SILC_LOG_INFO, with the difference
 *    that this macro also depends on the global define SILC_DEBUG.
 *
 *    Undefining SILC_DEBUG causes these functions to be defined to an empty
 *    value, thus removing all debug logging calls from the compiled
 *    application.
 *
 * SOURCE
 */
#if defined(SILC_DEBUG)
#define SILC_LOG_DEBUG(fmt) silc_log_output_debug(__FILE__,	\
				__FUNCTION__,			\
				__LINE__,			\
				silc_format fmt)
#define SILC_NOT_IMPLEMENTED(string)					\
  SILC_LOG_INFO(("*********** %s: NOT IMPLEMENTED YET", string));
#else
#define SILC_LOG_DEBUG(fmt) do { } while(0)
#define SILC_NOT_IMPLEMENTED(string) do { } while(0)
#endif	/* SILC_DEBUG */
/***/

/****d* silcutil/SilcLogAPI/SILC_LOG_HEXDUMP
 *
 * NAME
 *
 *    #define SILC_LOG_HEXDUMP(...)
 *
 * DESCRIPTION
 *
 *    This is a special wrapper to the hexdump output function.  This macro
 *    behaves slightly differently from other logging wrappers.
 *    The first parameter, is composed by a group of parameters delimited by
 *    parenthesis.
 *    The second parameter is a `char *' pointer pointing to the beginning
 *    of the memory section that should be hexdumped, and the third parameter
 *    is the length of this memory section.
 *    Undefining the global SILC_DEBUG define causes these functions to be
 *    defined to an empty value, thus removing all debug logging calls from
 *    the compiled application.
 *    This macro is also affected by the global variable silc_debug_hexdump.
 *
 * EXAMPLE
 *
 *    SILC_LOG_HEXDUMP(("Outgoing packet [%d], len %d", pckt->seq, pckt->len),
 *                     pckt->data, pckt->datalen);
 *
 * SOURCE
 */
#if defined(SILC_DEBUG)
#define SILC_LOG_HEXDUMP(fmt, data, len) silc_log_output_hexdump(__FILE__, \
				__FUNCTION__,				   \
				__LINE__,				   \
				(void *)(data), (len),			   \
				silc_format fmt)
#else
#define SILC_LOG_HEXDUMP(fmt, data, len) do { } while(0)
#endif	/* SILC_DEBUG */
/***/

/****d* silcutil/SilcLogAPI/SILC_ASSERT
 *
 * NAME
 *
 *    #define SILC_ASSERT(experssion)
 *
 * DESCRIPTION
 *
 *    Assert macro that prints error message to stderr and calls abort()
 *    if the `expression' is false (ie. compares equal to zero).  If
 *    SILC_DEBUG is not defined this macro has no effect.
 *
 * SOURCE
 */
#if defined(SILC_DEBUG)
#define SILC_ASSERT(expr) assert((expr));
#else
#define SILC_ASSERT(expr) do { } while(0)
#endif /* SILC_DEBUG */
/***/

/****d* silcutil/SilcLogAPI/SILC_VERIFY
 *
 * NAME
 *
 *    #define SILC_VERIFY(experssion)
 *
 * DESCRIPTION
 *
 *    Verification macro that prints error message to stderr and calls 
 *    abort() if the `expression' is false (ie. compares equal to zero)
 *    on debug builds (SILC_DEBUG defined), and prints error message to
 *    stderr on release builds (SILC_DEBUG undefined) but does not abort().
 *    This macro is always compiled even if debugging (SILC_DEBUG) is not
 *    defined.
 *
 * SOURCE
 */
#if defined(SILC_DEBUG)
#define SILC_VERIFY(expr) assert((expr));
#else
#define SILC_VERIFY(expr)						\
  if (!(expr))								\
    SILC_LOG_ERROR(("SILC_VERIFY %s:%d", __FUNCTION__, __LINE__));
#endif /* SILC_DEBUG */
/***/

/* Prototypes */

/****f* silcutil/SilcLogAPI/silc_log_set_file
 *
 * SYNOPSIS
 *
 *    SilcBool silc_log_set_file(SilcLogType type, char *filename,
 *                           SilcUInt32 maxsize,
 *                           SilcSchedule scheduler);
 *
 * DESCRIPTION
 *
 *    Sets `filename', which can be maximum `maxsize' bytes long, as the new
 *    logging file for the channel `type'.  If you specify an illegal filename
 *    a warning message is printed and FALSE is returned.  In this case
 *    logging settings are not changed.
 *
 *    You can disable logging for a channel by specifying NULL filename, the
 *    maxsize in this case is not important.  The `scheduler' parameter is
 *    needed by the internal logging to allow buffered output and thus to
 *    save HD activity.
 *
 ***/
SilcBool silc_log_set_file(SilcLogType type, char *filename,
			   SilcUInt32 maxsize, SilcSchedule scheduler);

/****f* silcutil/SilcLogAPI/silc_log_get_file
 *
 * SYNOPSIS
 *
 *    char *silc_log_get_file(SilcLogType type);
 *
 * DESCRIPTION
 *
 *    Returns the current logging file for the channel `type'.
 *    If there has been an error during the opening of this channel, NULL
 *    is returned, even if the file has been previously set with
 *    silc_log_set_file().
 *
 *    The returned pointer points to internally allocated storage and must
 *    not be freed, modified or stored.
 *
 ***/
char *silc_log_get_file(SilcLogType type);

/****f* silcutil/SilcLogAPI/silc_log_set_callback
 *
 * SYNOPSIS
 *
 *    void silc_log_set_callback(SilcLogType type, SilcLogCb cb,
 *                               void *context);
 *
 * DESCRIPTION
 *
 *    Set `cb' as the default callback function for the logging channel
 *    `type'.  When SilcLog receives a message for this channel, it will
 *    trigger the callback function.  If the callback function returns TRUE
 *    SilcLog will assume the input as handled and won't run its default
 *    handler.
 *
 *    You can disable/remove a callback by setting it to NULL or calling the
 *    function silc_log_reset_callbacks.  If set, the callback function
 *    must be in the form described by SilcLogCb.
 *
 * SEE ALSO
 *    silc_log_reset_callbacks
 *
 ***/
void silc_log_set_callback(SilcLogType type, SilcLogCb cb, void *context);

/****f* silcutil/SilcLogAPI/silc_log_reset_callbacks
 *
 * SYNOPSIS
 *
 *    void silc_log_reset_callbacks();
 *
 * DESCRIPTION
 *
 *    Removes all logging callbacks for normal channels.  This function does
 *    NOT remove callbacks for debugging channels (debug and hexdump), you
 *    rather need to call silc_log_set_debug_callbacks() with NULL callbacks.
 *
 ***/
void silc_log_reset_callbacks(void);

/****f* silcutil/SilcLogAPI/silc_log_flush_all
 *
 * SYNOPSIS
 *
 *    void silc_log_flush_all();
 *
 * DESCRIPTION
 *
 *    Forces flushing for all logging channels.  This should be called for
 *    example after receiving special signals.
 *
 * SEE ALSO
 *    silc_log_quick
 *
 ***/
void silc_log_flush_all(void);

/****f* silcutil/SilcLogAPI/silc_log_reset_all
 *
 * SYNOPSIS
 *
 *    void silc_log_reset_all();
 *
 * DESCRIPTION
 *
 *    Forces all logging channels to close and reopen their streams.  Useful
 *    for example after a SIGHUP signal.
 *
 *    Please note that this function could generate some warning messages if
 *    one or more logging channels point to an illegal filename.
 *
 ***/
void silc_log_reset_all(void);

/****f* silcutil/SilcLogAPI/silc_log_set_debug_callbacks
 *
 * SYNOPSIS
 *
 *    void silc_log_set_debug_callbacks(SilcLogDebugCb debug_cb,
 *                                      void *debug_context,
 *                                      SilcLogHexdumpCb hexdump_cb,
 *                                      void *hexdump_context);
 *
 * DESCRIPTION
 *
 *    Sets `debug_cb' as the the default callback function for the debug
 *    output, that will be called with the `debug_context' parameter.
 *    When SilcLog receives a debug message, it will trigger the callback
 *    function.  If the callback function returns TRUE SilcLog will assume
 *    the input as handled and won't run its default handler.  The `hexdump_cb'
 *    and `hexdump_context' works the same way, except that they are referred
 *    to SILC_LOG_HEXDUMP requests.
 *
 *    You can disable/remove a callback by setting it to NULL.  If set, each
 *    callback function must be either in the form described by SilcLogDebugCb
 *    or SilcLogHexdumpCb.
 *
 ***/
void silc_log_set_debug_callbacks(SilcLogDebugCb debug_cb,
				  void *debug_context,
				  SilcLogHexdumpCb hexdump_cb,
				  void *hexdump_context);

/****f* silcutil/SilcLogAPI/silc_log_reset_debug_callbacks
 *
 * SYNOPSIS
 *
 *    void silc_log_reset_debug_callbacks();
 *
 * DESCRIPTION
 *
 *    Resets debug callbacks set with silc_log_set_debug_callbacks.
 *
 ***/
void silc_log_reset_debug_callbacks(void);

/****f* silcutil/SilcLogAPI/silc_log_set_debug_string
 *
 * SYNOPSIS
 *
 *    void silc_log_set_debug_string(const char *debug_string);
 *
 * DESCRIPTION
 *
 *    Sets `debug_string' as the regexp string for filtering debugging
 *    output.  The string is copied and it can be modified/destroyed after
 *    this function call.
 *
 ***/
void silc_log_set_debug_string(const char *debug_string);

/****f* silcutil/SilcLogAPI/silc_log_timestamp
 *
 * NAME
 *
 *    void silc_log_timestamp(SilcBool enable);
 *
 * DESCRIPTION
 *
 *    Use timestamp in log messages.  Set `enable' to TRUE to enable
 *    timestamp and to FALSE to disable it.  Default is TRUE.
 *
 ***/
void silc_log_timestamp(SilcBool enable);

/****f* silcutil/SilcLogAPI/silc_log_flushdelay
 *
 * NAME
 *
 *    void silc_log_flushdelay(SilcUInt32 flushdelay);
 *
 * DESCRIPTION
 *
 *    Sets the logfiles flushing delay in seconds.  Default is 300 seconds.
 *
 ***/
void silc_log_flushdelay(SilcUInt32 flushdelay);

/****f* silcutil/SilcLogAPI/silc_log_quick
 *
 * NAME
 *
 *    void silc_log_quick(SilcBool enable);
 *
 * DESCRIPTION
 *
 *    SilcLog makes use of libc stream buffering output, which means that it
 *    saves HD activity by buffering the logging messages and writing them
 *    all together every some minutes (default is 5 minutes).
 *
 *    Setting `enable' to TRUE will force SilcLog to write messages to the
 *    filesystem as soon as they are received. This increases the CPU activity
 *    notably on bigger servers, but reduces memory usage.
 *
 *    If you want to change the logging style on-the-fly, make sure to call
 *    silc_log_flush_all() after setting `enable'  to TRUE.
 *
 *    Default is FALSE.
 *
 ***/
void silc_log_quick(SilcBool enable);

/****v* silcutil/SilcLogAPI/silc_log_debug
 *
 * NAME
 *
 *    void silc_log_debug(SilcBool enable);
 *
 * DESCRIPTION
 *
 *    If `enable' is set to FALSE, debugging functions won't procude any
 *    output and if set to TRUE prints debug messages to stderr.  Default
 *    is FALSE.
 *
 * SEE ALSO
 *    SILC_LOG_DEBUG
 *
 ***/
void silc_log_debug(SilcBool enable);

/****v* silcutil/SilcLogAPI/silc_log_debug_hexdump
 *
 * NAME
 *
 *    void silc_log_debug_hexdump(SilcBool enable);
 *
 * DESCRIPTION
 *
 *    If `enable' is set to FALSE, debugging functions won't produce
 *    any output anf if set to TRUE prints hexdump debug message to
 *    stderr.  Default is FALSE.
 *
 * SEE ALSO
 *    SILC_LOG_HEXDUMP
 *
 ***/
void silc_log_debug_hexdump(SilcBool enable);

#endif	/* !SILCLOG_H */
