/*------------------------------------------------------------------------------
 *
 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
 * The YADIFA TM software product is provided under the BSD 3-clause license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *        * Redistributions in binary form must reproduce the above copyright
 *          notice, this list of conditions and the following disclaimer in the
 *          documentation and/or other materials provided with the distribution.
 *        * Neither the name of EURid nor the names of its contributors may be
 *          used to endorse or promote products derived from this software
 *          without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *------------------------------------------------------------------------------
 *
 */

/** @defgroup logger Logging functions
 *  @ingroup dnscore
 *  @brief 
 *
 *  
 *
 * @{
 *
 *----------------------------------------------------------------------------*/
#ifndef _LOGGER_HANDLE_H
#define	_LOGGER_HANDLE_H

#include <syslog.h>
#include <sys/socket.h>

#define LOGGER_EARLY_CULL 1

#include <dnscore/thread.h>
#include <dnscore/thread-tag.h>
#include <dnscore/ptr_vector.h>
#include <dnscore/format.h>

/*
 * Basically a copy from syslog
 */

#define MSG_EMERG      0   /* system is unusable                      */
#define MSG_ALERT      1   /* action must be taken immediately        */
#define MSG_CRIT       2   /* critical conditions                     */
#define MSG_ERR        3   /* error conditions                        */
#define MSG_WARNING    4   /* warning conditions                      */
#define MSG_NOTICE     5   /* normal, but significant, condition      */
#define MSG_INFO       6   /* informational message                   */
#define MSG_DEBUG      7   /* debug-level message                     */
#define MSG_DEBUG1     8   /* debug-level message                     */
#define MSG_DEBUG2     9   /* debug-level message                     */
#define MSG_DEBUG3     10  /* debug-level message                     */
#define MSG_DEBUG4     11  /* debug-level message                     */
#define MSG_DEBUG5     12  /* debug-level message                     */
#define MSG_DEBUG6     13  /* debug-level message                     */
#define MSG_DEBUG7     14  /* debug-level message                     */

#define MSG_ALL        15   /* all message levels                     */
#define MSG_ALL_MASK   0xffff  /// all message levels as a bitmap
#define MSG_PROD_MASK  0x007f  /// non-debug message levels as a bitmap
#define MSG_WARN_MASK  0x001f  /// warnings and worse messages levels as a bitmap


#define MSG_LEVEL_COUNT 16

/**
 * The default buffer size (0-cost) made available for each line.
 * If the line is bigger the buffer's size is raised at a certain (non-nul)
 * cost.
 *
 */

#define DEFAULT_MAX_LINE_SIZE	128

#define LOG_QUEUE_MIN_SIZE              0x00000400              //  1K
#define LOG_QUEUE_MAX_SIZE              0x01000000              // 16M
#define LOG_QUEUE_DEFAULT_SIZE          0x00100000              //  1M

#define HAS_SHARED_QUEUE_SUPPORT 1      // must be 1

