Radium Engine  1.5.20
Loading...
Searching...
No Matches
Log.hpp
1#pragma once
2
3#include <Core/RaCore.hpp>
4#include <ctime>
5#include <sstream>
6#include <stdio.h>
7#include <string>
8
9namespace Ra {
10namespace Core {
11namespace Utils {
12
13inline std::string NowTime();
14
15enum TLogLevel {
16 logERROR,
17 logWARNING,
18 logINFO,
19 logDEBUG,
20 logDEBUG1,
21 logDEBUG2,
22 logDEBUG3,
23 logDEBUG4
24};
25
26template <typename T>
27class Log
28{
29 public:
30 Log();
31 virtual ~Log();
32 std::ostringstream& Get( TLogLevel level = logINFO );
33
34 public:
35 static TLogLevel& ReportingLevel();
36 static std::string ToString( TLogLevel level );
37 static TLogLevel FromString( const std::string& level );
38
39 protected:
41
42 private:
43 Log( const Log& );
44 Log& operator=( const Log& );
45};
46
47template <typename T>
48Log<T>::Log() {}
49
50template <typename T>
51std::ostringstream& Log<T>::Get( TLogLevel level ) {
52 os << "- " << NowTime();
53 os << " " << ToString( level ) << ": ";
54 os << std::string( level > logDEBUG ? level - logDEBUG : 0, '\t' );
55 return os;
56}
57
58template <typename T>
59Log<T>::~Log() {
60 os << std::endl;
61 T::Output( os.str() );
62}
63
64template <typename T>
65TLogLevel& Log<T>::ReportingLevel() {
66 static TLogLevel reportingLevel = logDEBUG4;
67 return reportingLevel;
68}
69
70template <typename T>
71std::string Log<T>::ToString( TLogLevel level ) {
72 static const char* const buffer[] = {
73 "ERROR", "WARNING", "INFO", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4" };
74 return buffer[level];
75}
76
77template <typename T>
78TLogLevel Log<T>::FromString( const std::string& level ) {
79 if ( level == "DEBUG4" ) { return logDEBUG4; }
80 if ( level == "DEBUG3" ) { return logDEBUG3; }
81 if ( level == "DEBUG2" ) { return logDEBUG2; }
82 if ( level == "DEBUG1" ) { return logDEBUG1; }
83 if ( level == "DEBUG" ) { return logDEBUG; }
84 if ( level == "INFO" ) { return logINFO; }
85 if ( level == "WARNING" ) { return logWARNING; }
86 if ( level == "ERROR" ) { return logERROR; }
87 Log<T>().Get( logWARNING ) << "Unknown logging level '" << level
88 << "'. Using INFO level as default.";
89 return logINFO;
90}
91
92class Output2FILE
93{
94 public:
95 static FILE*& Stream();
96 static void Output( const std::string& msg );
97};
98
99inline FILE*& Output2FILE::Stream() {
100 static FILE* pStream = stderr;
101 return pStream;
102}
103
104inline void Output2FILE::Output( const std::string& msg ) {
105 FILE* pStream = Stream();
106 if ( !pStream ) { return; }
107 fprintf( pStream, "%s", msg.c_str() );
108 fflush( pStream );
109}
110
111class FILELog : public Log<Output2FILE>
112{};
113// using FILELog = Log<Output2FILE>;
114
115inline std::string NowTime() {
116 char buffer[100];
117 std::time_t t = std::time( nullptr );
118 ON_ASSERT( int ok = ) std::strftime( buffer, 100, "%X", std::localtime( &t ) );
119 CORE_ASSERT( ok, "Increase buffer size." );
120 std::string result( buffer );
121 // This doesn't work with minGW. Maybe indicates a serious issue ?
122 // Ra::Core::Utils::stringPrintf( result, "%s", buffer );
123 return result;
124}
125
126} // namespace Utils
127} // namespace Core
128} // namespace Ra
129
130#ifndef FILELOG_MAX_LEVEL
131# ifdef CORE_DEBUG
132# define FILELOG_MAX_LEVEL Ra::Core::Utils::logDEBUG4
133# else
134# define FILELOG_MAX_LEVEL Ra::Core::Utils::logINFO
135# endif
136#endif
137
138#define FILE_LOG( level ) \
139 if ( level > FILELOG_MAX_LEVEL ) \
140 ; \
141 else if ( level > Ra::Core::Utils::FILELog::ReportingLevel() || \
142 !Ra::Core::Utils::Output2FILE::Stream() ) \
143 ; \
144 else \
145 Ra::Core::Utils::FILELog().Get( level )
146
147#ifdef RA_NO_LOG
148# define LOG( level ) FILE_LOG( Ra::Core::Utils::TLogLevel( FILELOG_MAX_LEVEL + 1 ) )
149#else
150# define LOG( level ) FILE_LOG( level )
151#endif
T c_str(T... args)
T endl(T... args)
T fflush(T... args)
T fprintf(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
STL namespace.
T time(T... args)