// Copyright (C) 2011 Kornel Kisielewicz // This file is part of NV Libraries. // For conditions of distribution and use, see copyright notice in nv.hh #include "nv/logger.hh" #include #include #include #include #include using namespace nv; // log level names const char *log_level_names[] = { "NONE", "FATAL", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "INFO", "DEBUG", "DEBUG2", "TRACE" }; // helper macro to access log_level_names #define NV_LOG_LEVEL_NAME(level) (log_level_names[ (level) / 10 ]) // log function void logger::log( log_level level, const std::string& message ) { // get the iterator to the beginning of the log_sink list log_sink_list::reverse_iterator it = m_log_sinks.rbegin(); // iterate while ( it != m_log_sinks.rend() ) { // if we have a log sink with high enough level... if ( it->first >= level ) { // log and iterate it->second->log( level, message ); } else { // otherwise return, the list is sorted by log level return; } ++it; } } // add a new sink void logger::add_sink( log_sink* sink, int level ) { // add a sink m_log_sinks.push_back( std::make_pair( log_level(level), sink ) ); // and sort the list (default sort of pairs is by first element) m_log_sinks.sort(); } // remove existing sink bool logger::remove_sink( log_sink* sink ) { // get the iterator to the beginning of the log_sink list log_sink_list::iterator it = m_log_sinks.begin(); // iterate while ( it != m_log_sinks.end() ) { // found? if ( it->second == sink ) { // erase and return true to report success m_log_sinks.erase(it); return true; } ++it; } // not found, return false return false; } // destructor logger::~logger() { // while we have sinks while ( !m_log_sinks.empty() ) { // delete the last one delete m_log_sinks.back().second; // and pop it m_log_sinks.pop_back(); } } // console logging void log_console_sink::log( log_level level, const std::string& message ) { std::cout << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << std::endl; } // stream logging void log_stream_sink::log( log_level level, const std::string& message ) { // if flushing is enabled if ( m_flush ) { // write and flush using std::endl *m_stream << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << std::endl; } else { // write and end with "\n" (no flush) *m_stream << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << "\n"; } } // file logging log_file_sink::log_file_sink( const std::string file_name, bool flush_always /*= true */ ) : log_stream_sink( nullptr, flush_always ) { // create the stream manually std::ofstream* fstream = new std::ofstream( file_name ); // check if it's open if ( !fstream->is_open() ) { // throw if not open throw runtime_error( "Could not open file \""+file_name+"\" for logging!" ); } m_stream = fstream; } // file logger destructor log_file_sink::~log_file_sink() { // close the file dynamic_cast< std::ofstream* >(m_stream)->close(); // dispose of the stream delete m_stream; }