#ifdef	__cplusplus
extern "C"
{
#endif

/**
 * Handle
 */
    
typedef ptr_vector logger_channel_array;

struct logger_channel;

typedef struct logger_handle logger_handle;

#if DEBUG
#define LOGGER_HANDLE_MAGIC_CHECK 0x11332244
#endif

#define LOGGER_HANDLE_NAME_SIZE_MAX 16
#define LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX 8

#define LOGGER_REPEAT_COMPRESSION 1

struct logger_handle // ~ 5 * 64
{
    u8 active[MSG_LEVEL_COUNT]; // 16 /// @note 20200818 edf -- I know what I always say about layout.  This is an exception.  Keep it first.
    logger_channel_array channels[MSG_LEVEL_COUNT]; // 256
    char name[LOGGER_HANDLE_NAME_SIZE_MAX]; // 16
    char formatted_name[LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX + 1]; // 8 + 1
    bool enabled; // 1
    // I expect 6 padding bytes here
    struct logger_handle **global_reference; // 8
#if DEBUG
    u32 magic_check;
#endif
};

#if LOGGER_EARLY_CULL
extern struct logger_handle LOGGER_HANDLE_SINK_;
#define LOGGER_HANDLE_SINK (&LOGGER_HANDLE_SINK_)
#else
#define LOGGER_HANDLE_SINK NULL
#endif

/**
 * Channel
 */

struct logger_channel_vtbl;
struct logger_message;

struct logger_channel
{
    void *data;
    const struct logger_channel_vtbl *vtbl;
#if LOGGER_REPEAT_COMPRESSION
    struct logger_message *last_message;
    u32 last_message_count;
#endif
    s32 linked_handles;
};

typedef struct logger_channel logger_channel;

typedef ya_result logger_channel_constmsg_method(logger_channel* chan, int level, char* text, u32 text_len, u32 date_offset);
typedef ya_result logger_channel_msg_method(logger_channel* chan, int level, char* text, ...);
typedef ya_result logger_channel_vmsg_method(logger_channel* chan, int level, char* text, va_list args);
typedef void logger_channel_flush_method(logger_channel* chan);
typedef void logger_channel_close_method(logger_channel* chan);
typedef ya_result logger_channel_reopen_method(logger_channel* chan);
typedef void logger_channel_sink_method(logger_channel* chan);

typedef struct logger_channel_vtbl logger_channel_vtbl;

struct logger_channel_vtbl
{
    logger_channel_constmsg_method *constmsg;
    logger_channel_msg_method *msg;
    logger_channel_vmsg_method *vmsg;
    logger_channel_flush_method *flush;
    logger_channel_close_method *close;
    logger_channel_reopen_method *reopen;   // so a HUP will flush, close then reopen/create the log files again
    logger_channel_sink_method *sink;       // the channel will verify its output make sense and if not act on it (ie: junk all until next reopen)
    const char *__class__;
};

#define logger_channel_msg(channel_,level_,text_, text_len_, date_offs_) (channel_)->vtbl->constmsg((channel_),(level_),(text_),(text_len_),(date_offs_))
#define logger_channel_msgf(channel_,level_,text_, ...) (channel_)->vtbl->msg((channel_),(level_),(text_),__VA_ARGS__)
#define logger_channel_vmsgf(channel_,level_,text_, args_) (channel_)->vtbl->msg((channel_),(level_),(text_),(args_))
#define logger_channel_flush(channel_) (channel_)->vtbl->flush(channel_)
#define logger_channel_reopen(channel_) (channel_)->vtbl->reopen(channel_)
#define logger_channel_close(channel_) (channel_)->vtbl->close(channel_)
#define logger_channel_sink(channel_) (channel_)->vtbl->sink(channel_)

/**
 * Message flags
 */

#define LOGGER_MESSAGE_STD      0
#define LOGGER_MESSAGE_TIMEMS   1
#define LOGGER_MESSAGE_PREFIX   2

/**
 * Allocates an empty channel
 * Meant to be used by channels implementation
 */

logger_channel* logger_channel_alloc();

/**
 * Returns true iff the current thread is the logger.
 * 
 * @return true iff the current thread is the logger.
 */

bool logger_is_self();

/**
 * Returns TRUE if the queue is half full
 * 
 * @param channel_name
 * @return 
 */

bool logger_queue_fill_critical();

s32 logger_channel_get_usage_count(const char* channel_name);
void logger_channel_register(const char* channel_name, struct logger_channel *channel);
void logger_channel_unregister(const char* channel_name);

void logger_channel_close_all();

void logger_handle_create(const char *logger_name, logger_handle **handle_holder);
void logger_handle_add_channel(const char* logger_name, int level, const char* channel_name);
void logger_handle_remove_channel(const char *logger_name, const char *channel_name);
s32 logger_handle_count_channels(const char *logger_name);
void logger_handle_close(const char *logger_name);

/**
 * 
 * Helper function.
 * Creates a logger for the given file descriptor (typically 1/stdout or 2/stderr)
 * 
 * ie: logger_handle_create_to_fd("system", MSG_ALL_MASK, 1);
 * 
 * @param logger_name name of the logger
 * @param mask the mask to use (ie: MSG_ALL_MASK)
 * @param fd the file descriptor
 */

void logger_handle_create_to_fd(const char *logger_name, int mask, int fd);

static inline void logger_handle_create_to_stdout(const char *logger_name, int mask)
{
    logger_handle_create_to_fd(logger_name, mask, 1);
}

/**
 * 
 * Sends a formatted text to the logger
 * 
 * @param handle        handle to use, can be NULL
 * @param level         level of the message
 * @param fmt           format string
 * @param args          parameters for the format
 */

void logger_handle_vmsg(logger_handle* handle, u32 level, const char* fmt, va_list args);

/**
 * 
 * Sends a formatted text to the logger
 * 
 * @param handle        handle to use, can be NULL
 * @param level         level of the message
 * @param fmt           format string
 * @param ...           parameters for the format
 */

void logger_handle_msg(logger_handle* handle, u32 level, const char* fmt, ...);

void logger_handle_msg_nocull(logger_handle* handle, u32 level, const char* fmt, ...);

/**
 * 
 * Sends a text to the logger
 * 
 * @param handle        handle to use, can be NULL
 * @param level         level of the message
 * @param text          text to send
 * @param text_len      length of the text to send
 */

void logger_handle_msg_text(logger_handle *handle, u32 level, const char* text, u32 text_len);

/**
 * 
 * Sends a text to the logger with a prefix
 * 
 * @param handle        handle to use, can be NULL
 * @param level         level of the message
 * @param text          text to send
 * @param text_len      text length
 * @param prefix        prefix
 * @param prefix_len    prefix length
 * @param flags         LOGGER_MESSAGE_* flags
 */

void logger_handle_msg_text_ext(logger_handle *handle, u32 level, const char* text, u32 text_len, const char* prefix, u32 prefix_len, u16 flags);

/**
 * Try to send a formatted text to the logger.
 * If the logging queue is full, drop the line.
 * This is to be used only in parts of code that would be dead-locked with the
 * logger in case of a full disk.
 * 
 * ie: anything on the path of the HUP signal handling.
 * 
 * @param handle        handle to use, can be NULL
 * @param level         level of the message
 * @param fmt           format string
 * @param ...           parameters for the format
 */

void logger_handle_try_msg(logger_handle* handle, u32 level, const char* fmt, ...);

/**
 * Try to send a formatted text to the logger.
 * If the logging queue is full, drop the line.
 * This is to be used only in parts of code that would be dead-locked with the
 * logger in case of a full disk.
 * 
 * ie: anything on the path of the HUP signal handling.
 * 
 * @param handle        handle to use, can be NULL
 * @param level         level of the message
 * @param text          text to send
 * @param text_len      length of the text to send
 */

void logger_handle_try_msg_text(logger_handle *handle, u32 level, const char* text, u32 text_len);


/**
 * Sets the layout for the logged memory dumps
 * Values MUST be set to (2^n)-1 with n >= 0
 * Values MUST be < 256
 * 
 * @param group_mask        The mask to group the bytes together (ie: 3 for making groups of 4)
 * @param separator_mask    the mask to put a space separator every few bytes (ie: 3 for every 4 bytes)
 * 
 */

void log_memdump_set_layout(u32 group_mask, u32 separator_mask);

/**
 * Dumps memory in to the logger
 * 
 * @param hndl          handle to use, can be NULL
 * @param level         level of the message
 * @param data_pointer  memory to dump
 * @param size          size of the memory to dump
 * @param line_size     length of a line
 * @param flags         see osprint_dump for details: OSPRINT_DUMP_ADDRESS, OSPRINT_DUMP_HEX, OSPRINT_DUMP_TEXT
 */

void log_memdump_ex(logger_handle* hndl, u32 level, const void* data_pointer, ssize_t size, ssize_t line_size, u32 flags);
void log_memdump(logger_handle* hndl, u32 level, const void* data_pointer, ssize_t size, ssize_t line_size);

void log_msghdr(logger_handle* hndl, u32 level, struct msghdr *hdr);

void logger_handle_exit_level(u32 level);

void logger_handle_finalize();

void logger_set_level(u8 level);

#if DNSCORE_HAS_LOG_THREAD_TAG

void logger_handle_set_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid, const char tag[THREAD_TAG_SIZE]);
void logger_handle_clear_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid);
void logger_handle_set_thread_tag(const char tag[THREAD_TAG_SIZE]);
void logger_handle_clear_thread_tag();

