source: trunk/src/logger.cc @ 245

Last change on this file since 245 was 204, checked in by cahir, 12 years ago

Fix warnings on MacOSX 64-bit with clang 3.3

File size: 5.8 KB
Line 
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 "nv/common.hh"
8#include <iostream>
9#include <utility>
10#include <algorithm>
11#include <fstream>
12#include <ctime>
13#include <cstdio>
14#include <nv/exception.hh>
15#if NV_PLATFORM == NV_WINDOWS
16#define WIN32_LEAN_AND_MEAN
17#include <Windows.h>
18#endif
19
20using namespace nv;
21
22// log level names
23static const char *log_level_names[] =
24{
25        "NONE",
26        "FATAL",
27        "CRITICAL",
28        "ERROR",
29        "WARNING",
30        "NOTICE",
31        "INFO",
32        "INFO",
33        "DEBUG",
34        "DEBUG2",
35        "TRACE"
36};
37
38// log level names
39static const char *log_level_names_pad[] =
40{
41        "NONE    ",
42        "FATAL   ",
43        "CRITICAL",
44        "ERROR   ",
45        "WARNING ",
46        "NOTICE  ",
47        "INFO    ",
48        "INFO    ",
49        "DEBUG   ",
50        "DEBUG2  ",
51        "TRACE   "
52};
53
54// helper macro to access log_level_names
55#define NV_LOG_LEVEL_NAME(level) (log_level_names[ (level) / 10 ])
56#define NV_LOG_LEVEL_NAME_PAD(level) (log_level_names_pad[ (level) / 10 ])
57
58#if NV_PLATFORM == NV_WINDOWS
59static unsigned short log_color[] =
60{
61        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
62        FOREGROUND_RED | FOREGROUND_INTENSITY,
63        FOREGROUND_RED | FOREGROUND_INTENSITY,
64        FOREGROUND_RED,
65        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
66        FOREGROUND_GREEN | FOREGROUND_INTENSITY,
67        FOREGROUND_GREEN,
68        FOREGROUND_GREEN,
69        FOREGROUND_INTENSITY,
70        FOREGROUND_INTENSITY,
71        FOREGROUND_INTENSITY
72};
73#else
74static const char *log_color[] =
75{
76        "\33[37;1m",
77        "\33[31;1m",
78        "\33[31;1m",
79        "\33[31m",
80        "\33[33;1m",
81        "\33[32;1m",
82        "\33[32m",
83        "\33[32m",
84        "\33[30;1m",
85        "\33[30;1m",
86        "\33[30;1m"
87};
88#endif
89
90// log function
91void logger::log( log_level level, const std::string& message )
92{
93        // get the iterator to the beginning of the log_sink list
94        log_sink_list::reverse_iterator it = m_log_sinks.rbegin();
95
96        // iterate
97        while ( it != m_log_sinks.rend() )
98        {
99                // if we have a log sink with high enough level...
100                if ( it->first >= level )
101                {
102                        // log and iterate
103                        it->second->log( level, message );
104                }
105                else
106                {
107                        // otherwise return, the list is sorted by log level
108                        return;
109                }
110                ++it;
111        }
112}
113
114// add a new sink
115void logger::add_sink( log_sink* sink, int level )
116{
117        // add a sink
118        m_log_sinks.push_back( std::make_pair( log_level(level), sink ) );
119        // and sort the list (default sort of pairs is by first element)
120        m_log_sinks.sort();
121}
122
123// remove existing sink
124bool logger::remove_sink( log_sink* sink )
125{
126        // get the iterator to the beginning of the log_sink list
127        log_sink_list::iterator it = m_log_sinks.begin();
128
129        // iterate
130        while ( it != m_log_sinks.end() )
131        {
132                // found?
133                if ( it->second == sink )
134                {
135                        // erase and return true to report success
136                        m_log_sinks.erase(it);
137                        return true;
138                }
139                ++it;
140        }
141
142        // not found, return false
143        return false;
144}
145
146// destructor
147logger::~logger()
148{
149        // while we have sinks
150        while ( !m_log_sinks.empty() )
151        {
152                // delete the last one
153                delete m_log_sinks.back().second;
154                // and pop it
155                m_log_sinks.pop_back();
156        }
157}
158
159
160// console logging
161void log_console_sink::log( log_level level, const std::string& message )
162{
163        if (m_color)
164        {
165#if NV_PLATFORM == NV_WINDOWS
166                SetConsoleTextAttribute( m_handle, FOREGROUND_INTENSITY );
167                std::cout << timestamp() << " [";
168                SetConsoleTextAttribute( m_handle, log_color[ (level) / 10 ] );
169                std::cout << NV_LOG_LEVEL_NAME_PAD(level);
170                SetConsoleTextAttribute( m_handle, FOREGROUND_INTENSITY );
171                std::cout << "] ";
172                SetConsoleTextAttribute( m_handle, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
173                std::cout << message << std::endl;
174#else
175                std::cout << "\33[30;1m" << timestamp() << " [" << log_color[ (level) / 10 ] << NV_LOG_LEVEL_NAME_PAD(level) << "\33[30;1m] \33[37;1m" << message << std::endl;
176#endif
177        }
178        else
179        {
180        std::cout << timestamp() << " [" << NV_LOG_LEVEL_NAME_PAD(level) << "] " << message << std::endl;
181        }
182}
183
184// stream logging
185void log_stream_sink::log( log_level level, const std::string& message )
186{
187        // if flushing is enabled
188        if ( m_flush )
189        {
190                // write and flush using std::endl
191                *m_stream << timestamp() << " [" << NV_LOG_LEVEL_NAME(level) << "] " << message << std::endl;
192        }
193        else
194        {
195                // write and end with "\n" (no flush)
196                *m_stream << timestamp() << " [" << NV_LOG_LEVEL_NAME(level) << "] " << message << "\n";
197        }
198}
199
200// file logging
201log_file_sink::log_file_sink( const std::string file_name, bool flush_always /*= true */ )
202        : log_stream_sink( nullptr, flush_always )
203{
204        // create the stream manually
205        std::ofstream* fstream = new std::ofstream( file_name );
206
207        // check if it's open
208        if ( !fstream->is_open() )
209        {
210                // throw if not open
211                NV_THROW( runtime_error, "Could not open file \""+file_name+"\" for logging!" );
212        }
213
214        m_stream = fstream;
215}
216
217// file logger destructor
218log_file_sink::~log_file_sink()
219{
220        // close the file
221        dynamic_cast< std::ofstream* >(m_stream)->close();
222        // dispose of the stream
223        delete m_stream;
224}
225
226nv::log_console_sink::log_console_sink( bool coloring )
227        : m_color( coloring )
228{
229#if NV_PLATFORM == NV_WINDOWS
230        m_handle = GetStdHandle( STD_OUTPUT_HANDLE );
231#else
232  NV_UNUSED( m_handle );
233#endif
234}
235
236const char* nv::log_sink::timestamp() const
237{
238        std::clock_t time = std::clock();
239        unsigned int secs = (unsigned int)(time / CLOCKS_PER_SEC);
240        unsigned int mm   = (unsigned int)(time*100 / CLOCKS_PER_SEC) % 100;
241        unsigned int h    = (unsigned int)(secs / (60*60));
242        unsigned int m    = (unsigned int)(secs / 60) % 60;
243        unsigned int s    = secs % 60;
244        static char buffer[128];
245#if NV_PLATFORM == NV_WINDOWS
246        sprintf_s( buffer, 128, "%02d:%02d:%02d.%02d", h, m, s, mm );
247#else
248        sprintf( buffer, "%02d:%02d:%02d.%02d", h, m, s, mm );
249#endif
250        buffer[11] = '\0';
251        return buffer;
252}
Note: See TracBrowser for help on using the repository browser.