// ----------------------------------------------------------------------
// File: Logging.hh
// Author: Andreas-Joachim Peters - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2011 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
/**
* @file Logging.hh
*
* @brief Class for message logging.
*
* You can use this class without creating an instance object (it provides a
* global singleton). All the 'eos_' functions require that the logging
* class inherits from the 'LogId' class. As an alternative as set of static
* 'eos_static_' logging functinos are provided. To define the log level
* one uses the static 'SetLogPriority' function. 'SetFilter' allows to filter
* out log messages which are identified by their function/method name
* (__FUNCTION__). If you prefix this comma seperated list with 'PASS:' it is
* used as an acceptance filter. By default all logging is printed to 'stderr'.
* You can arrange a log stream filter fan-out using 'AddFanOut'. The fan-out of
* messages is defined by the source filename the message comes from and mappes
* to a FILE* where the message is written. If you add a '*' fan-out you can
* write all messages into this file. If you add a '#' fan-out you can write
* all messages which are not in any other fan-out (besides '*') into that file.
* The fan-out functionality assumes that
* source filenames follow the pattern .xx !!!!
*/
#ifndef __EOSCOMMON_LOGGING_HH__
#define __EOSCOMMON_LOGGING_HH__
#include "common/Namespace.hh"
#include "common/Mapping.hh"
#include "XrdOuc/XrdOucHash.hh"
#include "XrdOuc/XrdOucString.hh"
#include "XrdSys/XrdSysPthread.hh"
#include "XrdSec/XrdSecEntity.hh"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SSTR(message) static_cast(std::ostringstream().flush() << message).str()
EOSCOMMONNAMESPACE_BEGIN
#define EOS_TEXTNORMAL "\033[0m"
#define EOS_TEXTBLACK "\033[49;30m"
#define EOS_TEXTRED "\033[49;31m"
#define EOS_TEXTREDERROR "\033[47;31m\e[5m"
#define EOS_TEXTBLUEERROR "\033[47;34m\e[5m"
#define EOS_TEXTGREEN "\033[49;32m"
#define EOS_TEXTYELLOW "\033[49;33m"
#define EOS_TEXTBLUE "\033[49;34m"
#define EOS_TEXTBOLD "\033[1m"
#define EOS_TEXTUNBOLD "\033[0m"
#define LOG_SILENT 0xffff
//------------------------------------------------------------------------------
//! Log Macros usable in objects inheriting from the logId Class
//------------------------------------------------------------------------------
#define eos_log(__EOSCOMMON_LOG_PRIORITY__ , ...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, __EOSCOMMON_LOG_PRIORITY__, __VA_ARGS__)
#define eos_debug(...) \
if ((LOG_MASK(LOG_DEBUG) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_DEBUG), __VA_ARGS__); \
}
#define eos_info(...) \
if ((LOG_MASK(LOG_INFO) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_INFO), __VA_ARGS__); \
}
#define eos_notice(...) \
if ((LOG_MASK(LOG_NOTICE) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_NOTICE), __VA_ARGS__); \
}
#define eos_warning(...) \
if ((LOG_MASK(LOG_WARNING) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_WARNING), __VA_ARGS__); \
}
#define eos_err(...) \
if ((LOG_MASK(LOG_ERR) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_ERR) , __VA_ARGS__); \
}
#define eos_crit(...) \
if ((LOG_MASK(LOG_CRIT) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_CRIT), __VA_ARGS__); \
}
#define eos_alert(...) \
if ((LOG_MASK(LOG_ALERT) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_ALERT) , __VA_ARGS__); \
}
#define eos_emerg(...) \
if ((LOG_MASK(LOG_EMERG) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_EMERG) , __VA_ARGS__); \
}
#define eos_silent(...) \
if ((LOG_MASK(LOG_SILENT) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, this->logId, \
vid, this->cident, (LOG_SILENT) , __VA_ARGS__); \
}
//------------------------------------------------------------------------------
//! Log Macros usable in singleton objects used by individual threads
//! You should define locally LodId tlLogId in the thread function
//------------------------------------------------------------------------------
#define eos_thread_debug(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_DEBUG) , __VA_ARGS__)
#define eos_thread_info(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_INFO) , __VA_ARGS__)
#define eos_thread_notice(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_NOTICE) , __VA_ARGS__)
#define eos_thread_warning(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_WARNING), __VA_ARGS__)
#define eos_thread_err(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_ERR) , __VA_ARGS__)
#define eos_thread_crit(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_CRIT) , __VA_ARGS__)
#define eos_thread_alert(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_ALERT) , __VA_ARGS__)
#define eos_thread_emerg(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, tlLogId.logId, \
vid, tlLogId.cident, (LOG_EMERG) , __VA_ARGS__)
//------------------------------------------------------------------------------
//! Log Macros usable from static member functions without LogId object
//------------------------------------------------------------------------------
#define eos_static_log(__EOSCOMMON_LOG_PRIORITY__ , ...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, \
"static..............................", \
eos::common::gLogging.gZeroVid, "", \
(__EOSCOMMON_LOG_PRIORITY__) , \
__VA_ARGS__)
#define eos_static_debug(...) \
if ((LOG_MASK(LOG_DEBUG) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, \
"static..............................", \
eos::common::gLogging.gZeroVid, "", \
(LOG_DEBUG), __VA_ARGS__); \
}
#define eos_static_info(...) \
if ((LOG_MASK(LOG_INFO) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid, "", (LOG_INFO), __VA_ARGS__); \
}
#define eos_static_notice(...) \
if ((LOG_MASK(LOG_NOTICE) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid, "", (LOG_NOTICE), __VA_ARGS__); \
}
#define eos_static_warning(...) \
if ((LOG_MASK(LOG_WARNING) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid, "", (LOG_WARNING), __VA_ARGS__); \
}
#define eos_static_err(...) \
if ((LOG_MASK(LOG_ERR) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid, "", (LOG_ERR), __VA_ARGS__); \
}
#define eos_static_crit(...) \
if ((LOG_MASK(LOG_CRIT) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid, "", (LOG_CRIT), __VA_ARGS__); \
}
#define eos_static_alert(...) \
if ((LOG_MASK(LOG_ALERT) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid, "", (LOG_ALERT) , __VA_ARGS__); \
}
#define eos_static_emerg(...) \
if ((LOG_MASK(LOG_EMERG) & eos::common::Logging::GetInstance().GetLogMask()) != 0) { \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid,"", (LOG_EMERG) , __VA_ARGS__); \
}
#define eos_static_silent(...) \
eos::common::Logging::GetInstance().log(__FUNCTION__,__FILE__, __LINE__, "static..............................", \
eos::common::gLogging.gZeroVid,"", (LOG_SILENT) , __VA_ARGS__)
//------------------------------------------------------------------------------
//! Log Macros to check if a function would log in a certain log level
//------------------------------------------------------------------------------
#define EOS_LOGS_DEBUG eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_DEBUG) )
#define EOS_LOGS_INFO eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_INFO) )
#define EOS_LOGS_NOTICE eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_NOTICE) )
#define EOS_LOGS_WARNING eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_WARNING))
#define EOS_LOGS_ERR eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_ERR) )
#define EOS_LOGS_CRIT eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_CRIT) )
#define EOS_LOGS_ALERT eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_ALERT) )
#define EOS_LOGS_EMERG eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_EMERG) )
#define EOS_LOGS_SILENT eos::common::Logging::GetInstance().shouldlog(__FUNCTION__,(LOG_SILENT) )
#define EOSCOMMONLOGGING_CIRCULARINDEXSIZE 10000
//------------------------------------------------------------------------------
//! Log Macros providing a third party code location in static functions
//------------------------------------------------------------------------------
#define eos_third_party_warning(function,file,line,...) \
eos::common::Logging::GetInstance().log((function),(file), (line), "static..............................", \
eos::common::gLogging.gZeroVid, "", (LOG_WARNING), __VA_ARGS__)
//------------------------------------------------------------------------------
//! Class implementing EOS logging
//------------------------------------------------------------------------------
class LogId
{
public:
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
LogId()
{
uuid_t uuid;
uuid_generate_time(uuid);
uuid_unparse(uuid, logId);
sprintf(cident, "");
vid.uid = getuid();
vid.gid = getgid();
vid.name = "";
vid.tident = "";
vid.prot = "";
}
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
virtual ~LogId() = default;
//----------------------------------------------------------------------------
//! Generate log id value
//----------------------------------------------------------------------------
static std::string GenerateLogId()
{
char log_id[40];
uuid_t uuid;
uuid_generate_time(uuid);
uuid_unparse(uuid, log_id);
return log_id;
}
//----------------------------------------------------------------------------
//! For calls which are not client initiated this function set's a unique
//! dummy log id
//----------------------------------------------------------------------------
void
SetSingleShotLogId(const char* td = "")
{
snprintf(logId, sizeof(logId), "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
snprintf(cident, sizeof(cident), "%s", td);
}
//----------------------------------------------------------------------------
//! Set's the logid
//----------------------------------------------------------------------------
void
SetLogId(const char* newlogid)
{
if (newlogid && (strncmp(newlogid, logId, sizeof(newlogid) - 1) != 0)) {
snprintf(logId, sizeof(logId), "%s", newlogid);
}
}
//----------------------------------------------------------------------------
//! Set's the logid and trace identifier
//----------------------------------------------------------------------------
void
SetLogId(const char* newlogid, const char* td)
{
if (newlogid && (newlogid != logId)) {
snprintf(logId, sizeof(logId) , "%s", newlogid);
}
if (td) {
snprintf(cident, sizeof(cident) , "%s", td);
}
}
//----------------------------------------------------------------------------
//! Set's the logid, vid and trace identifier
//----------------------------------------------------------------------------
void
SetLogId(const char* newlogid,
const XrdSecEntity* client,
const char* td = "")
{
if (newlogid) {
SetLogId(newlogid, td);
}
if (client) {
vid.name = client->name;
vid.host = (client->host) ? client->host : "?";
vid.prot = client->prot;
}
}
//----------------------------------------------------------------------------
//! Set's the logid, vid and trace identifier
//----------------------------------------------------------------------------
void
SetLogId(const char* newlogid, const VirtualIdentity& vid_in,
const char* td = "")
{
vid = vid_in;
snprintf(cident, sizeof(cident), "%s", td);
if (vid.token && vid.token->Valid()) {
// use the voucher as logging ID
snprintf(logId, sizeof(logId), "%s", vid.token->Voucher().c_str());
} else {
if (newlogid != logId) {
snprintf(logId, sizeof(logId), "%s", newlogid);
}
}
}
char logId[40]; //< the log Id for message printout
char cident[256]; //< the client identifier
VirtualIdentity vid; //< the client identity
};
#define LOG_BUFFER_DBG 0
class LogBuffer
{
public:
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
LogBuffer()
{
char* s = getenv("EOS_MGM_LOG_BUFFERS");
if (s) {
int val = atoi(s);
if (val > 0) {
max_log_buffers = val;
}
}
}
/* Suspend/resume is for forkers - threads aren't carried over into children */
void suspend()
{
std::unique_lock guard(log_buffer_mutex);
log_suspended = true;
}
void resume()
{
std::unique_lock guard(log_buffer_mutex);
resume_int();
}
void resume_int()
{
if (!log_thread_started) {
log_suspended = false;
log_thread_p = std::thread([this] { log_thread(); });
log_thread_started = true;
}
}
void
shutDown(bool gracefully = false)
{
LogBuffer::log_buffer* buff;
std::unique_lock guard(log_buffer_mutex);
if (shuttingDown > 0) {
return;
}
/* Stop allocating buffers, tell thread to stop, perhaps gracefully */
/* many things here should only be modified under a lock: the log
thread set shuttingDown it to indicate it finishes */
shuttingDown = (gracefully) ? 1 : 4;
if (log_thread_started) {
while (true) {
int old_q = log_buffer_in_q;
log_buffer_cond.notify_all();
guard.unlock(); /* let log_thread run for a bit */
std::this_thread::sleep_for(chrono::milliseconds(1000));
guard.lock();
if (shuttingDown > 38) {
break;
}
if (log_buffer_in_q == old_q) {
shuttingDown++;
}
}
if (shuttingDown < 99) {
log_thread_p.join();
}
}
while ((buff = free_buffers) != NULL) {
free_buffers = buff->h.next;
--log_buffer_free;
guard.unlock();
#if LOG_BUFFER_DBG
if (buff->h.debug1 != 52) {
fprintf(stderr, "*** log shutdown: free buffer %#p has debug1=%#x free=%d\n",
buff, buff->h.debug1, log_buffer_free);
break;
}
#endif
free(buff);
guard.lock();
}
}
struct log_buffer;
struct log_buffer_hdr {
struct log_buffer* next;
#if LOG_BUFFER_DBG
int debug1; /* for debugging only */
#endif
char* ptr;
char* fanOutBuffer;
FILE* fanOutS;
FILE* fanOut;
int priority;
int fanOutBufLen;
};
struct log_buffer {
struct log_buffer_hdr h;
char buffer[(8 * 1024 - sizeof(struct log_buffer_hdr))];
};
struct log_buffer* free_buffers = NULL;
struct log_buffer* active_head = NULL;
struct log_buffer* active_tail = NULL;
int shuttingDown = 0;
int log_buffer_waiters = 0; /* protected by log_buffer_shortage_mutex */
/* limit number of log_buffers */
int log_buffer_total = 0; /* protected by log_mutex */
int max_log_buffers = 2048; /* reasonable: 2048 */;
/* the following are info only, could be junked */
int log_buffer_balance = 0; /* between "requested" and "queued" */
int log_buffer_free = 0;
int log_buffer_in_q = 0;
unsigned int log_buffer_num_waits = 0;
bool log_suspended = false;
bool log_thread_started = false;
std::thread log_thread_p;
std::mutex log_buffer_mutex;
std::condition_variable log_buffer_cond;
std::condition_variable log_buffer_shortage;
struct log_buffer* log_alloc_buffer();
void log_return_buffers(struct log_buffer*);
void log_queue_buffer(struct log_buffer*);
void log_thread();
};
//------------------------------------------------------------------------------
//! Class wrapping global singleton objects for logging
//------------------------------------------------------------------------------
class Logging
{
public:
//! Typedef for circular index pointing to the next message position int he log array
typedef std::vector< unsigned long > LogCircularIndex;
//! Typdef for log message array
typedef std::vector< std::vector > LogArray;
VirtualIdentity gZeroVid; ///< Root vid
LogCircularIndex gLogCircularIndex; //< global circular index
LogArray gLogMemory; //< global logging memory
unsigned long gCircularIndexSize; //< global circular index size
std::atomic gLogMask; //< log mask
std::atomic gPriorityLevel; //< log priority
bool gToSysLog; //< duplicate into syslog
XrdSysMutex gMutex; //< global mutex
XrdOucString gUnit; //< global unit name
//! Global list of function names allowed to log
XrdOucHash gAllowFilter;
//! Global list of function names denied to log
XrdOucHash gDenyFilter;
int gShortFormat; //< indiciating if the log-output is in short format
//! Here one can define log fan-out to different file descriptors than stderr
std::map gLogFanOut;
bool gRateLimiter; //< indicating to apply message rate limiting
LogBuffer* LB;
//----------------------------------------------------------------------------
//! Get singleton instance
//----------------------------------------------------------------------------
static Logging& GetInstance();
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
Logging();
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
~Logging() = default;
void
shutDown(bool gracefully = false)
{
if (LB) {
LB->shutDown(gracefully);
}
}
//----------------------------------------------------------------------------
//! Get current loglevel
//----------------------------------------------------------------------------
void
EnableRateLimiter()
{
gRateLimiter = true;
}
//----------------------------------------------------------------------------
//! Get current loglevel
//----------------------------------------------------------------------------
int
GetLogMask() const
{
return gLogMask;
}
//----------------------------------------------------------------------------
//! Set the log priority (like syslog)
//----------------------------------------------------------------------------
void
SetLogPriority(int pri)
{
gLogMask = LOG_UPTO(pri);
gPriorityLevel = pri;
}
//----------------------------------------------------------------------------
//! Set the log unit name
//----------------------------------------------------------------------------
void
SetUnit(const char* unit)
{
gUnit = unit;
}
void
SetSysLog(bool onoff)
{
gToSysLog = onoff;
}
//----------------------------------------------------------------------------
//! Set index size
//----------------------------------------------------------------------------
void
SetIndexSize(size_t size)
{
gCircularIndexSize = size;
for (int i = 0; i <= LOG_DEBUG; i++) {
gLogCircularIndex[i] = 0;
gLogMemory[i].resize(size);
gLogMemory[i].shrink_to_fit();
}
}
//----------------------------------------------------------------------------
//! Set the log filter
//----------------------------------------------------------------------------
void
SetFilter(const char* filter)
{
int pos = 0;
char del = ',';
XrdOucString token;
XrdOucString pass_tag = "PASS:";
XrdOucString sfilter = filter;
// Clear both maps
gDenyFilter.Purge();
gAllowFilter.Purge();
if ((pos = sfilter.find(pass_tag)) != STR_NPOS) {
// Extract the function names which are allowed to log
pos += pass_tag.length();
while ((pos = sfilter.tokenize(token, pos, del)) != -1) {
gAllowFilter.Add(token.c_str(), NULL, 0, Hash_data_is_key);
}
} else {
// Extract the function names which are denied to log
pos = 0;
try {
while ((pos = sfilter.tokenize(token, pos, del)) != -1) {
gDenyFilter.Add(token.c_str(), NULL, 0, Hash_data_is_key);
}
} catch (int& err) {}
}
}
//----------------------------------------------------------------------------
//! Return priority as string
//----------------------------------------------------------------------------
const char*
GetPriorityString(int pri)
{
if (pri == (LOG_INFO)) {
return "INFO ";
}
if (pri == (LOG_DEBUG)) {
return "DEBUG";
}
if (pri == (LOG_ERR)) {
return "ERROR";
}
if (pri == (LOG_EMERG)) {
return "EMERG";
}
if (pri == (LOG_ALERT)) {
return "ALERT";
}
if (pri == (LOG_CRIT)) {
return "CRIT ";
}
if (pri == (LOG_WARNING)) {
return "WARN ";
}
if (pri == (LOG_NOTICE)) {
return "NOTE ";
}
if (pri == (LOG_SILENT)) {
return "";
}
return "NONE ";
}
//----------------------------------------------------------------------------
//! Return priority int from string
//----------------------------------------------------------------------------
int
GetPriorityByString(const char* pri)
{
if (!strcmp(pri, "info")) {
return LOG_INFO;
}
if (!strcmp(pri, "debug")) {
return LOG_DEBUG;
}
if (!strcmp(pri, "err")) {
return LOG_ERR;
}
if (!strcmp(pri, "emerg")) {
return LOG_EMERG;
}
if (!strcmp(pri, "alert")) {
return LOG_ALERT;
}
if (!strcmp(pri, "crit")) {
return LOG_CRIT;
}
if (!strcmp(pri, "warning")) {
return LOG_WARNING;
}
if (!strcmp(pri, "notice")) {
return LOG_NOTICE;
}
if (!strcmp(pri, "silent")) {
return LOG_SILENT;
}
return -1;
}
//----------------------------------------------------------------------------
//! Add a tag fanout filedescriptor to the logging module
//----------------------------------------------------------------------------
void
AddFanOut(const char* tag, FILE* fd)
{
gLogFanOut[tag] = fd;
}
//----------------------------------------------------------------------------
//! Add a tag fanout alias to the logging module
//----------------------------------------------------------------------------
void
AddFanOutAlias(const char* alias, const char* tag)
{
if (gLogFanOut.count(tag)) {
gLogFanOut[alias] = gLogFanOut[tag];
}
}
//----------------------------------------------------------------------------
//! Get a color for a given logging level
//----------------------------------------------------------------------------
const char*
GetLogColour(const char* loglevel)
{
if (!strcmp(loglevel, "INFO ")) {
return EOS_TEXTGREEN;
}
if (!strcmp(loglevel, "ERROR")) {
return EOS_TEXTRED;
}
if (!strcmp(loglevel, "WARN ")) {
return EOS_TEXTYELLOW;
}
if (!strcmp(loglevel, "NOTE ")) {
return EOS_TEXTBLUE;
}
if (!strcmp(loglevel, "CRIT ")) {
return EOS_TEXTREDERROR;
}
if (!strcmp(loglevel, "EMERG")) {
return EOS_TEXTBLUEERROR;
}
if (!strcmp(loglevel, "ALERT")) {
return EOS_TEXTREDERROR;
}
if (!strcmp(loglevel, "DEBUG")) {
return "";
}
return "";
}
//----------------------------------------------------------------------------
//! Check if we should log in the defined level/filter
//!
//! @param func name of the calling function
//! @param priority priority level of the message
//!
//----------------------------------------------------------------------------
bool shouldlog(const char* func, int priority);
//----------------------------------------------------------------------------
//! Log a message into the global buffer
//!
//! @param func name of the calling function
//! @param file name of the source file calling
//! @param line line in the source file
//! @param logid log message identifier
//! @param vid virtual id of the caller
//! @param cident client identifier
//! @param priority priority level of the message
//! @param msg the actual log message
//!
//! @return pointer to the log message
//----------------------------------------------------------------------------
const char* log(const char* func, const char* file, int line,
const char* logid, const VirtualIdentity& vid,
const char* cident, int priority, const char* msg, ...);
//----------------------------------------------------------------------------
//! estimates log message distance and similiary to suppress log messages
//!
//! @param time of the message
//! @param priority of the message
//! @param source file name
//! @param line in source file
//!
//! @return true if it should be suppressed, otherwise false
//---------------------------------------------------------------------------
bool rate_limit(struct timeval& tv, int priority, const char* file, int line);
};
extern Logging& gLogging; ///< Global logging object
//------------------------------------------------------------------------------
//! Static Logging initializer
//------------------------------------------------------------------------------
static struct LoggingInitializer {
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
LoggingInitializer();
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
~LoggingInitializer();
} sLoggingInit; ///< Static initializer for every translation unit
EOSCOMMONNAMESPACE_END
#endif