#else

static inline void logger_handle_set_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid, const char tag[1])
{
    (void)pid;
    (void)tid;
    (void)tag;
}

static inline void logger_handle_clear_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid)
{
    (void)pid;
    (void)tid;
}

static inline void logger_handle_set_thread_tag(const char tag[1])
{
    (void)tag;
}

static inline void logger_handle_clear_thread_tag()
{
}

#endif


#define LOG_MEMDUMP_LAYOUT_DENSE 0xff,0xff
#define LOG_MEMDUMP_LAYOUT_ERIC 3,0xff
#define LOG_MEMDUMP_LAYOUT_GERY 0,3
    
/*
 * GCC style :
 *
 * #define debug(vararg...) logger_handle_msg(NULL,MSG_DEBUG,vararg)
 *
 * C99 style :
 *
 * #define debug(...) logger_handle_msg(NULL,MSG_DEBUG,__VA_ARGS__)
 *
 */

#if defined(MODULE_MSG_HANDLE)
    #define debug(...)  logger_handle_msg((MODULE_MSG_HANDLE),MSG_DEBUG,__VA_ARGS__)
#else
    #define debug(...)  logger_handle_msg(NULL,MSG_DEBUG,__VA_ARGS__)
#endif

/**
 * LOG_TEXT_PREFIX is a text constant that will be prefixed to every text logged in the current source file.
 * It is a constant that MUST be set before including logger_handle.h (or any logger header)
 */

