📄 log.cpp
字号:
/*+============================================================================
File: log.cpp
Description: It provides an uniform interface for logging.
History:
2000/05/29 V1.0
Start it by shencan@263.net
2000/06/01 V1.1
Fix RadTrace output format (shencan@263.net)
Add Size(), Empty() and Instance() method.
2000/06/20 V1.2
We can use command "copy empty.log radius.log" to empty log file. (shencan@263.net)
2000/06/27 V1.3
Support solaris platform (shencan@263.net)
2000/07/08 V1.4
Fix a bug when log system exit, we set treace stream to cerr. (shencan@263.net)
2000/07/12 V1.5
Add check size timer. (shencan@263.net)
2000/07/19 V1.6
We separate log file when the size is exceed 10M. (shencan@263.net)
2000/07/25 V1.7
Fix log file size limit bug. (shencan@263.net)
2000/08/11 V1.8
Fix localtime() return NULL pointer bug. (shencan@263.net)
2000/08/25 V1.9
Add log file maximum szie limit. (shencan@263.net)
2001/11/25 V1.10
Fix string array bug, donot use [-1] to access array. (shencan@263.net)
===========================================================================+*/
//#include "ace/OS.h"
//#include "ace/Synch.h"
#include <ptlib.h>
#include <time.h>
#include "log.h"
// default maxium total log file size is 500M
#define DEFAULT_MAX_LOG_SIZE 500
// default maxium separate log file size is 5M
const int separateFileSize = 5000000L;
//const int separateFileSize = 50000L;
/////////////////////////////////////////////////////////////////////
// TRACE begin!
/////////////////////////////////////////////////////////////////////
static ostream * RadTraceStream = &cerr;
static unsigned RadTraceOptions = RadTrace::FileAndLine;
static unsigned RadTraceLevelThreshold = 0;
static int oldTraceLevel = 0;
PMutex traceMutex;
//static ACE_Mutex traceMutex; // Lock of log file
RadLogFile * RadLogFile::m_instance = NULL; // inital static member
void RadTrace::SetStream(ostream * s)
{
RadTraceStream = s != NULL ? s : &cerr;
}
void RadTrace::SetOptions(unsigned options)
{
RadTraceOptions |= options;
}
void RadTrace::ClearOptions(unsigned options)
{
RadTraceOptions &= ~options;
}
unsigned RadTrace::GetOptions()
{
return RadTraceOptions;
}
void RadTrace::SetLevel(unsigned level)
{
RadTraceLevelThreshold = level;
}
unsigned RadTrace::GetLevel()
{
return RadTraceLevelThreshold;
}
bool RadTrace::CanTrace(unsigned level)
{
return level <= RadTraceLevelThreshold;
}
ostream & RadTrace::Begin(unsigned level, const char * fileName, int lineNum)
{
//char msg[30];
traceMutex.Wait();
if ((RadTraceOptions&DateAndTime) != 0) {
/*time_t tm_sys;
struct tm tm_local_buf;
struct tm * tm_local = &tm_local_buf;
time(&tm_sys);
tm_local = localtime(&tm_sys);
if ( tm_local == NULL )
sprintf ( msg, "00/00 00:00:00");
else {
sprintf ( msg, "%02d/%02d %02d:%02d:%02d",
tm_local->tm_mon+1, tm_local->tm_mday,
tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
}
*RadTraceStream << msg << " ";*/
PTime now;
*RadTraceStream << now.AsString("MM/dd hh:mm:ss ");
}
if ((RadTraceOptions&Thread) != 0)
{
PThread * thread = PThread::Current();
if (thread == NULL)
*RadTraceStream << setw(23) << "<<SOCKETS RECIEVE>>";
else {
PString name = thread->GetThreadName();
if (name.GetLength() <= 23)
*RadTraceStream << setw(23) << name;
else
*RadTraceStream << name.Left(10) << "..." << name.Right(10);
}
*RadTraceStream << '\t';
//ACE_thread_t threadId = ACE_OS::thr_self ();
//RadTraceStream->width(4);
//*RadTraceStream << threadId << " ";
}
if ((RadTraceOptions&TraceLevel) != 0)
*RadTraceStream << level << '\t';
if ((RadTraceOptions&FileAndLine) != 0 && fileName != NULL) {
const char * file = strrchr(fileName, '/');
if (file != NULL)
file++;
else {
file = strrchr(fileName, '\\');
if (file != NULL)
file++;
else
file = fileName;
}
RadTraceStream->width(12);
*RadTraceStream << file << '(' << lineNum << ")\t";
}
return *RadTraceStream;
}
ostream & RadTrace::End(ostream & s)
{
s.flush();
s << endl;
traceMutex.Signal();
return s;
}
/////////////////////////////////////////////////////////////////////
// RadLogFile begin!
/////////////////////////////////////////////////////////////////////
// if (fOption==e_oneFile), use only one file.
// if (fOption==e_separateFile), 5M is the upper size of log file
int RadLogFile::Init(int level, char * msgLog, char * controlFileName,
int maxSize, RadTrace::FileOption fOption)
{
m_option = fOption;
oldTraceLevel = level;
// Set log file name
memcpy(m_fileName, msgLog, FILE_NAME_LENGTH+1);
m_fileName[FILE_NAME_LENGTH] = 0;
// Set control file name
memcpy(m_controlFile, controlFileName, FILE_NAME_LENGTH+1);
m_controlFile[FILE_NAME_LENGTH] = 0;
if ( maxSize >= 0 )
m_maxLogSize = maxSize;
else
m_maxLogSize = DEFAULT_MAX_LOG_SIZE;
m_totalLogFile = m_maxLogSize * 1000 / (separateFileSize/1000);
if ( m_totalLogFile < 2 )
m_totalLogFile = 2;
// Get start log file number
m_alterNumber = GetNumber();
if ( m_alterNumber < 0 )
m_alterNumber = 1;
RadTrace::SetOptions(RadTrace::DateAndTime);
RadTrace::SetOptions(RadTrace::Thread);
#ifdef ACE_WIN32
#ifdef NDEBUG
RadTrace::ClearOptions(RadTrace::FileAndLine);
#endif
#else
// On Unix, we donot print file name and line number!
RadTrace::ClearOptions(RadTrace::FileAndLine);
#endif
RadTrace::SetLevel( level );
if ( fOption == RadTrace::e_separateFile )
{
InitOpenFile();
}
else {
#ifndef ACE_WIN32
outputPtrace.open(msgLog, ios::out | ios::app);
#else
// "filebuf::sh_read||filebuf::sh_write" make file can be changed by other process.
outputPtrace.open(msgLog, ios::out | ios::app,
filebuf::sh_read || filebuf::sh_write );
#endif
if(outputPtrace.bad() || !outputPtrace.good() ) {
cout << "open log file fail!\n";
return(-1);
}
}
outputPtrace << "\n\n\n\n\n - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
RadTrace::SetStream(&outputPtrace);
RTRACE(1, "Trace logging started.");
// start logger timer
timeLogger.SetNotifier(PCREATE_NOTIFIER(CheckTimer));
timeLogger.RunContinuous(5000);
return 1;
}
int RadLogFile::Close()
{
traceMutex.Wait();
outputPtrace.close();
traceMutex.Signal();
RadTrace::SetStream(&cerr);
return 1;
}
RadLogFile::RadLogFile()
{
m_instance = this;
}
RadLogFile::~RadLogFile()
{
m_instance = NULL;
}
// get size of log file
long RadLogFile::Size()
{
traceMutex.Wait();
outputPtrace.seekp(0, ios::end); // End of file
long s = outputPtrace.tellp(); // Size of file
traceMutex.Signal();
return s;
}
// empty this log file
bool RadLogFile::Empty()
{
traceMutex.Wait();
outputPtrace.close();
outputPtrace.open(m_fileName, ios::out | ios::trunc );
if(outputPtrace.bad() || !outputPtrace.good() ) {
cout << "error, empty log file fail!\n";
traceMutex.Signal();
return(false);
}
RTRACE(1, "Empty the logging file");
//RadTraceStream->seekp(0, ios::beg); // Start of file
//*RadTraceStream << EOF << flush;
traceMutex.Signal();
return true;
}
//return -1 means fail, return value > 1 means success.
int RadLogFile::GetNumber()
{
int ret;
m_controlStream.open(m_controlFile, ios::in);
if( m_controlStream.fail() || m_controlStream.bad() || !m_controlStream.good() )
return -1;
else
m_controlStream >> ret;
m_controlStream.close();
return ret;
}
int RadLogFile::SaveNumber(int num)
{
m_controlStream.clear();
m_controlStream.open(m_controlFile, ios::out | ios::trunc);
if( m_controlStream.bad() || !m_controlStream.good() )
{
outputPtrace << "save log file number fail";
return -1;
}
m_controlStream << num << endl;
m_controlStream.close();
return 0;
}
// When program inital, call this function to open log file.
// get another name of log file, if the old name is X.Y, the new name is :
// "X1.Y", "X2.Y" or "X3.Y",
// return 0 if success, return -1 if fail
int RadLogFile::InitOpenFile()
{
int i, j, len;
// check m_alterNumber value
if ( m_alterNumber > m_totalLogFile )
m_alterNumber = 1;
len = strlen(m_fileName);
for ( j=len-1; j>=0; j--)
{
// get the last directory separate symbol
if ( m_fileName[j] == '\\' || m_fileName[j] == '/' )
break;
}
if(j == -1 ) j = 0; // fix a bug
for ( i=j; i < FILE_NAME_LENGTH && m_fileName[i] != 0; i++)
if ( m_fileName[i] == '.' )
break;
if ( i > FILE_NAME_LENGTH-9 )
return -1;
strncpy( m_alterFileName, m_fileName, i);
sprintf( m_alterFileName+i, "%d", m_alterNumber);
if ( m_fileName[i] != 0 )
strcat(m_alterFileName, m_fileName+i);
#ifndef ACE_WIN32
outputPtrace.open(m_alterFileName, ios::out | ios::app);
#else
outputPtrace.open(m_alterFileName, ios::out | ios::app,
filebuf::sh_read || filebuf::sh_write );
#endif
if(outputPtrace.bad() || !outputPtrace.good() )
{
cout << "open alternate log file fail!\n";
return(-1);
}
if ( m_option == RadTrace::e_separateFile && Size() >= separateFileSize )
{
// we try to open another log file.
outputPtrace << "This log file is full, we open next file";
RunningOpenFile();
}
else
SaveNumber(m_alterNumber);
return 0;
}
// When program is running, call this function to open log file.
// get another name of log file, if the old name is X.Y, the new name is :
// "X1.Y", "X2.Y" or "X3.Y",
// return 0 if success, return -1 if fail
int RadLogFile::RunningOpenFile()
{
int i, j, len;
outputPtrace.close();
m_alterNumber++;
if ( m_alterNumber > m_totalLogFile )
m_alterNumber = 1;
len = strlen(m_fileName);
for ( j=len-1; j>=0; j--)
{
// get the last directory separate symbol
if ( m_fileName[j] == '\\' || m_fileName[j] == '/' )
break;
}
if(j == -1 ) j = 0; // fix a bug
for ( i=j; i < FILE_NAME_LENGTH && m_fileName[i] != 0; i++)
if ( m_fileName[i] == '.' )
break;
if ( i > FILE_NAME_LENGTH-9 )
return -1;
strncpy( m_alterFileName, m_fileName, i);
sprintf( m_alterFileName+i, "%d", m_alterNumber);
if ( m_fileName[i] != 0 )
strcat(m_alterFileName, m_fileName+i);
#ifndef ACE_WIN32
outputPtrace.open(m_alterFileName, ios::out | ios::trunc );
#else
outputPtrace.open(m_alterFileName, ios::out | ios::trunc,
filebuf::sh_read || filebuf::sh_write );
#endif
if(outputPtrace.bad() || !outputPtrace.good() )
{
cout << "open alternate log file fail!\n";
return(-1);
}
SaveNumber(m_alterNumber);
return 0;
}
///////////////////////////////////////////////////////////////////////
// class CLogTimer
///////////////////////////////////////////////////////////////////////
//int CLogTimer::handle_timeout( const ACE_Time_Value & tv, const void * arg){
void RadLogFile::CheckTimer(PTimer &, INT)
{
long size;
RTRACE(6, "Enter log timer");
switch ( RadLogFile::Instance()->m_option ) {
case RadTrace::e_oneFile:
{
size = RadLogFile::Instance()->Size();
int level = RadTrace::GetLevel();
RTRACE(4, "Log file size = " << size << "\tlevel = " << level );
if ( size > WARN_SIZE5 ) {
if ( level > 0 )
RadTrace::SetLevel(0);
}
else if ( size > WARN_SIZE4 ) {
if ( level > 1 )
RadTrace::SetLevel(1);
}
else if ( size > WARN_SIZE3 ) {
if ( level > 2 )
RadTrace::SetLevel(2);
}
else if ( size > WARN_SIZE2 ) {
if ( level > 3 )
RadTrace::SetLevel(3);
}
else if ( size > WARN_SIZE1 ) {
if ( level > 4 )
RadTrace::SetLevel(4);
}
else {
RadTrace::SetLevel(oldTraceLevel);
}
}
break;
case RadTrace::e_separateFile:
size = RadLogFile::Instance()->Size();
if ( size >= separateFileSize )
{
// we try to open another log file.
traceMutex.Wait();
RadLogFile::Instance()->RunningOpenFile();
traceMutex.Signal();
}
break;
default:
break;
}
//return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -