2020-07-29 02:43:59 +01:00
# include "Logger.h"
# include <cstdio>
# include <cstdarg>
2020-07-29 05:32:35 +01:00
// Platform-dependent console initialization
static void InitPlatformConsole ( ) ;
2020-07-29 02:43:59 +01:00
namespace Feather : : Logging
{
Logger GlobalLogger ;
2020-07-29 05:32:35 +01:00
ChannelID LOG_GENERAL = REGISTER_LOGGING_CHANNEL ( " General " ) ;
2020-07-31 00:33:34 +01:00
ChannelID LOG_LOGGING = REGISTER_LOGGING_CHANNEL ( " Logging " ) ;
2020-07-29 05:32:35 +01:00
// Since min and max are inclusive we have to add 1 here
// This assumes max > min (they better be)
2020-08-01 04:53:21 +01:00
static constexpr int NUM_LEVELS = ( ( int ) Level : : MaxLevel - ( int ) Level : : MinLevel ) + 1 ;
2020-07-29 05:32:35 +01:00
// Temporary solution while we don't have named enums
static const char * s_levelNames [ NUM_LEVELS ] = { " ERROR " , " WARNING " , " INFO " , " DEBUG " , " TRACE " } ;
// Shifts an enum value to be a positive index in s_levelNames
2020-08-01 04:53:21 +01:00
static constexpr int LEVEL_NAME_OFFSET = 0 - ( int ) Level : : MinLevel ;
2020-07-29 05:32:35 +01:00
Logger : : Logger ( )
{
InitPlatformConsole ( ) ;
}
void Logger : : LogDirect ( ChannelID channel , Level level , const char * message , . . . )
2020-07-29 02:43:59 +01:00
{
char buffer [ MAX_LOG_MESSAGE_LENGTH ] ;
2020-07-29 05:32:35 +01:00
int offset = 0 ;
// All color escape sequences follow the following ANSI format:
// ESC (\x1B) CSI ([) <COLOR CODES> SGR (m)
switch ( level )
{
2020-08-01 04:53:21 +01:00
case Level : : Warning :
2020-07-29 05:32:35 +01:00
// 1 BRIGHT, 33 YELLOW
offset + = snprintf ( buffer + offset , MAX_LOG_MESSAGE_LENGTH - offset , " \x1B [1;33m " ) ;
break ;
2020-08-01 04:53:21 +01:00
case Level : : Error :
2020-07-29 05:32:35 +01:00
// 1 BRIGHT, 31 RED
offset + = snprintf ( buffer + offset , MAX_LOG_MESSAGE_LENGTH - offset , " \x1B [1;31m " ) ;
break ;
default :
2020-08-01 04:53:21 +01:00
case Level : : Info :
2020-07-29 05:32:35 +01:00
break ;
}
const char * levelName = s_levelNames [ ( int ) level + LEVEL_NAME_OFFSET ] ;
if ( channel = = LOG_GENERAL ) {
// Print only severity level
offset + = snprintf ( buffer + offset , MAX_LOG_MESSAGE_LENGTH - offset , " [%s] " , levelName ) ;
} else {
// Print channel name and severity level
const char * channelName = m_channels [ channel ] - > GetName ( ) ;
offset + = snprintf ( buffer + offset , MAX_LOG_MESSAGE_LENGTH - offset , " [%s] [%s] " , channelName , levelName ) ;
}
2020-07-29 02:43:59 +01:00
2020-07-29 05:32:35 +01:00
// Write our message
2020-07-29 02:43:59 +01:00
va_list args ;
va_start ( args , message ) ;
2020-07-29 05:32:35 +01:00
offset + = vsnprintf ( buffer + offset , MAX_LOG_MESSAGE_LENGTH - offset , message , args ) ;
2020-07-29 02:43:59 +01:00
va_end ( args ) ;
2020-07-29 05:32:35 +01:00
// Ignore any terminal newline
if ( buffer [ offset - 1 ] = = ' \n ' ) offset - - ;
// Append ANSI style reset code 0 and newline
offset + = snprintf ( buffer + offset , MAX_LOG_MESSAGE_LENGTH - offset , " \x1b [0m \n " ) ;
2020-08-01 04:53:21 +01:00
if ( level > = Level : : Info ) {
2020-07-29 05:32:35 +01:00
// Info and above go to stdout
printf ( buffer ) ;
} else {
// Error and warn go to stderr
fprintf ( stderr , buffer ) ;
}
2020-07-29 02:43:59 +01:00
}
2020-07-29 05:32:35 +01:00
ChannelID Logger : : RegisterChannel ( const char * name )
{
if ( m_channelCount > = MAX_LOGGING_CHANNEL_COUNT ) {
2020-08-01 04:53:21 +01:00
Log_Msg ( LOG_LOGGING , Error , " Cannot register new logging channel '%s' because the maximum of %d channels has been exceeded. " , name , MAX_LOGGING_CHANNEL_COUNT ) ;
2020-07-31 00:33:34 +01:00
return LOG_GENERAL ;
2020-07-29 05:32:35 +01:00
}
2020-07-31 00:33:34 +01:00
Channel * channel = new Channel ( name ) ;
2020-07-29 05:32:35 +01:00
m_channels [ m_channelCount ] = channel ;
int id = m_channelCount + + ;
return id ;
}
}
# ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
# endif
static void InitPlatformConsole ( )
{
static bool s_initialized = false ;
if ( s_initialized )
return ;
# ifdef _WIN32
HANDLE handle = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
if ( handle ! = INVALID_HANDLE_VALUE )
{
DWORD mode = 0 ;
if ( GetConsoleMode ( handle , & mode ) )
{
2020-07-31 00:33:34 +01:00
// To enable ANSI escape sequences on Windows 10 we need to set this flag
2020-07-29 05:32:35 +01:00
mode | = ENABLE_VIRTUAL_TERMINAL_PROCESSING ;
SetConsoleMode ( handle , mode ) ;
}
}
# endif
s_initialized = true ;
}