/**
 * @file SMLog.hpp
 * @author Schlund + Partner AG
 * @brief Syslog Macro Log: Simple logging based on compiler macros and syslog(3)
 *
 * Synopsis:
 * @code
 * #include <ui-utilcpp/SMLog.hpp>
 * @endcode
 *
 * Each prirority level (see syslog(3)) gets its own compiler macro, which can be used
 * rather straightforward in the source; the argument of the macro may include stream piping.
 * For example:
 *
 * SM_LOGNOTICE("I have noticed something: " << something)
 *
 * Logs can be turned off at compile time (giving full run time advantage, as the code is removed)
 * with a threshold. Additionally, you can give the facility, and additional text at compile time.
 * For example:
 *
 * c++ ... -DSM_LOGLEVEL=5 -DSM_LOGADD="getpid()" -DSM_LOGFACILITY="ost::SLOG_USER"
 *
 * eliminates all log messages with priority higher than 5, giving the process id as additional
 * information
 *
 * Logging itself is done CommonC++'s Slog. It is common to make the following
 * configuration (Note: currently, the facility must be given when compiling):
 *
 *  ost::slog.open(LOGPREFIX, FACILITY);  // Set prefix and syslog(3) facility.
 *
 *  ost::slog.clogEnable(true);           // En- or disable logging to "clog"
 *
 * levels as defined in syslog(3).
 *
 * The log strings automatically get several additional information, like source file name,
 * line number, process id, etc.
 *
 */

/** @example SMLog.cpp
 *
 * Example showing log messages in all levels.  Should be installed as
 * ui-utilcpp-smlog along with the library.
 */

#ifndef UI_UTIL_SMLOG_HPP
#define UI_UTIL_SMLOG_HPP

// STDC++
#include <iostream>

// SYSTEM C
#include <syslog.h>

// C++ Libraries
#include <commoncpp/slog.h>


#ifndef SM_LOGLEVEL
/** @brief The Log Level; Log code under this level gets eliminated. */
#define SM_LOGLEVEL LOG_NOTICE
#endif

#ifndef SM_LOGADD
/** @brief Add this text to every log messages. */
#define SM_LOGADD __FILE__ << ":" << __LINE__
#endif

#ifndef SM_LOGFACILITY
/** @brief The Log Facility.
 *
 * Normally, it should be enough to configure this once via slog.open(); however,
 * there is no really functional "<<(level)" method in Slog, while the "<<(level, facility)" method
 * works fine.
 */
#define SM_LOGFACILITY ost::Slog::classDaemon
#endif

#ifndef SM_LOG
/**
 * @def SM_LOG(l, x)
 *
 * Master Macro (must not be used directly).
 */
#ifdef SM_ENABLE_CLOG
#define SM_LOG(l, p, x) { ost::slog(l, SM_LOGFACILITY) << p << ": " << x << " [" SM_LOGADD << "]." << std::endl; std::clog << p << ": " << x << " [" SM_LOGADD << "]." << std::endl; }
#else
#define SM_LOG(l, p, x) ost::slog(l, SM_LOGFACILITY) << p << ": " << x << " [" SM_LOGADD << "]." << std::endl
#endif
#endif

/** @brief Macro for syslog(3) level EMERG. */
#if SM_LOGLEVEL >= LOG_EMERG
#define SM_LOGEMERG(x) SM_LOG(ost::Slog::levelEmergency, "EMG", x)
#else
#define SM_LOGEMERG(x)
#endif

/** @brief Macro for syslog(3) level ALERT. */
#if SM_LOGLEVEL >= LOG_ALERT
#define SM_LOGALERT(x) SM_LOG(ost::Slog::levelAlert, "ALT", x)
#else
#define SM_LOGALERT(x)
#endif

/** @brief Macro for syslog(3) level CRIT. */
#if SM_LOGLEVEL >= LOG_CRIT
#define SM_LOGCRIT(x) SM_LOG(ost::Slog::levelCritical, "CRT", x)
#else
#define SM_LOGCRIT(x)
#endif

/** @brief Macro for syslog(3) level ERR. */
#if SM_LOGLEVEL >= LOG_ERR
#define SM_LOGERR(x) SM_LOG(ost::Slog::levelError, "ERR", x)
#else
#define SM_LOGERR(x)
#endif

/** @brief Macro for syslog(3) level WARNING. */
#if SM_LOGLEVEL >= LOG_WARNING
#define SM_LOGWARNING(x) SM_LOG(ost::Slog::levelWarning, "WRN", x)
#else
#define SM_LOGWARNING(x)
#endif

/** @brief Macro for syslog(3) level NOTICE. */
#if SM_LOGLEVEL >= LOG_NOTICE
#define SM_LOGNOTICE(x) SM_LOG(ost::Slog::levelNotice, "ntc", x)
#else
#define SM_LOGNOTICE(x)
#endif

/** @brief Macro for syslog(3) level INFO. */
#if SM_LOGLEVEL >= LOG_INFO
#define SM_LOGINFO(x) SM_LOG(ost::Slog::levelInfo, "inf", x)
#else
#define SM_LOGINFO(x)
#endif

/** @brief Macro for syslog(3) level DEBUG. */
#if SM_LOGLEVEL >= LOG_DEBUG
#define SM_LOGDEBUG(x) SM_LOG(ost::Slog::levelDebug, "dbg", x)
#else
#define SM_LOGDEBUG(x)
#endif

/** @name Additional debug levels 8-11.
 * @{ */
#if SM_LOGLEVEL >= 8
#define SM_LOGDEBUG1(x) SM_LOGDEBUG(x)
#else
#define SM_LOGDEBUG1(x)
#endif

#if SM_LOGLEVEL >= 9
#define SM_LOGDEBUG2(x) SM_LOGDEBUG(x)
#else
#define SM_LOGDEBUG2(x)
#endif

#if SM_LOGLEVEL >= 10
#define SM_LOGDEBUG3(x) SM_LOGDEBUG(x)
#else
#define SM_LOGDEBUG3(x)
#endif

#if SM_LOGLEVEL >= 11
#define SM_LOGDEBUG4(x) SM_LOGDEBUG(x)
#else
#define SM_LOGDEBUG4(x)
#endif
/** @} */

#endif
