source: trunk/src/core/logger.cc @ 376

Last change on this file since 376 was 376, checked in by epyon, 10 years ago
  • stl/assert.hh, stl/capi.hh, size_t independent
  • GCC 4.8 compatibility
  • using template usage
  • various minor changes
File size: 6.9 KB
Line 
1// Copyright (C) 2011-2014 ChaosForge Ltd
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/core/logger.hh"
6
7#include "nv/core/common.hh"
8#include "nv/core/time.hh"
9#include <cstdio>
10#if NV_COMPILER == NV_MSVC
11#define WIN32_LEAN_AND_MEAN
12#include <Windows.h>
13#endif
14
15using namespace nv;
16
17// log level names
18static const char *log_level_names[] =
19{
20        "NONE",
21        "FATAL",
22        "CRITICAL",
23        "ERROR",
24        "WARNING",
25        "NOTICE",
26        "INFO",
27        "INFO",
28        "DEBUG",
29        "DEBUG2",
30        "TRACE"
31};
32
33// log level names
34static const char *log_level_names_pad[] =
35{
36        "NONE    ",
37        "FATAL   ",
38        "CRITICAL",
39        "ERROR   ",
40        "WARNING ",
41        "NOTICE  ",
42        "INFO    ",
43        "INFO    ",
44        "DEBUG   ",
45        "DEBUG2  ",
46        "TRACE   "
47};
48
49// helper macro to access log_level_names
50#define NV_LOG_LEVEL_NAME(level) (log_level_names[ (level) / 10 ])
51#define NV_LOG_LEVEL_NAME_PAD(level) (log_level_names_pad[ (level) / 10 ])
52
53#if NV_COMPILER == NV_MSVC
54static unsigned short log_color[] =
55{
56        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
57        FOREGROUND_RED | FOREGROUND_INTENSITY,
58        FOREGROUND_RED | FOREGROUND_INTENSITY,
59        FOREGROUND_RED,
60        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
61        FOREGROUND_GREEN | FOREGROUND_INTENSITY,
62        FOREGROUND_GREEN,
63        FOREGROUND_GREEN,
64        FOREGROUND_INTENSITY,
65        FOREGROUND_INTENSITY,
66        FOREGROUND_INTENSITY
67};
68#else
69static const char *log_color[] =
70{
71        "\33[37;1m",
72        "\33[31;1m",
73        "\33[31;1m",
74        "\33[31m",
75        "\33[33;1m",
76        "\33[32;1m",
77        "\33[32m",
78        "\33[32m",
79        "\33[30;1m",
80        "\33[30;1m",
81        "\33[30;1m"
82};
83#endif
84
85// log function
86void logger::log( log_level level, const string_ref& message )
87{
88        for ( auto& sink_info : m_log_sinks )
89        {
90                if ( sink_info.sink && (sink_info.level >= (uint32)level) )
91                {
92                        // log and iterate
93                        sink_info.sink->log( level, message );
94                }
95        }
96}
97
98// add a new sink
99void logger::add_sink( log_sink* sink, int level )
100{
101        // add a sink
102        for ( auto& sink_info : m_log_sinks )
103        {
104                if ( sink_info.sink == nullptr )
105                {
106                        sink_info.sink  = sink;
107                        sink_info.level = (uint32)level;
108                        return;
109                }
110        }
111        NV_ASSERT( false, "ran out of log sink space!" );
112}
113
114// remove existing sink
115bool logger::remove_sink( log_sink* sink )
116{
117        for ( auto& sink_info : m_log_sinks )
118        {
119                if ( sink_info.sink == sink )
120                {
121                        delete sink_info.sink;
122                        sink_info.sink = nullptr;
123                        return true;
124                }
125        }
126        // not found, return false
127        return false;
128}
129
130// destructor
131logger::~logger()
132{
133        // delete all sinks
134        for ( auto& sink_info : m_log_sinks )
135        {
136                delete sink_info.sink;
137        }
138}
139
140
141// console logging
142void log_console_sink::log( log_level level, const string_ref& message )
143{
144        char stamp[16];
145        size_t ssize = timestamp( stamp );
146
147#if NV_COMPILER == NV_MSVC
148        if ( m_color ) SetConsoleTextAttribute( m_handle, FOREGROUND_INTENSITY );
149        WriteConsole( m_handle, stamp, ssize, nullptr, nullptr );
150        WriteConsole( m_handle, " [", 2, nullptr, nullptr );
151        if (m_color) SetConsoleTextAttribute( m_handle, log_color[( level ) / 10] );
152        WriteConsole( m_handle, NV_LOG_LEVEL_NAME_PAD( level ), 8, nullptr, nullptr );
153        if ( m_color ) SetConsoleTextAttribute( m_handle, FOREGROUND_INTENSITY );
154        WriteConsole( m_handle, "] ", 2, nullptr, nullptr );
155        if ( m_color ) SetConsoleTextAttribute( m_handle, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
156        WriteConsole( m_handle, message.data(), message.size(), nullptr, nullptr );
157        WriteConsole( m_handle, "\n", 1, nullptr, nullptr );
158#else
159        if ( m_color ) fwrite( "\33[30;1m", 7, 1, stdout );
160        fwrite( stamp, ssize, 1, stdout );
161        fwrite( " [", 2, 1, stdout );
162        if ( m_color )
163        {
164                const char* lcolor = log_color[( level ) / 10];
165                fwrite( lcolor, strlen(lcolor), 1, stdout );
166        }
167        fwrite( NV_LOG_LEVEL_NAME_PAD( level ), 8, 1, stdout );
168        if ( m_color )
169                fwrite( "\33[30;1m] \33[37;1m", 16, 1, stdout );
170        else
171                fwrite( "] ", 2, 1, stdout );
172        fwrite( message.data(), message.size(), 1, stdout );
173        fwrite( "\n", 1, 1, stdout );
174#endif
175}
176
177// handle logging
178void log_handle_sink::log( log_level level, const string_ref& message )
179{
180        char stamp[16];
181        size_t ssize = timestamp( stamp );
182#if 0 // NV_PLATFORM == NV_WINDOWS
183        // Turns out WriteFile on Windows is unbuffered and quite slower than fwrite
184        // due to this fact -- especially UNUSABLE with manual FlushFileBuffers
185        // If we want to get rid of C runtime, this would need a buffered I/O layer.
186        DWORD unused = 0;
187        WriteFile( m_handle, stamp, ssize, &unused, nullptr );
188        WriteFile( m_handle, " [", 2, &unused, nullptr );
189        WriteFile( m_handle, NV_LOG_LEVEL_NAME_PAD( level ), 8, &unused, nullptr );
190        WriteFile( m_handle, "] ", 2, &unused, nullptr );
191        WriteFile( m_handle, message.data(), message.size(), &unused, nullptr );
192        WriteFile( m_handle, "\n", 1, &unused, nullptr );
193        //if ( m_flush ) FlushFileBuffers( m_handle );
194#else
195        fwrite( stamp, ssize, 1, (FILE*)m_handle );
196        fwrite( " [", 2, 1, (FILE*)m_handle );
197        fwrite( NV_LOG_LEVEL_NAME_PAD( level ), 8, 1, (FILE*)m_handle );
198        fwrite( "] ", 2, 1, (FILE*)m_handle );
199        fwrite( message.data(), message.size(), 1, (FILE*)m_handle );
200        fwrite( "\n", 1, 1, (FILE*)m_handle );
201        if ( m_flush ) fflush( (FILE*)m_handle );
202#endif
203}
204
205nv::log_file_sink::log_file_sink( const string_ref& file_name, bool flush_always /*= true */ )
206        : log_handle_sink( nullptr, flush_always )
207{
208#if 0 // NV_PLATFORM == NV_WINDOWS
209        // See comments in log_handle_sink
210        HANDLE handle = CreateFile( file_name.data(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr );
211        if ( INVALID_HANDLE_VALUE == handle )
212        {
213                NV_ASSERT( false, "invalid log handle" );
214        }
215        m_handle = handle;
216#else
217        m_handle = fopen( file_name.data(), "w" );
218#endif
219}
220
221nv::log_file_sink::~log_file_sink()
222{
223#if 0 // NV_PLATFORM == NV_WINDOWS
224        // See comments in log_handle_sink
225        CloseHandle( m_handle );
226#else
227        fclose( (FILE*) m_handle );
228#endif
229}
230
231
232nv::log_console_sink::log_console_sink( bool coloring )
233        : m_color( coloring )
234{
235#if NV_COMPILER == NV_MSVC
236        m_handle = GetStdHandle( STD_OUTPUT_HANDLE );
237#else
238  NV_UNUSED( m_handle );
239#endif
240}
241
242nv::size_t nv::log_sink::timestamp( char* buffer ) const
243{
244        uint32 ms = get_system_ms();
245        unsigned int secs = (unsigned int)(ms / 1000);
246        unsigned int mm   = (unsigned int)( ms * 100 / 1000 ) % 100;
247        unsigned int h    = (unsigned int)(secs / (60*60));
248        unsigned int m    = (unsigned int)(secs / 60) % 60;
249        unsigned int s    = secs % 60;
250#if NV_COMPILER == NV_MSVC
251        sprintf_s( buffer, 16, "%02d:%02d:%02d.%02d", h, m, s, mm );
252#else
253        snprintf( buffer, 16, "%02d:%02d:%02d.%02d", h, m, s, mm );
254#endif
255        return 11;
256}
257
258string_ref nv::log_sink::level_name( log_level level ) const
259{
260        return NV_LOG_LEVEL_NAME( level );
261}
262
263string_ref nv::log_sink::padded_level_name( log_level level ) const
264{
265        return string_ref( NV_LOG_LEVEL_NAME_PAD( level ), 8 );
266}
267
Note: See TracBrowser for help on using the repository browser.