335 lines
9.9 KiB
C++
335 lines
9.9 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// Log.cpp
|
|
//
|
|
// Cross-platform message and error logging
|
|
//
|
|
// Copyright (c) 2010 Mal Lansell <mal@lansell.org>
|
|
// All rights reserved.
|
|
//
|
|
// SOFTWARE NOTICE AND LICENSE
|
|
//
|
|
// This file is part of OpenZWave.
|
|
//
|
|
// OpenZWave is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published
|
|
// by the Free Software Foundation, either version 3 of the License,
|
|
// or (at your option) any later version.
|
|
//
|
|
// OpenZWave 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 Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#include <stdarg.h>
|
|
|
|
#include "../Defs.h"
|
|
#include "Mutex.h"
|
|
#include "Log.h"
|
|
|
|
#ifdef _WIN32
|
|
#include "windows/LogImpl.h" // Platform-specific implementation of a log
|
|
#else
|
|
#include "unix/LogImpl.h" // Platform-specific implementation of a log
|
|
#endif
|
|
|
|
|
|
using namespace OpenZWave;
|
|
|
|
char const *OpenZWave::LogLevelString[] =
|
|
{
|
|
"None", /**< LogLevel_None Disable all logging */
|
|
"Always", /**< LogLevel_Always These messages should always be shown */
|
|
"Fatal", /**< LogLevel_Fatal A likely fatal issue in the library */
|
|
"Error", /**< LogLevel_Error A serious issue with the library or the network */
|
|
"Warning", /**< LogLevel_Warning A minor issue from which the library should be able to recover */
|
|
"Alert", /**< LogLevel_Alert Something unexpected by the library about which the controlling application should be aware */
|
|
"Info", /**< LogLevel_Info Everything's working fine...these messages provide streamlined feedback on each message */
|
|
"Detail", /**< LogLevel_Detail Detailed information on the progress of each message */
|
|
"Debug", /**< LogLevel_Debug Very detailed information on progress that will create a huge log file quickly
|
|
But this level (as others) can be queued and sent to the log only on an error or warning */
|
|
"StreamDetail", /**< LogLevel_StreamDetail Will include low-level byte transfers from controller to buffer to application and back */
|
|
"Internal" /**< LogLevel_Internal Used only within the log class (uses existing timestamp, etc.) */
|
|
};
|
|
|
|
|
|
|
|
Log* Log::s_instance = NULL;
|
|
i_LogImpl* Log::m_pImpl = NULL;
|
|
static bool s_dologging;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::Create>
|
|
// Static creation of the singleton
|
|
//-----------------------------------------------------------------------------
|
|
Log* Log::Create
|
|
(
|
|
string const& _filename,
|
|
bool const _bAppend,
|
|
bool const _bConsoleOutput,
|
|
LogLevel const _saveLevel,
|
|
LogLevel const _queueLevel,
|
|
LogLevel const _dumpTrigger
|
|
)
|
|
{
|
|
if( NULL == s_instance )
|
|
{
|
|
s_instance = new Log( _filename, _bAppend, _bConsoleOutput, _saveLevel, _queueLevel, _dumpTrigger );
|
|
s_dologging = true; // default logging to true so no change to what people experience now
|
|
}
|
|
|
|
return s_instance;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::Create>
|
|
// Static creation of the singleton
|
|
//-----------------------------------------------------------------------------
|
|
/* It isn't clear this is ever called or used. If no one complains, consider
|
|
deleting this code in April 2012.
|
|
Log* Log::Create
|
|
(
|
|
i_LogImpl *LogClass
|
|
)
|
|
{
|
|
if (NULL == s_instance )
|
|
{
|
|
s_instance = new Log( "" );
|
|
s_dologging = true;
|
|
}
|
|
SetLoggingClass( LogClass );
|
|
return s_instance;
|
|
}
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::Destroy>
|
|
// Static method to destroy the logging singleton.
|
|
//-----------------------------------------------------------------------------
|
|
void Log::Destroy
|
|
(
|
|
)
|
|
{
|
|
delete s_instance;
|
|
s_instance = NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::SetLoggingClass>
|
|
// Set log class
|
|
//-----------------------------------------------------------------------------
|
|
bool Log::SetLoggingClass
|
|
(
|
|
i_LogImpl *LogClass
|
|
)
|
|
{
|
|
delete m_pImpl;
|
|
m_pImpl = LogClass;
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::SetLoggingState>
|
|
// Set flag to actually write to log or skip it (legacy version)
|
|
// If logging is enabled, the default log detail settings will be used
|
|
// Write to file/screen LogLevel_Detail
|
|
// Save in queue for errors LogLevel_Debug
|
|
// Trigger for dumping queue LogLevel_Warning
|
|
// Console output? Yes
|
|
// Append to an existing log? No (overwrite)
|
|
//-----------------------------------------------------------------------------
|
|
void Log::SetLoggingState
|
|
(
|
|
bool _dologging
|
|
)
|
|
{
|
|
bool prevLogging = s_dologging;
|
|
s_dologging = _dologging;
|
|
|
|
if (!prevLogging && s_dologging) Log::Write(LogLevel_Always, "Logging started\n\n");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::SetLoggingState>
|
|
// Set flag to actually write to log or skip it
|
|
//-----------------------------------------------------------------------------
|
|
void Log::SetLoggingState
|
|
(
|
|
LogLevel _saveLevel,
|
|
LogLevel _queueLevel,
|
|
LogLevel _dumpTrigger
|
|
)
|
|
{
|
|
// parameter checking:
|
|
// _queueLevel cannot be less than or equal to _saveLevel (where lower ordinals are more severe conditions)
|
|
// _dumpTrigger cannot be greater than or equal to _queueLevel
|
|
if( _queueLevel <= _saveLevel )
|
|
Log::Write( LogLevel_Warning, "Only lower priority messages may be queued for error-driven display." );
|
|
if( _dumpTrigger >= _queueLevel )
|
|
Log::Write( LogLevel_Warning, "The trigger for dumping queued messages must be a higher-priority message than the level that is queued." );
|
|
|
|
bool prevLogging = s_dologging;
|
|
// s_dologging is true if any messages are to be saved in file or queue
|
|
if( (_saveLevel > LogLevel_Always) ||
|
|
(_queueLevel > LogLevel_Always) )
|
|
{
|
|
s_dologging = true;
|
|
}
|
|
else
|
|
{
|
|
s_dologging = false;
|
|
}
|
|
|
|
if( s_instance && s_dologging && s_instance->m_pImpl )
|
|
{
|
|
s_instance->m_logMutex->Lock();
|
|
s_instance->m_pImpl->SetLoggingState( _saveLevel, _queueLevel, _dumpTrigger );
|
|
s_instance->m_logMutex->Unlock();
|
|
}
|
|
|
|
if (!prevLogging && s_dologging) Log::Write(LogLevel_Always, "Logging started\n\n");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::GetLoggingState>
|
|
// Return a flag to indicate whether logging is enabled
|
|
//-----------------------------------------------------------------------------
|
|
bool Log::GetLoggingState
|
|
(
|
|
)
|
|
{
|
|
return s_dologging;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::Write>
|
|
// Write to the log
|
|
//-----------------------------------------------------------------------------
|
|
void Log::Write
|
|
(
|
|
LogLevel _level,
|
|
char const* _format,
|
|
...
|
|
)
|
|
{
|
|
if( s_instance && s_dologging && s_instance->m_pImpl )
|
|
{
|
|
s_instance->m_logMutex->Lock(); // double locks if recursive
|
|
va_list args;
|
|
va_start( args, _format );
|
|
s_instance->m_pImpl->Write( _level, 0, _format, args );
|
|
va_end( args );
|
|
s_instance->m_logMutex->Unlock();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::Write>
|
|
// Write to the log
|
|
//-----------------------------------------------------------------------------
|
|
void Log::Write
|
|
(
|
|
LogLevel _level,
|
|
uint8 const _nodeId,
|
|
char const* _format,
|
|
...
|
|
)
|
|
{
|
|
if( s_instance && s_dologging && s_instance->m_pImpl )
|
|
{
|
|
if( _level != LogLevel_Internal )
|
|
s_instance->m_logMutex->Lock();
|
|
va_list args;
|
|
va_start( args, _format );
|
|
s_instance->m_pImpl->Write( _level, _nodeId, _format, args );
|
|
va_end( args );
|
|
if( _level != LogLevel_Internal )
|
|
s_instance->m_logMutex->Unlock();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::QueueDump>
|
|
// Send queued messages to the log (and empty the queue)
|
|
//-----------------------------------------------------------------------------
|
|
void Log::QueueDump
|
|
(
|
|
)
|
|
{
|
|
if( s_instance && s_dologging && s_instance->m_pImpl )
|
|
{
|
|
s_instance->m_logMutex->Lock();
|
|
s_instance->m_pImpl->QueueDump();
|
|
s_instance->m_logMutex->Unlock();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::QueueClear>
|
|
// Empty the queued message queue
|
|
//-----------------------------------------------------------------------------
|
|
void Log::QueueClear
|
|
(
|
|
)
|
|
{
|
|
if( s_instance && s_dologging && s_instance->m_pImpl )
|
|
{
|
|
s_instance->m_logMutex->Lock();
|
|
s_instance->m_pImpl->QueueClear();
|
|
s_instance->m_logMutex->Unlock();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::SetLogFileName>
|
|
// Change the name of the log file (will start writing a new file)
|
|
//-----------------------------------------------------------------------------
|
|
void Log::SetLogFileName
|
|
(
|
|
const string &_filename
|
|
)
|
|
{
|
|
if( s_instance && s_dologging && s_instance->m_pImpl )
|
|
{
|
|
s_instance->m_logMutex->Lock();
|
|
s_instance->m_pImpl->SetLogFileName( _filename );
|
|
s_instance->m_logMutex->Unlock();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::Log>
|
|
// Constructor
|
|
//-----------------------------------------------------------------------------
|
|
Log::Log
|
|
(
|
|
string const& _filename,
|
|
bool const _bAppend,
|
|
bool const _bConsoleOutput,
|
|
LogLevel const _saveLevel,
|
|
LogLevel const _queueLevel,
|
|
LogLevel const _dumpTrigger
|
|
):
|
|
m_logMutex( new Mutex() )
|
|
{
|
|
if (NULL == m_pImpl)
|
|
m_pImpl = new LogImpl( _filename, _bAppend, _bConsoleOutput, _saveLevel, _queueLevel, _dumpTrigger );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// <Log::~Log>
|
|
// Destructor
|
|
//-----------------------------------------------------------------------------
|
|
Log::~Log
|
|
(
|
|
)
|
|
{
|
|
m_logMutex->Release();
|
|
delete m_pImpl;
|
|
m_pImpl = NULL;
|
|
}
|