#if !defined(LOG_TEXT_PREFIX)
#define LOG_TEXT_PREFIX
#endif

#if LOGGER_EARLY_CULL

// #define LOGGER_EARLY_CULL_PREFIX(__MSGLEVEL__) if(MODULE_MSG_HANDLE->channels[__MSGLEVEL__].offset >= 0)
// if(MODULE_MSG_HANDLE->channels[__MSGLEVEL__].offset >= 0)
// ptr +              k1 + level * k2 + k3
// if(table[MODULE_MSG_INDEX].channel[__MSGLEVEL__].offset >= 0
// ptr + index * k0 + k1 + level * k2 + k3
//
// proposed optimisation:
// ptr + level <- choosen one (obviously)
// ptr + index * k0 + level
// note: k0 = 64, k1 = 0, k2 = 16
// if index = index * k0, it's still one addition that could be removed
// if channel cannot be destroyed once created but only disabled, setting the ptr once is enough
// it still means children must be spawned after the channels are setup
// I don't see this as a problem as channel names are hard-coded in the binaries
//

#define LOGGER_EARLY_CULL_PREFIX(__MSGLEVEL__) if(MODULE_MSG_HANDLE->active[__MSGLEVEL__] != 0)

static inline bool log_is_set(logger_handle* handle, int level)
{
    return (handle != NULL) && (handle->channels[level].offset >= 0);
}

#define log_debug7(...) LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG7) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG7,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug6(...) LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG6) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG6,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug5(...) LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG5) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG5,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug4(...) LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG4) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG4,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug3(...) LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG3) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG3,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug2(...) LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG2) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG2,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug1(...) LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG1) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG1,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug(...)  LOGGER_EARLY_CULL_PREFIX(MSG_DEBUG) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_DEBUG,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_notice(...) LOGGER_EARLY_CULL_PREFIX(MSG_NOTICE) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_NOTICE,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_info(...)   LOGGER_EARLY_CULL_PREFIX(MSG_INFO) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_INFO,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_warn(...)   LOGGER_EARLY_CULL_PREFIX(MSG_WARNING) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_WARNING,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_err(...)    LOGGER_EARLY_CULL_PREFIX(MSG_ERR) logger_handle_msg_nocull(MODULE_MSG_HANDLE,MSG_ERR,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_to_level(level_,...)    LOGGER_EARLY_CULL_PREFIX((level_)) logger_handle_msg_nocull(MODULE_MSG_HANDLE,(level_),LOG_TEXT_PREFIX __VA_ARGS__)

#define log_try_debug7(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG7,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug6(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG6,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug5(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG5,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug4(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG4,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug3(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG3,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug2(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG2,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug1(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG1,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug(...)  logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_notice(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_NOTICE,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_info(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_INFO,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_warn(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_WARNING,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_err(...)    logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_ERR,LOG_TEXT_PREFIX __VA_ARGS__)
/* Obsolete, Critical error: quit */
#define log_try_quit(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_CRIT,LOG_TEXT_PREFIX __VA_ARGS__)
/* Critical error: quit */
#define log_try_crit(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_CRIT,LOG_TEXT_PREFIX __VA_ARGS__)
/* Emergency: quit      */
#define log_try_emerg(...)  logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_EMERG,LOG_TEXT_PREFIX __VA_ARGS__)
#else
#define log_debug7(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG7,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug6(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG6,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug5(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG5,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug4(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG4,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug3(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG3,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug2(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG2,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug1(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG1,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_debug(...)  logger_handle_msg(MODULE_MSG_HANDLE,MSG_DEBUG,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_notice(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_NOTICE,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_info(...)   logger_handle_msg(MODULE_MSG_HANDLE,MSG_INFO,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_warn(...)   logger_handle_msg(MODULE_MSG_HANDLE,MSG_WARNING,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_err(...)    logger_handle_msg(MODULE_MSG_HANDLE,MSG_ERR,LOG_TEXT_PREFIX __VA_ARGS__)

