2011-06-21 17:19:10 +08:00
|
|
|
/*
|
|
|
|
* ZoneMinder Logger Implementation, $Date$, $Revision$
|
|
|
|
* Copyright (C) 2001-2008 Philip Coombes
|
|
|
|
*
|
|
|
|
* 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 2
|
|
|
|
* 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, write to the Free Software
|
2016-12-26 23:23:16 +08:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2011-06-21 17:19:10 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "zm_logger.h"
|
|
|
|
|
|
|
|
#include "zm_config.h"
|
|
|
|
#include "zm_utils.h"
|
|
|
|
|
2013-04-30 00:51:46 +08:00
|
|
|
#include <unistd.h>
|
2011-06-21 17:19:10 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <errno.h>
|
2017-01-31 16:10:25 +08:00
|
|
|
#include <libgen.h>
|
2015-02-24 22:22:08 +08:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
#include <sys/thr.h>
|
|
|
|
#endif
|
2011-06-21 17:19:10 +08:00
|
|
|
|
|
|
|
bool Logger::smInitialised = false;
|
|
|
|
Logger *Logger::smInstance = 0;
|
|
|
|
|
|
|
|
Logger::StringMap Logger::smCodes;
|
|
|
|
Logger::IntMap Logger::smSyslogPriorities;
|
|
|
|
|
2013-03-17 07:45:21 +08:00
|
|
|
#if 0
|
2017-05-20 00:57:43 +08:00
|
|
|
static void subtractTime( struct timeval * const tp1, struct timeval * const tp2 ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
tp1->tv_sec -= tp2->tv_sec;
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( tp1->tv_usec <= tp2->tv_usec ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
tp1->tv_sec--;
|
|
|
|
tp1->tv_usec = 1000000 - (tp2->tv_usec - tp1->tv_usec);
|
2017-05-20 00:57:43 +08:00
|
|
|
} else {
|
2016-04-04 22:11:48 +08:00
|
|
|
tp1->tv_usec = tp1->tv_usec - tp2->tv_usec;
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2013-03-17 07:45:21 +08:00
|
|
|
#endif
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::usrHandler( int sig ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Logger *logger = fetch();
|
|
|
|
if ( sig == SIGUSR1 )
|
|
|
|
logger->level( logger->level()+1 );
|
|
|
|
else if ( sig == SIGUSR2 )
|
|
|
|
logger->level( logger->level()-1 );
|
|
|
|
Info( "Logger - Level changed to %d", logger->level() );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Logger::Logger() :
|
2016-04-04 22:11:48 +08:00
|
|
|
mLevel( INFO ),
|
|
|
|
mTermLevel( NOLOG ),
|
|
|
|
mDatabaseLevel( NOLOG ),
|
|
|
|
mFileLevel( NOLOG ),
|
|
|
|
mSyslogLevel( NOLOG ),
|
|
|
|
mEffectiveLevel( NOLOG ),
|
|
|
|
//mLogPath( config.path_logs ),
|
|
|
|
//mLogFile( mLogPath+"/"+mId+".log" ),
|
|
|
|
mDbConnected( false ),
|
|
|
|
mLogFileFP( NULL ),
|
|
|
|
mHasTerm( false ),
|
2017-05-20 00:57:43 +08:00
|
|
|
mFlush( false ) {
|
|
|
|
|
|
|
|
if ( smInstance ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Panic( "Attempt to create second instance of Logger class" );
|
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( !smInitialised ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
smCodes[INFO] = "INF";
|
|
|
|
smCodes[WARNING] = "WAR";
|
|
|
|
smCodes[ERROR] = "ERR";
|
|
|
|
smCodes[FATAL] = "FAT";
|
|
|
|
smCodes[PANIC] = "PNC";
|
|
|
|
smCodes[NOLOG] = "OFF";
|
|
|
|
|
|
|
|
smSyslogPriorities[INFO] = LOG_INFO;
|
|
|
|
smSyslogPriorities[WARNING] = LOG_WARNING;
|
|
|
|
smSyslogPriorities[ERROR] = LOG_ERR;
|
|
|
|
smSyslogPriorities[FATAL] = LOG_ERR;
|
|
|
|
smSyslogPriorities[PANIC] = LOG_ERR;
|
|
|
|
|
|
|
|
char code[4] = "";
|
2017-05-20 00:57:43 +08:00
|
|
|
for ( int i = DEBUG1; i <= DEBUG9; i++ ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
snprintf( code, sizeof(code), "DB%d", i );
|
|
|
|
smCodes[i] = code;
|
|
|
|
smSyslogPriorities[i] = LOG_DEBUG;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
smInitialised = true;
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( fileno(stderr) && isatty(fileno(stderr)) )
|
|
|
|
mHasTerm = true;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
Logger::~Logger() {
|
2016-04-04 22:11:48 +08:00
|
|
|
terminate();
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::initialise( const std::string &id, const Options &options ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
char *envPtr;
|
|
|
|
|
|
|
|
if ( !id.empty() )
|
|
|
|
this->id( id );
|
|
|
|
|
|
|
|
std::string tempLogFile;
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( options.mLogPath.size() ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
mLogPath = options.mLogPath;
|
|
|
|
tempLogFile = mLogPath+"/"+mId+".log";
|
|
|
|
}
|
|
|
|
if ( options.mLogFile.size() )
|
|
|
|
tempLogFile = options.mLogFile;
|
|
|
|
else
|
|
|
|
tempLogFile = mLogPath+"/"+mId+".log";
|
|
|
|
if ( (envPtr = getTargettedEnv( "LOG_FILE" )) )
|
|
|
|
tempLogFile = envPtr;
|
|
|
|
|
|
|
|
Level tempLevel = INFO;
|
|
|
|
Level tempTermLevel = mTermLevel;
|
|
|
|
Level tempDatabaseLevel = mDatabaseLevel;
|
|
|
|
Level tempFileLevel = mFileLevel;
|
|
|
|
Level tempSyslogLevel = mSyslogLevel;
|
|
|
|
|
|
|
|
if ( options.mTermLevel != NOOPT )
|
|
|
|
tempTermLevel = options.mTermLevel;
|
|
|
|
if ( options.mDatabaseLevel != NOOPT )
|
|
|
|
tempDatabaseLevel = options.mDatabaseLevel;
|
|
|
|
else
|
|
|
|
tempDatabaseLevel = config.log_level_database >= DEBUG1 ? DEBUG9 : config.log_level_database;
|
|
|
|
if ( options.mFileLevel != NOOPT )
|
|
|
|
tempFileLevel = options.mFileLevel;
|
|
|
|
else
|
|
|
|
tempFileLevel = config.log_level_file >= DEBUG1 ? DEBUG9 : config.log_level_file;
|
|
|
|
if ( options.mSyslogLevel != NOOPT )
|
|
|
|
tempSyslogLevel = options.mSyslogLevel;
|
|
|
|
else
|
|
|
|
tempSyslogLevel = config.log_level_syslog >= DEBUG1 ? DEBUG9 : config.log_level_syslog;
|
|
|
|
|
|
|
|
// Legacy
|
|
|
|
if ( (envPtr = getenv( "LOG_PRINT" )) )
|
|
|
|
tempTermLevel = atoi(envPtr) ? DEBUG9 : NOLOG;
|
|
|
|
|
|
|
|
if ( (envPtr = getTargettedEnv( "LOG_LEVEL" )) )
|
|
|
|
tempLevel = atoi(envPtr);
|
|
|
|
|
|
|
|
if ( (envPtr = getTargettedEnv( "LOG_LEVEL_TERM" )) )
|
|
|
|
tempTermLevel = atoi(envPtr);
|
|
|
|
if ( (envPtr = getTargettedEnv( "LOG_LEVEL_DATABASE" )) )
|
|
|
|
tempDatabaseLevel = atoi(envPtr);
|
|
|
|
if ( (envPtr = getTargettedEnv( "LOG_LEVEL_FILE" )) )
|
|
|
|
tempFileLevel = atoi(envPtr);
|
|
|
|
if ( (envPtr = getTargettedEnv( "LOG_LEVEL_SYSLOG" )) )
|
|
|
|
tempSyslogLevel = atoi(envPtr);
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( config.log_debug ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
StringVector targets = split( config.log_debug_target, "|" );
|
2017-05-20 00:57:43 +08:00
|
|
|
for ( unsigned int i = 0; i < targets.size(); i++ ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
const std::string &target = targets[i];
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( target == mId || target == "_"+mId || target == "_"+mIdRoot || target == "_"+mIdRoot || target == "" ) {
|
|
|
|
if ( config.log_debug_level > NOLOG ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
tempLevel = config.log_debug_level;
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( config.log_debug_file[0] ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
tempLogFile = config.log_debug_file;
|
|
|
|
tempFileLevel = tempLevel;
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2017-05-20 20:53:27 +08:00
|
|
|
} // end foreach target
|
|
|
|
} // end if config.log_debug
|
|
|
|
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
logFile( tempLogFile );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
termLevel( tempTermLevel );
|
|
|
|
databaseLevel( tempDatabaseLevel );
|
|
|
|
fileLevel( tempFileLevel );
|
|
|
|
syslogLevel( tempSyslogLevel );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
level( tempLevel );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
mFlush = (envPtr = getenv( "LOG_FLUSH")) ? atoi( envPtr ) : false;
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
//mRuntime = (envPtr = getenv( "LOG_RUNTIME")) ? atoi( envPtr ) : false;
|
|
|
|
{
|
|
|
|
struct sigaction action;
|
|
|
|
memset( &action, 0, sizeof(action) );
|
|
|
|
action.sa_handler = usrHandler;
|
|
|
|
action.sa_flags = SA_RESTART;
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( sigaction( SIGUSR1, &action, 0 ) < 0 ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Fatal( "sigaction(), error = %s", strerror(errno) );
|
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( sigaction( SIGUSR2, &action, 0 ) < 0) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Fatal( "sigaction(), error = %s", strerror(errno) );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
mInitialised = true;
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
Debug( 1, "LogOpts: level=%s/%s, screen=%s, database=%s, logfile=%s->%s, syslog=%s",
|
|
|
|
smCodes[mLevel].c_str(),
|
|
|
|
smCodes[mEffectiveLevel].c_str(),
|
|
|
|
smCodes[mTermLevel].c_str(),
|
|
|
|
smCodes[mDatabaseLevel].c_str(),
|
|
|
|
smCodes[mFileLevel].c_str(),
|
|
|
|
mLogFile.c_str(),
|
|
|
|
smCodes[mSyslogLevel].c_str()
|
|
|
|
);
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::terminate() {
|
2016-04-04 22:11:48 +08:00
|
|
|
Debug(1, "Terminating Logger" );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( mFileLevel > NOLOG )
|
|
|
|
closeFile();
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( mSyslogLevel > NOLOG )
|
|
|
|
closeSyslog();
|
2014-11-15 05:17:44 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( mDatabaseLevel > NOLOG )
|
|
|
|
closeDatabase();
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
bool Logger::boolEnv( const std::string &name, bool defaultValue ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
const char *envPtr = getenv( name.c_str() );
|
|
|
|
return( envPtr ? atoi( envPtr ) : defaultValue );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
int Logger::intEnv( const std::string &name, bool defaultValue ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
const char *envPtr = getenv( name.c_str() );
|
|
|
|
return( envPtr ? atoi( envPtr ) : defaultValue );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
std::string Logger::strEnv( const std::string &name, const std::string defaultValue ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
const char *envPtr = getenv( name.c_str() );
|
|
|
|
return( envPtr ? envPtr : defaultValue );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
char *Logger::getTargettedEnv( const std::string &name ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
char *envPtr = NULL;
|
|
|
|
std::string envName;
|
|
|
|
|
|
|
|
envName = name+"_"+mId;
|
|
|
|
envPtr = getenv( envName.c_str() );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( !envPtr && mId != mIdRoot ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
envName = name+"_"+mIdRoot;
|
2011-06-21 17:19:10 +08:00
|
|
|
envPtr = getenv( envName.c_str() );
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
|
|
|
if ( !envPtr )
|
|
|
|
envPtr = getenv( name.c_str() );
|
|
|
|
return( envPtr );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
const std::string &Logger::id( const std::string &id ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
std::string tempId = id;
|
|
|
|
|
|
|
|
size_t pos;
|
|
|
|
// Remove whitespace
|
2017-05-20 00:57:43 +08:00
|
|
|
while ( (pos = tempId.find_first_of( " \t" )) != std::string::npos ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
tempId.replace( pos, 1, "" );
|
|
|
|
}
|
|
|
|
// Replace non-alphanum with underscore
|
2017-05-20 00:57:43 +08:00
|
|
|
while ( (pos = tempId.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" )) != std::string::npos ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
tempId.replace( pos, 1, "_" );
|
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( mId != tempId ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
mId = tempId;
|
|
|
|
pos = mId.find( '_' );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( pos != std::string::npos ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
mIdRoot = mId.substr( 0, pos );
|
|
|
|
if ( ++pos < mId.size() )
|
|
|
|
mIdArgs = mId.substr( pos );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
|
|
|
return( mId );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
Logger::Level Logger::level( Logger::Level level ) {
|
|
|
|
if ( level > NOOPT ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
level = limit(level);
|
|
|
|
if ( mLevel != level )
|
|
|
|
mLevel = level;
|
|
|
|
|
|
|
|
mEffectiveLevel = NOLOG;
|
|
|
|
if ( mTermLevel > mEffectiveLevel )
|
|
|
|
mEffectiveLevel = mTermLevel;
|
|
|
|
if ( mDatabaseLevel > mEffectiveLevel )
|
|
|
|
mEffectiveLevel = mDatabaseLevel;
|
|
|
|
if ( mFileLevel > mEffectiveLevel )
|
|
|
|
mEffectiveLevel = mFileLevel;
|
|
|
|
if ( mSyslogLevel > mEffectiveLevel )
|
|
|
|
mEffectiveLevel = mSyslogLevel;
|
|
|
|
if ( mEffectiveLevel > mLevel)
|
|
|
|
mEffectiveLevel = mLevel;
|
|
|
|
}
|
|
|
|
return( mLevel );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
Logger::Level Logger::termLevel( Logger::Level termLevel ) {
|
|
|
|
if ( termLevel > NOOPT ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( !mHasTerm )
|
|
|
|
termLevel = NOLOG;
|
|
|
|
termLevel = limit(termLevel);
|
|
|
|
if ( mTermLevel != termLevel )
|
|
|
|
mTermLevel = termLevel;
|
|
|
|
}
|
|
|
|
return( mTermLevel );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) {
|
|
|
|
if ( databaseLevel > NOOPT ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
databaseLevel = limit(databaseLevel);
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( mDatabaseLevel != databaseLevel ) {
|
|
|
|
if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG ) {
|
|
|
|
if ( !mDbConnected ) {
|
|
|
|
if ( !mysql_init( &mDbConnection ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Fatal( "Can't initialise database connection: %s", mysql_error( &mDbConnection ) );
|
|
|
|
exit( mysql_errno( &mDbConnection ) );
|
|
|
|
}
|
|
|
|
my_bool reconnect = 1;
|
|
|
|
if ( mysql_options( &mDbConnection, MYSQL_OPT_RECONNECT, &reconnect ) )
|
|
|
|
Fatal( "Can't set database auto reconnect option: %s", mysql_error( &mDbConnection ) );
|
2016-05-22 23:08:12 +08:00
|
|
|
std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( colonIndex == std::string::npos ) {
|
|
|
|
if ( !mysql_real_connect( &mDbConnection, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0 ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Fatal( "Can't connect to database: %s", mysql_error( &mDbConnection ) );
|
|
|
|
exit( mysql_errno( &mDbConnection ) );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
} else {
|
2016-05-22 23:08:12 +08:00
|
|
|
std::string dbHost = staticConfig.DB_HOST.substr( 0, colonIndex );
|
|
|
|
std::string dbPortOrSocket = staticConfig.DB_HOST.substr( colonIndex+1 );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( dbPortOrSocket[0] == '/' ) {
|
|
|
|
if ( !mysql_real_connect( &mDbConnection, NULL, staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, dbPortOrSocket.c_str(), 0 ) ) {
|
2016-05-22 23:08:12 +08:00
|
|
|
Fatal( "Can't connect to database: %s", mysql_error( &mDbConnection ) );
|
|
|
|
exit( mysql_errno( &mDbConnection ) );
|
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
} else {
|
|
|
|
if ( !mysql_real_connect( &mDbConnection, dbHost.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, atoi(dbPortOrSocket.c_str()), NULL, 0 ) ) {
|
2016-05-22 23:08:12 +08:00
|
|
|
Fatal( "Can't connect to database: %s", mysql_error( &mDbConnection ) );
|
|
|
|
exit( mysql_errno( &mDbConnection ) );
|
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
} // end if has colon
|
2016-04-04 22:11:48 +08:00
|
|
|
unsigned long mysqlVersion = mysql_get_server_version( &mDbConnection );
|
|
|
|
if ( mysqlVersion < 50019 )
|
|
|
|
if ( mysql_options( &mDbConnection, MYSQL_OPT_RECONNECT, &reconnect ) )
|
|
|
|
Fatal( "Can't set database auto reconnect option: %s", mysql_error( &mDbConnection ) );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( mysql_select_db( &mDbConnection, staticConfig.DB_NAME.c_str() ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Fatal( "Can't select database: %s", mysql_error( &mDbConnection ) );
|
|
|
|
exit( mysql_errno( &mDbConnection ) );
|
|
|
|
}
|
|
|
|
mDbConnected = true;
|
2017-05-20 00:57:43 +08:00
|
|
|
} // end if ! mDbConnected
|
|
|
|
} // end if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG )
|
2016-04-04 22:11:48 +08:00
|
|
|
mDatabaseLevel = databaseLevel;
|
2017-05-20 00:57:43 +08:00
|
|
|
} // end if ( mDatabaseLevel != databaseLevel )
|
|
|
|
} // end if ( databaseLevel > NOOPT )
|
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
return( mDatabaseLevel );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
Logger::Level Logger::fileLevel( Logger::Level fileLevel ) {
|
|
|
|
if ( fileLevel > NOOPT ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
fileLevel = limit(fileLevel);
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( mFileLevel != fileLevel ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( mFileLevel > NOLOG )
|
|
|
|
closeFile();
|
|
|
|
mFileLevel = fileLevel;
|
|
|
|
if ( mFileLevel > NOLOG )
|
|
|
|
openFile();
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
|
|
|
return( mFileLevel );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
Logger::Level Logger::syslogLevel( Logger::Level syslogLevel ) {
|
|
|
|
if ( syslogLevel > NOOPT ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
syslogLevel = limit(syslogLevel);
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( mSyslogLevel != syslogLevel ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( mSyslogLevel > NOLOG )
|
|
|
|
closeSyslog();
|
|
|
|
mSyslogLevel = syslogLevel;
|
|
|
|
if ( mSyslogLevel > NOLOG )
|
|
|
|
openSyslog();
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
|
|
|
return( mSyslogLevel );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::logFile( const std::string &logFile ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
bool addLogPid = false;
|
|
|
|
std::string tempLogFile = logFile;
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( tempLogFile[tempLogFile.length()-1] == '+' ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
tempLogFile.resize(tempLogFile.length()-1);
|
|
|
|
addLogPid = true;
|
|
|
|
}
|
|
|
|
if ( addLogPid )
|
|
|
|
mLogFile = stringtf( "%s.%05d", tempLogFile.c_str(), getpid() );
|
|
|
|
else
|
|
|
|
mLogFile = tempLogFile;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::openFile() {
|
|
|
|
if ( mLogFile.size() && (mLogFileFP = fopen( mLogFile.c_str() ,"w" )) == (FILE *)NULL ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
mFileLevel = NOLOG;
|
|
|
|
Fatal( "fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno) );
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::closeFile() {
|
|
|
|
if ( mLogFileFP ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
fflush( mLogFileFP );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( fclose( mLogFileFP ) < 0 ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Fatal( "fclose(), error = %s",strerror(errno) );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
mLogFileFP = (FILE *)NULL;
|
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::closeDatabase() {
|
|
|
|
if ( mDbConnected ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
mysql_close( &mDbConnection );
|
|
|
|
mDbConnected = false;
|
|
|
|
}
|
2014-11-15 05:17:44 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::openSyslog() {
|
2016-04-04 22:11:48 +08:00
|
|
|
(void) openlog( mId.c_str(), LOG_PID|LOG_NDELAY, LOG_LOCAL1 );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::closeSyslog() {
|
2016-04-04 22:11:48 +08:00
|
|
|
(void) closelog();
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void Logger::logPrint( bool hex, const char * const filepath, const int line, const int level, const char *fstring, ... ) {
|
|
|
|
if ( level <= mEffectiveLevel ) {
|
|
|
|
char timeString[64];
|
|
|
|
char logString[8192];
|
|
|
|
va_list argPtr;
|
2016-04-04 22:11:48 +08:00
|
|
|
struct timeval timeVal;
|
2015-08-22 07:28:50 +08:00
|
|
|
|
2017-01-31 16:10:25 +08:00
|
|
|
char *filecopy = strdup(filepath);
|
|
|
|
const char * const file = basename(filecopy);
|
2017-05-20 00:57:43 +08:00
|
|
|
const char *classString = smCodes[level].c_str();
|
2017-01-31 16:10:25 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( level < PANIC || level > DEBUG9 )
|
|
|
|
Panic( "Invalid logger level %d", level );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
gettimeofday( &timeVal, NULL );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
#if 0
|
2017-05-20 20:53:27 +08:00
|
|
|
if ( logRuntime ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
static struct timeval logStart;
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
subtractTime( &timeVal, &logStart );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
snprintf( timeString, sizeof(timeString), "%ld.%03ld", timeVal.tv_sec, timeVal.tv_usec/1000 );
|
2017-05-20 20:53:27 +08:00
|
|
|
} else {
|
2017-05-20 00:57:43 +08:00
|
|
|
#endif
|
2016-04-04 22:11:48 +08:00
|
|
|
char *timePtr = timeString;
|
|
|
|
timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) );
|
|
|
|
snprintf( timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec );
|
2017-05-20 00:57:43 +08:00
|
|
|
#if 0
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
#endif
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
pid_t tid;
|
2015-02-24 22:22:08 +08:00
|
|
|
#ifdef __FreeBSD__
|
2017-05-20 00:57:43 +08:00
|
|
|
long lwpid;
|
|
|
|
thr_self(&lwpid);
|
|
|
|
tid = lwpid;
|
2015-02-24 22:22:08 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
if (tid < 0 ) // Thread/Process id
|
2015-02-24 22:22:08 +08:00
|
|
|
#else
|
2011-06-21 17:19:10 +08:00
|
|
|
#ifdef HAVE_SYSCALL
|
2017-05-20 00:57:43 +08:00
|
|
|
#ifdef __FreeBSD_kernel__
|
|
|
|
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
|
|
|
|
|
|
|
|
# else
|
|
|
|
// SOLARIS doesn't have SYS_gettid; don't assume
|
|
|
|
#ifdef SYS_gettid
|
|
|
|
if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id
|
|
|
|
#endif // SYS_gettid
|
|
|
|
#endif
|
2011-06-21 17:19:10 +08:00
|
|
|
#endif // HAVE_SYSCALL
|
2015-02-24 22:22:08 +08:00
|
|
|
#endif
|
2017-05-20 00:57:43 +08:00
|
|
|
tid = getpid(); // Process id
|
2016-04-04 22:11:48 +08:00
|
|
|
|
|
|
|
char *logPtr = logString;
|
|
|
|
logPtr += snprintf( logPtr, sizeof(logString), "%s %s[%d].%s-%s/%d [",
|
2017-05-20 00:57:43 +08:00
|
|
|
timeString,
|
|
|
|
mId.c_str(),
|
|
|
|
tid,
|
|
|
|
classString,
|
|
|
|
file,
|
|
|
|
line
|
2016-04-04 22:11:48 +08:00
|
|
|
);
|
|
|
|
char *syslogStart = logPtr;
|
|
|
|
|
|
|
|
va_start( argPtr, fstring );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( hex ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
unsigned char *data = va_arg( argPtr, unsigned char * );
|
|
|
|
int len = va_arg( argPtr, int );
|
|
|
|
int i;
|
|
|
|
logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), "%d:", len );
|
2017-05-20 00:57:43 +08:00
|
|
|
for ( i = 0; i < len; i++ ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), " %02x", data[i] );
|
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
} else {
|
2016-04-04 22:11:48 +08:00
|
|
|
logPtr += vsnprintf( logPtr, sizeof(logString)-(logPtr-logString), fstring, argPtr );
|
|
|
|
}
|
|
|
|
va_end(argPtr);
|
|
|
|
char *syslogEnd = logPtr;
|
|
|
|
strncpy( logPtr, "]\n", sizeof(logString)-(logPtr-logString) );
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( level <= mTermLevel ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
printf( "%s", logString );
|
|
|
|
fflush( stdout );
|
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( level <= mFileLevel ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
fprintf( mLogFileFP, "%s", logString );
|
|
|
|
if ( mFlush )
|
|
|
|
fflush( mLogFileFP );
|
|
|
|
}
|
|
|
|
*syslogEnd = '\0';
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( level <= mDatabaseLevel ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
char sql[ZM_SQL_MED_BUFSIZ];
|
|
|
|
char escapedString[(strlen(syslogStart)*2)+1];
|
|
|
|
|
|
|
|
mysql_real_escape_string( &mDbConnection, escapedString, syslogStart, strlen(syslogStart) );
|
2017-05-20 00:57:43 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line );
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( mysql_query( &mDbConnection, sql ) ) {
|
2016-12-13 10:44:03 +08:00
|
|
|
Level tempDatabaseLevel = mDatabaseLevel;
|
|
|
|
databaseLevel( NOLOG );
|
|
|
|
Error( "Can't insert log entry: sql(%s) error(%s)", sql, mysql_error( &mDbConnection ) );
|
|
|
|
databaseLevel(tempDatabaseLevel);
|
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( level <= mSyslogLevel ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
int priority = smSyslogPriorities[level];
|
|
|
|
//priority |= LOG_DAEMON;
|
2017-05-20 00:57:43 +08:00
|
|
|
syslog( priority, "%s [%s] [%s]", classString, mId.c_str(), syslogStart );
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2017-01-31 16:10:25 +08:00
|
|
|
free(filecopy);
|
2017-05-20 00:57:43 +08:00
|
|
|
if ( level <= FATAL ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( level <= PANIC )
|
|
|
|
abort();
|
|
|
|
exit( -1 );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void logInit( const char *name, const Logger::Options &options ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( !Logger::smInstance )
|
|
|
|
Logger::smInstance = new Logger();
|
|
|
|
Logger::Options tempOptions = options;
|
|
|
|
tempOptions.mLogPath = config.path_logs;
|
|
|
|
Logger::smInstance->initialise( name, tempOptions );
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:57:43 +08:00
|
|
|
void logTerm() {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( Logger::smInstance )
|
|
|
|
delete Logger::smInstance;
|
2011-06-21 17:19:10 +08:00
|
|
|
}
|