common/logger.h (131 lines of code) (raw):
#pragma once
#include <string>
#include <chrono>
#include <atomic>
#include <map>
#include <memory>
#include <thread>
#include <mutex>
#include <functional>
#include "concurrentmap.h"
#include "selectableevent.h"
namespace swss {
#define SWSS_LOG_ERROR(MSG, ...) swss::Logger::getInstance().write(swss::Logger::SWSS_ERROR, ":- %s: " MSG, __FUNCTION__, ##__VA_ARGS__)
#define SWSS_LOG_WARN(MSG, ...) swss::Logger::getInstance().write(swss::Logger::SWSS_WARN, ":- %s: " MSG, __FUNCTION__, ##__VA_ARGS__)
#define SWSS_LOG_NOTICE(MSG, ...) swss::Logger::getInstance().write(swss::Logger::SWSS_NOTICE, ":- %s: " MSG, __FUNCTION__, ##__VA_ARGS__)
#define SWSS_LOG_INFO(MSG, ...) swss::Logger::getInstance().write(swss::Logger::SWSS_INFO, ":- %s: " MSG, __FUNCTION__, ##__VA_ARGS__)
#define SWSS_LOG_DEBUG(MSG, ...) swss::Logger::getInstance().write(swss::Logger::SWSS_DEBUG, ":- %s: " MSG, __FUNCTION__, ##__VA_ARGS__)
#define SWSS_LOG_ENTER() swss::Logger::ScopeLogger logger ## __LINE__ (__LINE__, __FUNCTION__)
#define SWSS_LOG_TIMER(msg, ...) swss::Logger::ScopeTimer scopetimer ## __LINE__ (__LINE__, __FUNCTION__, msg, ##__VA_ARGS__)
#define SWSS_LOG_THROW(MSG, ...) swss::Logger::getInstance().wthrow(swss::Logger::SWSS_ERROR, ":- %s: " MSG, __FUNCTION__, ##__VA_ARGS__)
static constexpr const char * const DAEMON_LOGLEVEL = "LOGLEVEL";
static constexpr const char * const DAEMON_LOGOUTPUT = "LOGOUTPUT";
void err_exit(const char *fn, int ln, int e, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 4, 5)))
__attribute__ ((noreturn))
#endif
;
#define ABORT_IF_NOT(x, fmt, args...) \
if (!(x)) { \
int e = errno; \
err_exit(__FUNCTION__, __LINE__, e, (fmt), ##args); \
}
#ifdef __GNUC__
# define ATTRIBUTE_NORTEURN __attribute__ ((noreturn))
#else
# define ATTRIBUTE_NORTEURN
#endif
class Logger
{
public:
enum Priority
{
SWSS_EMERG,
SWSS_ALERT,
SWSS_CRIT,
SWSS_ERROR,
SWSS_WARN,
SWSS_NOTICE,
SWSS_INFO,
SWSS_DEBUG
};
typedef std::map<std::string, Priority> PriorityStringMap;
static const PriorityStringMap priorityStringMap;
typedef std::function<void (std::string component, std::string prioStr)> PriorityChangeNotify;
enum Output
{
SWSS_SYSLOG,
SWSS_STDOUT,
SWSS_STDERR
};
typedef std::map<std::string, Output> OutputStringMap;
static const OutputStringMap outputStringMap;
typedef std::function<void (std::string component, std::string outputStr)> OutputChangeNotify;
static Logger& getInstance();
static void setMinPrio(Priority prio);
static Priority getMinPrio();
static void linkToDbWithOutput(
const std::string& dbName,
const PriorityChangeNotify& prioNotify,
const std::string& defPrio,
const OutputChangeNotify& outputNotify,
const std::string& defOutput);
static void linkToDb(const std::string& dbName, const PriorityChangeNotify& notify, const std::string& defPrio);
// Must be called after all linkToDb to start select from DB
static void linkToDbNative(const std::string& dbName, const char * defPrio="NOTICE");
static void restartLogger();
void write(Priority prio, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 3, 4)))
#endif
;
void wthrow(Priority prio, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 3, 4)))
__attribute__ ((noreturn))
#endif
;
static std::string priorityToString(Priority prio);
static std::string outputToString(Output output);
static void swssOutputNotify(const std::string& component, const std::string& outputStr);
class ScopeLogger
{
public:
ScopeLogger(int line, const char *fun);
~ScopeLogger();
private:
const int m_line;
const char *m_fun;
};
class ScopeTimer
{
typedef std::chrono::duration<double, std::ratio<1>> second_t;
public:
ScopeTimer(int line, const char* fun, const char *msg, ...);
~ScopeTimer();
private:
const int m_line;
const char *m_fun;
std::string m_msg;
std::chrono::time_point<std::chrono::high_resolution_clock> m_start;
};
private:
Logger() = default;
~Logger();
Logger(const Logger&);
Logger& operator=(const Logger&);
static void swssPrioNotify(const std::string& component, const std::string& prioStr);
void settingThread();
void terminateSettingThread();
void restartSettingThread();
typedef ConcurrentMap<std::string, std::pair<PriorityChangeNotify, OutputChangeNotify>> LogSettingChangeObservers;
LogSettingChangeObservers m_settingChangeObservers;
ConcurrentMap<std::string, std::string> m_currentPrios;
std::atomic<Priority> m_minPrio = { SWSS_NOTICE };
ConcurrentMap<std::string, std::string> m_currentOutputs;
std::atomic<Output> m_output = { SWSS_SYSLOG };
std::unique_ptr<std::thread> m_settingThread;
std::mutex m_mutex;
std::unique_ptr<SelectableEvent> m_stopEvent;
};
}