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

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