* change the format of messages for stderr and syslog (eg, debugging

info goes after the message)
* add thread ID to the logging facility API
* on linux, use gettid() syscall instead of pthread_self() for 
  thread ID
* convert syslog logging to a logging facility
* add possibility to disable syslog at compile-time (see 
  DISABLE_SYSLOG_LOG macro)



git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@1870 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Ondrej Martine 16 years ago
parent c7df7e63fb
commit 3a28ee48a5

@ -223,9 +223,19 @@ class AmLoggingFacility : public AmPluginFactory
AmLoggingFacility(const string& name);
virtual ~AmLoggingFacility() { }
/** will be called on logging messages
/**
* This method is called when logging a message if the instance
* is registered as a logging hook.
*
* @param level log level
* @param pid process ID
* @param tid thread ID
* @param func function name
* @param file file name
* @param line line number
* @param msg message
*/
virtual void log(int level, const char* msg) = 0;
virtual void log(int level, pid_t pid, pthread_t tid, const char* func, const char* file, int line, char* msg) = 0;
};
#if __GNUC__ < 3

@ -20,135 +20,164 @@
* 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, write to the Free Software
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "log.h"
#include <unistd.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#ifndef DISABLE_SYSLOG_LOG
# include <syslog.h>
#endif
#include <vector>
#include "AmApi.h"
#include <string>
int log_level=L_INFO;
int log_stderr=0;
#include "AmApi.h" /* AmLoggingFacility */
#include "AmThread.h" /* AmMutex */
#include "log.h"
/* log facility (see syslog(3)) */
int log_facility=LOG_DAEMON;
vector<AmLoggingFacility*> log_hooks;
int log_level = AmConfig::LogLevel; /**< log level */
int log_stderr = AmConfig::LogStderr; /**< non-zero if logging to stderr */
/** Map log levels to text labels */
const char* log_level2str[] = { "ERROR", "WARNING", "INFO", "DEBUG" };
inline const char* level2txt(int level)
{
switch(level){
case L_ERR: return "ERROR";
case L_WARN: return "WARNING";
case L_INFO: return "INFO";
case L_DBG: return "DEBUG";
/** Registered logging hooks */
static vector<AmLoggingFacility*> log_hooks;
static AmMutex log_hooks_mutex;
#ifndef DISABLE_SYSLOG_LOG
/**
* Syslog Logging Facility (built-in plug-in)
*/
class SyslogLogFac : public AmLoggingFacility {
int facility; /**< syslog facility */
void init() {
openlog("sems", LOG_PID | LOG_CONS, facility);
setlogmask(-1);
}
return "";
}
void init_log()
{
openlog(LOG_NAME, LOG_PID|LOG_CONS,log_facility);
setlogmask( -1 );
}
public:
SyslogLogFac() : AmLoggingFacility("syslog"), facility(LOG_DAEMON) {
init();
}
~SyslogLogFac() {
closelog();
}
int onLoad() {
/* unused (because it is a built-in plug-in */
return 0;
}
bool setFacility(const char* str);
void log(int, pid_t, pthread_t, const char*, const char*, int, char*);
};
static SyslogLogFac syslog_log;
/** Set syslog facility */
bool SyslogLogFac::setFacility(const char* str) {
static int local_fac[] = {
LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3,
LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7,
};
void set_log_facility(const char* facility) {
int new_facility = -1;
if (!strcmp(facility, "DAEMON")){
if (!strcmp(str, "DAEMON")){
new_facility = LOG_DAEMON;
} else if (!strcmp(facility, "USER")) {
}
else if (!strcmp(str, "USER")) {
new_facility = LOG_USER;
} else if (strlen(facility)==6 &&
!strncmp(facility, "LOCAL", 5) &&
facility[5]-'0' < 8) {
switch (facility[5]) {
case '0': new_facility = LOG_LOCAL0; break;
case '1': new_facility = LOG_LOCAL1; break;
case '2': new_facility = LOG_LOCAL2; break;
case '3': new_facility = LOG_LOCAL3; break;
case '4': new_facility = LOG_LOCAL4; break;
case '5': new_facility = LOG_LOCAL5; break;
case '6': new_facility = LOG_LOCAL6; break;
case '7': new_facility = LOG_LOCAL7; break;
}
} else {
ERROR("unknown syslog facility '%s'\n",
facility);
return;
}
else if (strlen(str) == 6 && !strncmp(str, "LOCAL", 5) &&
isdigit(str[5]) && str[5] - '0' < 8) {
new_facility = local_fac[str[5] - '0'];
}
else {
ERROR("unknown syslog facility '%s'\n", str);
return false;
}
if (new_facility != log_facility) {
log_facility = new_facility;
if (new_facility != facility) {
facility = new_facility;
closelog();
init_log();
init();
}
return true;
}
AmMutex dprint_mut;
void SyslogLogFac::log(int level, pid_t pid, pthread_t tid, const char* func, const char* file, int line, char* msg)
{
static const int log2syslog_level[] = { LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG };
#ifdef _DEBUG
# ifndef NO_THREADID_LOG
syslog(log2syslog_level[level], "%s: %s [%s, #%lx] [%s:%d]",
log_level2str[level], msg, func, tid, file, line);
# else /* NO_THREADID_LOG */
syslog(log2syslog_level[level], "%s: %s [%s] [%s:%d]",
log_level2str[level], msg, func, file, line);
# endif /* NO_THREADID_LOG */
#else /* !_DEBUG */
syslog(log2syslog_level[level], "%s: %s [%s:%d]",
log_level2str[level], msg, file, line);
#endif /* !_DEBUG */
}
void dprint(int level, const char* fct, const char* file, int line, const char* fmt, ...)
int set_syslog_facility(const char* str)
{
dprint_mut.lock();
return (syslog_log.setFacility(str) == true);
}
va_list ap;
#endif /* !DISABLE_SYSLOG_LOG */
#ifndef _DEBUG
fprintf(stderr, "(%i) %s: %s (%s:%i): ",(int)getpid(), level2txt(level), fct, file, line);
#else
fprintf(stderr, "(%i) %s: " THREAD_FMT "%s (%s:%i): ",(int)getpid(), level2txt(level), THREAD_ID fct, file, line);
#endif
va_start(ap, fmt);
vfprintf(stderr,fmt,ap);
fflush(stderr);
va_end(ap);
dprint_mut.unlock();
}
void log_print (int level, const char* fmt, ...)
/**
* Initialize logging
*/
void init_logging()
{
va_list ap;
log_hooks.clear();
#ifndef DISABLE_SYSLOG_LOG
register_log_hook(&syslog_log);
#endif
fprintf(stderr, "(%i) %s: ",(int)getpid(),level2txt(level));
va_start(ap, fmt);
vfprintf(stderr,fmt,ap);
fflush(stderr);
va_end(ap);
INFO("Logging initialized\n");
}
void log_fac_print(int level, const char* fct, const char* file, int line, const char* fmt, ...)
/**
* Run log hooks
*/
void run_log_hooks(int level, pid_t pid, pthread_t tid, const char* func, const char* file, int line, char* msg)
{
va_list ap;
char logline[512];
int len;
if(log_hooks.empty()) return;
log_hooks_mutex.lock();
// file, line etc
len = snprintf(logline, sizeof(logline), "(%i) %s: %s (%s:%i): ",
(int)getpid(), level2txt(level), fct, file, line);
// dbg msg
va_start(ap, fmt);
vsnprintf(logline+len, sizeof(logline)-len, fmt, ap);
va_end(ap);
if (!log_hooks.empty()) {
for (vector<AmLoggingFacility*>::iterator it = log_hooks.begin();
it != log_hooks.end(); ++it) {
(*it)->log(level, pid, tid, func, file, line, msg);
}
}
for(unsigned i=0; i<log_hooks.size(); i++) log_hooks[i]->log(level, logline);
log_hooks_mutex.unlock();
}
void register_logging_fac(void* vp)
/**
* Register the log hook
*/
void register_log_hook(AmLoggingFacility* fac)
{
AmLoggingFacility* lf = static_cast<AmLoggingFacility*>(vp);
#ifdef _DEBUG
assert(lf != NULL);
#endif
log_hooks.push_back(lf);
AmLock lock(log_hooks_mutex);
log_hooks.push_back(fac);
}

@ -20,102 +20,120 @@
* 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, write to the Free Software
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** @file log.h */
#ifndef _log_h_
#define _log_h_
#include <syslog.h>
#ifdef _DEBUG
#include <pthread.h>
#endif
#include <sys/types.h> /* pid_t */
#include <stdio.h>
#include <unistd.h> /* getpid() */
#include <pthread.h> /* pthread_self() */
#ifdef __cplusplus
extern "C" {
# if 0
}
# endif
#endif
#define L_ERR 0
#define L_WARN 1
#define L_INFO 2
#define L_DBG 3
/* priority at which we log */
#define DPRINT_PRIO LOG_DEBUG
#define LOG_NAME "sems"
extern int log_level;
extern int log_stderr;
extern int log_facility;
void init_log();
void set_log_facility(const char* facility);
/**
* @{ Log levels
*/
enum Log_Level {
L_ERR = 0,
L_WARN,
L_INFO,
L_DBG
};
/** @} */
void dprint (int level, const char* fct, const char* file, int line, const char* fmt, ...);
void log_print (int level, const char* fmt, ...);
void register_logging_fac(void*);
void log_fac_print(int level, const char* fct, const char* file, int line, const char* fmt, ...);
#define FIX_LOG_LEVEL(level) \
((level) < L_ERR ? L_ERR : ((level) > L_DBG ? L_DBG : (level)))
#ifdef _DEBUG
#define LOG_PRINT(level, args... ) dprint( level, __FUNCTION__, __FILE__, __LINE__, ##args )
#ifdef __cplusplus
# define FUNC_NAME __PRETTY_FUNCTION__
#else
#define LOG_PRINT(level, args... ) log_print( level , ##args )
# define FUNC_NAME __FUNCTION__
#endif
#define LOG_FAC_PRINT(level, args... ) log_fac_print( level, __FUNCTION__, __FILE__, __LINE__, ##args )
#ifdef _DEBUG
#ifndef NO_THREADID_LOG
#define THREAD_FMT "[%lx] "
#define THREAD_ID (unsigned long)pthread_self(),
#endif
#endif
#ifndef THREAD_FMT
#define THREAD_FMT ""
#define THREAD_ID
#ifdef __linux
# include <linux/unistd.h>
# define GET_PID() syscall(__NR_gettid)
#else
# define GET_PID() getpid()
#endif
#if __GNUC__ < 3
#define _LOG(level,fmt...) LOG_PRINT(level,##fmt)
#ifdef _DEBUG
# ifndef NO_THREADID_LOG
# define GET_TID() pthread_self()
# define LOC_FMT " [%s, #%lx] [%u/%s:%d]"
# define LOC_DATA FUNC_NAME, tid_, pid_, __FILE__, __LINE__
# else
# define GET_TID() 0
# define LOC_FMT " [%s] [%u/%s:%d]"
# define LOC_DATA FUNC_NAME, pid_, __FILE__, __LINE__
# endif
#else
#define _LOG(level, fmt, args...) \
do{ \
if((level)<=log_level) { \
if(log_stderr) \
LOG_PRINT( level, fmt, ##args ); \
else { \
switch(level){ \
case L_ERR: \
syslog(LOG_ERR, (char*)("ERROR: " THREAD_FMT "%s (%s:%i): " fmt), THREAD_ID __FUNCTION__, __FILE__, __LINE__, ##args); \
break; \
case L_WARN: \
syslog(LOG_WARNING, (char*)("WARNING: " THREAD_FMT "%s (%s:%i): " fmt), THREAD_ID __FUNCTION__, __FILE__, __LINE__, ##args); \
break; \
case L_INFO: \
syslog(LOG_INFO, (char*)("INFO: " THREAD_FMT "%s (%s:%i): " fmt), THREAD_ID __FUNCTION__, __FILE__, __LINE__, ##args); \
break; \
case L_DBG: \
syslog(LOG_DEBUG, (char*)("DEBUG: " THREAD_FMT "%s (%s:%i): " fmt), THREAD_ID __FUNCTION__, __FILE__, __LINE__, ##args); \
break; \
} \
} \
} \
LOG_FAC_PRINT( level, fmt, ##args ); \
}while(0)
# define GET_TID() 0
# define LOC_FMT " [%u/%s:%d]"
# define LOC_DATA pid_, __FILE__, __LINE__
#endif
/* The underscores in parameter and local variable names are there to
avoid collisions. */
#define _LOG(level__, fmt, args...) \
do { \
int level_ = FIX_LOG_LEVEL(level__); \
\
if ((level_) <= log_level) { \
pid_t pid_ = GET_PID(); \
pthread_t tid_ = GET_TID(); \
char msg_[512]; \
int n_ = snprintf(msg_, sizeof(msg_), fmt, ##args); \
if (msg_[n_ - 1] == '\n') msg_[n_ - 1] = '\0'; \
\
if (log_stderr) { \
fprintf(stderr, "%s: %s" LOC_FMT "\n", log_level2str[level_], msg_, LOC_DATA); \
fflush(stderr); \
} \
run_log_hooks(level_, pid_, tid_, FUNC_NAME, __FILE__, __LINE__, msg_); \
} \
} while(0)
/**
* @{ Logging macros
*/
#define ERROR(fmt, args...) _LOG(L_ERR, fmt, ##args)
#define WARN(fmt, args...) _LOG(L_WARN, fmt, ##args)
#define INFO(fmt, args...) _LOG(L_INFO, fmt, ##args)
#define DBG(fmt, args...) _LOG(L_DBG, fmt, ##args)
/** @} */
extern int log_level;
extern int log_stderr;
extern const char* log_level2str[];
void init_logging(void);
void run_log_hooks(int, pid_t, pthread_t, const char*, const char*, int, char*);
#define DBG(args...) _LOG(L_DBG, ##args)
#define ERROR(args...) _LOG(L_ERR, ##args)
#define WARN(args...) _LOG(L_WARN, ##args)
#define INFO(args...) _LOG(L_INFO, ##args)
#ifndef DISABLE_SYSLOG_LOG
int set_syslog_facility(const char*);
#endif
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
/* ...only for C++ */
class AmLoggingFacility;
void register_log_hook(AmLoggingFacility*);
#endif
#endif /* !_log_h_ */

Loading…
Cancel
Save