#define log_try_debug7(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG7,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug6(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG6,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug5(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG5,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug4(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG4,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug3(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG3,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug2(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG2,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug1(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG1,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_debug(...)  logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_DEBUG,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_notice(...) logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_NOTICE,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_info(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_INFO,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_warn(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_WARNING,LOG_TEXT_PREFIX __VA_ARGS__)
#define log_try_err(...)    logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_ERR,LOG_TEXT_PREFIX __VA_ARGS__)
#endif

/* Obsolete, Critical error: quit */
#define log_quit(...)   logger_handle_msg(MODULE_MSG_HANDLE,MSG_CRIT,LOG_TEXT_PREFIX __VA_ARGS__)
/* Critical error: quit */
#define log_crit(...)   logger_handle_msg(MODULE_MSG_HANDLE,MSG_CRIT,LOG_TEXT_PREFIX __VA_ARGS__)
/* Emergency: quit      */
#define log_emerg(...)  logger_handle_msg(MODULE_MSG_HANDLE,MSG_EMERG,LOG_TEXT_PREFIX __VA_ARGS__)

/* Obsolete, Critical error: quit */
#define log_try_quit(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_CRIT,LOG_TEXT_PREFIX __VA_ARGS__)
/* Critical error: quit */
#define log_try_crit(...)   logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_CRIT,LOG_TEXT_PREFIX __VA_ARGS__)
/* Emergency: quit      */
#define log_try_emerg(...)  logger_handle_try_msg(MODULE_MSG_HANDLE,MSG_EMERG,LOG_TEXT_PREFIX __VA_ARGS__)

/* -7----------------------------------------------------------------------------
 *
 *      MACROS
 */

#if DEBUG
#define DERROR_MSG(...) logger_handle_msg(MODULE_MSG_HANDLE,MSG_ERR,__VA_ARGS__)
#else
#define DERROR_MSG(...)   /* nothing */
#endif /* DEBUG */

/**
 * For practical reasons, the code for logger_init() is in logger_handle.c
 */

void logger_init();

void logger_init_ex(u32 queue_size, size_t shared_heap_size);

/**
 * For practical reasons, the code for logger_start() is in logger_handle.c
 */

void logger_start();
void logger_start_server();
void logger_stop_server();
void logger_start_client();
void logger_stop_client();

u8 logger_set_shared_heap(u8 id);

/**
 * For practical reasons, the code for logger_stop() is in logger_handle.c
 */

void logger_stop();

/**
 * For practical reasons, the code for logger_finalize() is in logger_handle.c
 */

void logger_finalize();

/**
 * For practical reasons, the code for logger_flush() is in logger_handle.c
 */

void logger_flush();

/**
 * The next message seen by the logger will trigger a sink.
 */

void logger_sink_noblock();

/**
 * Asks all channels to verify their output is valid and if not, to discard
 * all content to a sink until reopen is called.
 */

void logger_sink();

/**
 * For practical reasons, the code for logger_reopen() is in logger_handle.c
 */

void logger_reopen();

bool logger_is_running();

/**
 * Sets the logger queue size
 */

u32  logger_set_queue_size(u32 n);

void logger_set_path(const char *path);
const char* logger_get_path();

void  logger_release_ownership();
void  logger_take_ownership(pid_t new_owner);

void logger_set_uid(uid_t uid);
uid_t logger_get_uid();

void logger_set_gid(uid_t gid);
gid_t logger_get_gid();

/**
 * Polls for the state of the logger.
 * Made for a specific task.
 * Use with care, or not at all.
 */

bool logger_wait_started();

#ifdef	__cplusplus
}
#endif

#endif	/* _LOGGER_HANDLE_H */
/** @} */
