source: trunk/src/core/logger.cc

Last change on this file was 534, checked in by epyon, 8 years ago

CONTINUED:

  • getting rid of size_t
  • datatypes now restricted to uint32 size
  • 64-bit compatibility
  • copyright updates where modified
File size: 7.0 KB
RevLine 
[534]1// Copyright (C) 2011-2017 ChaosForge Ltd
[395]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.
[4]6
[319]7#include "nv/core/logger.hh"
[4]8
[365]9#include "nv/core/time.hh"
[48]10#include <cstdio>
[376]11#if NV_COMPILER == NV_MSVC
[48]12#define WIN32_LEAN_AND_MEAN
13#include <Windows.h>
14#endif
[4]15
16using namespace nv;
17
18// log level names
[121]19static const char *log_level_names[] =
[4]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
[48]34// log level names
[121]35static const char *log_level_names_pad[] =
[48]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
[4]50// helper macro to access log_level_names
51#define NV_LOG_LEVEL_NAME(level) (log_level_names[ (level) / 10 ])
[48]52#define NV_LOG_LEVEL_NAME_PAD(level) (log_level_names_pad[ (level) / 10 ])
[4]53
[376]54#if NV_COMPILER == NV_MSVC
[121]55static unsigned short log_color[] =
[48]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
[121]70static const char *log_color[] =
[48]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
[4]86// log function
[399]87void logger::log( log_level level, const string_view& message )
[4]88{
[365]89        for ( auto& sink_info : m_log_sinks )
[4]90        {
[402]91                if ( sink_info.sink && (sink_info.level >= static_cast<uint32>( level ) ) )
[4]92                {
93                        // log and iterate
[365]94                        sink_info.sink->log( level, message );
[4]95                }
96        }
97}
98
99// add a new sink
100void logger::add_sink( log_sink* sink, int level )
101{
102        // add a sink
[365]103        for ( auto& sink_info : m_log_sinks )
104        {
105                if ( sink_info.sink == nullptr )
106                {
107                        sink_info.sink  = sink;
[402]108                        sink_info.level = static_cast<uint32>( level );
[365]109                        return;
110                }
111        }
112        NV_ASSERT( false, "ran out of log sink space!" );
[4]113}
114
115// remove existing sink
116bool logger::remove_sink( log_sink* sink )
117{
[365]118        for ( auto& sink_info : m_log_sinks )
[4]119        {
[365]120                if ( sink_info.sink == sink )
[4]121                {
[365]122                        delete sink_info.sink;
123                        sink_info.sink = nullptr;
[4]124                        return true;
125                }
126        }
127        // not found, return false
128        return false;
129}
130
131// destructor
132logger::~logger()
133{
[365]134        // delete all sinks
135        for ( auto& sink_info : m_log_sinks )
[4]136        {
[365]137                delete sink_info.sink;
[4]138        }
139}
140
141
142// console logging
[399]143void log_console_sink::log( log_level level, const string_view& message )
[4]144{
[368]145        char stamp[16];
[533]146        uint32 ssize = timestamp( stamp );
[368]147
[376]148#if NV_COMPILER == NV_MSVC
[365]149        if ( m_color ) SetConsoleTextAttribute( m_handle, FOREGROUND_INTENSITY );
[368]150        WriteConsole( m_handle, stamp, ssize, nullptr, nullptr );
[365]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 );
[48]159#else
[365]160        if ( m_color ) fwrite( "\33[30;1m", 7, 1, stdout );
[368]161        fwrite( stamp, ssize, 1, stdout );
[365]162        fwrite( " [", 2, 1, stdout );
163        if ( m_color )
164        {
165                const char* lcolor = log_color[( level ) / 10];
[380]166                fwrite( lcolor, nvstrlen(lcolor), 1, stdout );
[48]167        }
[365]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 );
[48]171        else
[365]172                fwrite( "] ", 2, 1, stdout );
[376]173        fwrite( message.data(), message.size(), 1, stdout );
[365]174        fwrite( "\n", 1, 1, stdout );
175#endif
[4]176}
177
[365]178// handle logging
[399]179void log_handle_sink::log( log_level level, const string_view& message )
[4]180{
[368]181        char stamp[16];
[533]182        uint32 ssize = timestamp( stamp );
[365]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;
[368]188        WriteFile( m_handle, stamp, ssize, &unused, nullptr );
[365]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
[402]196        FILE* file = static_cast<FILE*>( m_handle );
197        fwrite( stamp, ssize, 1, file );
198        fwrite( " [", 2, 1, file );
199        fwrite( NV_LOG_LEVEL_NAME_PAD( level ), 8, 1, file );
200        fwrite( "] ", 2, 1, file );
201        fwrite( message.data(), message.size(), 1, file );
202        fwrite( "\n", 1, 1, file );
203        if ( m_flush ) fflush( file );
[365]204#endif
[4]205}
206
[399]207nv::log_file_sink::log_file_sink( const string_view& file_name, bool flush_always /*= true */ )
[365]208        : log_handle_sink( nullptr, flush_always )
[4]209{
[365]210#if 0 // NV_PLATFORM == NV_WINDOWS
211        // See comments in log_handle_sink
212        HANDLE handle = CreateFile( file_name.data(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr );
213        if ( INVALID_HANDLE_VALUE == handle )
[4]214        {
[365]215                NV_ASSERT( false, "invalid log handle" );
[4]216        }
[365]217        m_handle = handle;
218#else
219        m_handle = fopen( file_name.data(), "w" );
220#endif
[4]221}
222
[365]223nv::log_file_sink::~log_file_sink()
[4]224{
[365]225#if 0 // NV_PLATFORM == NV_WINDOWS
226        // See comments in log_handle_sink
227        CloseHandle( m_handle );
228#else
[402]229        fclose( static_cast<FILE*>( m_handle ) );
[365]230#endif
[4]231}
[48]232
[365]233
[48]234nv::log_console_sink::log_console_sink( bool coloring )
235        : m_color( coloring )
236{
[376]237#if NV_COMPILER == NV_MSVC
[48]238        m_handle = GetStdHandle( STD_OUTPUT_HANDLE );
[204]239#else
240  NV_UNUSED( m_handle );
[48]241#endif
242}
243
[533]244nv::uint32 nv::log_sink::timestamp( char* buffer ) const
[48]245{
[365]246        uint32 ms = get_system_ms();
[402]247        unsigned int secs = static_cast<unsigned int>( ms / 1000 );
248        unsigned int mm   = static_cast<unsigned int>( ms * 100 / 1000 ) % 100;
249        unsigned int h    = static_cast<unsigned int>( secs / (60*60) );
250        unsigned int m    = static_cast<unsigned int>( secs / 60 ) % 60;
[48]251        unsigned int s    = secs % 60;
[376]252#if NV_COMPILER == NV_MSVC
[365]253        sprintf_s( buffer, 16, "%02d:%02d:%02d.%02d", h, m, s, mm );
[48]254#else
[365]255        snprintf( buffer, 16, "%02d:%02d:%02d.%02d", h, m, s, mm );
[48]256#endif
[368]257        return 11;
[48]258}
[295]259
[399]260string_view nv::log_sink::level_name( log_level level ) const
[295]261{
262        return NV_LOG_LEVEL_NAME( level );
263}
264
[399]265string_view nv::log_sink::padded_level_name( log_level level ) const
[295]266{
[399]267        return string_view( NV_LOG_LEVEL_NAME_PAD( level ), 8 );
[295]268}
[365]269
Note: See TracBrowser for help on using the repository browser.