[4] | 1 | // Copyright (C) 2011 Kornel Kisielewicz
|
---|
| 2 | // This file is part of NV Libraries.
|
---|
| 3 | // For conditions of distribution and use, see copyright notice in nv.hh
|
---|
| 4 |
|
---|
| 5 | #include "nv/logger.hh"
|
---|
| 6 |
|
---|
| 7 | #include <iostream>
|
---|
| 8 | #include <utility>
|
---|
| 9 | #include <algorithm>
|
---|
| 10 | #include <fstream>
|
---|
| 11 | #include <nv/exception.hh>
|
---|
| 12 |
|
---|
| 13 | using namespace nv;
|
---|
| 14 |
|
---|
| 15 | // log level names
|
---|
| 16 | const char *log_level_names[] =
|
---|
| 17 | {
|
---|
| 18 | "NONE",
|
---|
| 19 | "FATAL",
|
---|
| 20 | "CRITICAL",
|
---|
| 21 | "ERROR",
|
---|
| 22 | "WARNING",
|
---|
| 23 | "NOTICE",
|
---|
| 24 | "INFO",
|
---|
| 25 | "INFO",
|
---|
| 26 | "DEBUG",
|
---|
| 27 | "DEBUG2",
|
---|
| 28 | "TRACE"
|
---|
| 29 | };
|
---|
| 30 |
|
---|
| 31 | // helper macro to access log_level_names
|
---|
| 32 | #define NV_LOG_LEVEL_NAME(level) (log_level_names[ (level) / 10 ])
|
---|
| 33 |
|
---|
| 34 | // log function
|
---|
| 35 | void logger::log( log_level level, const std::string& message )
|
---|
| 36 | {
|
---|
| 37 | // get the iterator to the beginning of the log_sink list
|
---|
| 38 | log_sink_list::reverse_iterator it = m_log_sinks.rbegin();
|
---|
| 39 |
|
---|
| 40 | // iterate
|
---|
| 41 | while ( it != m_log_sinks.rend() )
|
---|
| 42 | {
|
---|
| 43 | // if we have a log sink with high enough level...
|
---|
| 44 | if ( it->first >= level )
|
---|
| 45 | {
|
---|
| 46 | // log and iterate
|
---|
| 47 | it->second->log( level, message );
|
---|
| 48 | }
|
---|
| 49 | else
|
---|
| 50 | {
|
---|
| 51 | // otherwise return, the list is sorted by log level
|
---|
| 52 | return;
|
---|
| 53 | }
|
---|
| 54 | ++it;
|
---|
| 55 | }
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | // add a new sink
|
---|
| 59 | void logger::add_sink( log_sink* sink, int level )
|
---|
| 60 | {
|
---|
| 61 | // add a sink
|
---|
| 62 | m_log_sinks.push_back( std::make_pair( log_level(level), sink ) );
|
---|
| 63 | // and sort the list (default sort of pairs is by first element)
|
---|
| 64 | m_log_sinks.sort();
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | // remove existing sink
|
---|
| 68 | bool logger::remove_sink( log_sink* sink )
|
---|
| 69 | {
|
---|
| 70 | // get the iterator to the beginning of the log_sink list
|
---|
| 71 | log_sink_list::iterator it = m_log_sinks.begin();
|
---|
| 72 |
|
---|
| 73 | // iterate
|
---|
| 74 | while ( it != m_log_sinks.end() )
|
---|
| 75 | {
|
---|
| 76 | // found?
|
---|
| 77 | if ( it->second == sink )
|
---|
| 78 | {
|
---|
| 79 | // erase and return true to report success
|
---|
| 80 | m_log_sinks.erase(it);
|
---|
| 81 | return true;
|
---|
| 82 | }
|
---|
| 83 | ++it;
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | // not found, return false
|
---|
| 87 | return false;
|
---|
| 88 | }
|
---|
| 89 |
|
---|
| 90 | // destructor
|
---|
| 91 | logger::~logger()
|
---|
| 92 | {
|
---|
| 93 | // while we have sinks
|
---|
| 94 | while ( !m_log_sinks.empty() )
|
---|
| 95 | {
|
---|
| 96 | // delete the last one
|
---|
| 97 | delete m_log_sinks.back().second;
|
---|
| 98 | // and pop it
|
---|
| 99 | m_log_sinks.pop_back();
|
---|
| 100 | }
|
---|
| 101 | }
|
---|
| 102 |
|
---|
| 103 |
|
---|
| 104 | // console logging
|
---|
| 105 | void log_console_sink::log( log_level level, const std::string& message )
|
---|
| 106 | {
|
---|
| 107 | std::cout << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << std::endl;
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | // stream logging
|
---|
| 111 | void log_stream_sink::log( log_level level, const std::string& message )
|
---|
| 112 | {
|
---|
| 113 | // if flushing is enabled
|
---|
| 114 | if ( m_flush )
|
---|
| 115 | {
|
---|
| 116 | // write and flush using std::endl
|
---|
| 117 | *m_stream << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << std::endl;
|
---|
| 118 | }
|
---|
| 119 | else
|
---|
| 120 | {
|
---|
| 121 | // write and end with "\n" (no flush)
|
---|
| 122 | *m_stream << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << "\n";
|
---|
| 123 | }
|
---|
| 124 | }
|
---|
| 125 |
|
---|
| 126 | // file logging
|
---|
| 127 | log_file_sink::log_file_sink( const std::string file_name, bool flush_always /*= true */ )
|
---|
| 128 | : log_stream_sink( nullptr, flush_always )
|
---|
| 129 | {
|
---|
| 130 | // create the stream manually
|
---|
| 131 | std::ofstream* fstream = new std::ofstream( file_name );
|
---|
| 132 |
|
---|
| 133 | // check if it's open
|
---|
| 134 | if ( !fstream->is_open() )
|
---|
| 135 | {
|
---|
| 136 | // throw if not open
|
---|
| 137 | throw runtime_error( "Could not open file \""+file_name+"\" for logging!" );
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | m_stream = fstream;
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | // file logger destructor
|
---|
| 144 | log_file_sink::~log_file_sink()
|
---|
| 145 | {
|
---|
| 146 | // close the file
|
---|
| 147 | dynamic_cast< std::ofstream* >(m_stream)->close();
|
---|
| 148 | // dispose of the stream
|
---|
| 149 | delete m_stream;
|
---|
| 150 | }
|
---|