36 #include <QStringConverter>
49const char*
Logger::__levels[] = {
"None",
"Error",
"Warning",
"Info",
"Debug",
"Constructors",
"Locks" };
55 if ( param ==
nullptr ) {
60# ifdef H2CORE_HAVE_DEBUG
63 SetConsoleOutputCP( CP_UTF8 );
64 freopen(
"CONOUT$",
"wt", stdout );
68 QTextStream stdoutStream( stdout );
69 QTextStream stderrStream( stderr );
71 stdoutStream.setEncoding( QStringConverter::Utf8 );
72 stderrStream.setEncoding( QStringConverter::Utf8 );
74 stdoutStream.setCodec( QTextCodec::codecForName(
"UTF-8" ) );
75 stderrStream.setCodec( QTextCodec::codecForName(
"UTF-8" ) );
78 bool bUseLogFile =
true;
80 QTextStream logFileStream = QTextStream();
81 if ( logFile.open( QIODevice::WriteOnly | QIODevice::Text ) ) {
82 logFileStream.setDevice( &logFile );
84 logFileStream.setEncoding( QStringConverter::Utf8 );
86 logFileStream.setCodec( QTextCodec::codecForName(
"UTF-8" ) );
91 QString(
"Error: can't open log file [%1] for writing...\n" )
97 Logger::queue_t::iterator it, last;
100 pthread_mutex_lock( &pLogger->
__mutex );
102 pthread_mutex_unlock( &pLogger->
__mutex );
103 if ( !queue->empty() ) {
104 for ( it = last = queue->begin() ; it != queue->end() ; ++it ) {
108 stdoutStream.flush();
111 logFileStream << *it;
112 logFileStream.flush();
116 pthread_mutex_lock( &pLogger->
__mutex );
117 queue->erase( queue->begin(), last );
119 pthread_mutex_unlock( &pLogger->
__mutex );
123 logFileStream <<
"Stop logger";
130 stderrStream.flush();
131 stdoutStream.flush();
132 pthread_exit(
nullptr );
137 bool bUseStdout,
bool bLogTimestamps,
145 QFileInfo logFileInfo;
146 if ( ! sLogFilePath.isEmpty() ) {
147 logFileInfo = QFileInfo( sLogFilePath );
152 const auto dir = logFileInfo.absoluteDir();
153 if ( ! dir.exists() ) {
162 bool bLogTimestamps,
bool bLogColors ) {
165 sLogFilePath, bUseStdout, bLogTimestamps, bLogColors );
171 bool bLogTimestamps,
bool bLogColors )
179 m_prefixList <<
"" <<
"(E) " <<
"(W) " <<
"(I) " <<
"(D) " <<
"(C)" <<
"(L) ";
182 m_colorList <<
"" <<
"" <<
"" <<
"" <<
"" <<
"" <<
"";
186 m_colorList <<
"" <<
"\033[31m" <<
"\033[36m" <<
"\033[32m" <<
"\033[35m"
187 <<
"\033[35;1m" <<
"\033[35;1m";
193 QFileInfo fiParentFolder( fiLogFile.absolutePath() );
194 if ( ( fiLogFile.exists() && ! fiLogFile.isWritable() ) ||
195 ( ! fiLogFile.exists() && ! fiParentFolder.isWritable() ) ) {
204 pthread_attr_init( &attr );
205 pthread_mutex_init( &
__mutex,
nullptr );
210 log(
Info,
"Logger",
"Logger", QString(
"Starting Hydrogen version [%1]" )
212 log(
Info,
"Logger",
"Logger", QString(
"Using log file [%1]" )
223void Logger::log(
unsigned level,
const QString& sClassName,
const char* func_name,
224 const QString& sMsg,
const QString& sColor ) {
255 QString sTimestampPrefix;
257 sTimestampPrefix = QString(
"[%1] " )
258 .arg( QDateTime::currentDateTime().toString(
"hh:mm:ss.zzz" ) );
263 sCol = sColor.isEmpty() ?
m_colorList[ i ] : sColor;
266 const QString tmp = QString(
"%1%2%3[%4::%5] %6%7\n" )
267 .arg( sCol ).arg( sTimestampPrefix ).arg(
m_prefixList[i] )
268 .arg( sClassName ).arg( func_name ).arg( sMsg ).arg(
m_sColorOff );
270 pthread_mutex_lock( &
__mutex );
272 pthread_mutex_unlock( &
__mutex );
279 for (
int ii = 0; ii < nTimeout; ++ii ) {
284 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
293 }
else if ( 0 == strncasecmp( level,
__levels[1], strlen(
__levels[1] ) ) ) {
295 }
else if ( 0 == strncasecmp( level,
__levels[2], strlen(
__levels[2] ) ) ) {
297 }
else if ( 0 == strncasecmp( level,
__levels[3], strlen(
__levels[3] ) ) ) {
299 }
else if ( 0 == strncasecmp( level,
__levels[4], strlen(
__levels[4] ) ) ) {
301 }
else if ( 0 == strncasecmp( level,
__levels[5], strlen(
__levels[5] ) ) ) {
303 }
else if ( 0 == strncasecmp( level,
__levels[6], strlen(
__levels[6] ) ) ) {
307 int val = sscanf( level,
"%x",&log_level );
312 log_level =
hextoi( level, -1 );
313 if( log_level==-1 ) {
327 bool leading_zero =
false;
330 if( ( len!=-1 ) && ( pos>=len ) ) {
336 }
else if( c==
'x' || c==
'X' ) {
337 if ( ( pos==1 ) && leading_zero ) {
344 }
else if( c>=
'a' ) {
346 }
else if( c>=
'A' ) {
348 }
else if( c>=
'0' ) {
349 if ( ( c==
'0' ) && ( pos==0 ) ) {
360 res = ( res << 4 ) | v;
361 assert( ( res & 0xF ) == ( v & 0xF ) );
static bool mkdir(const QString &path)
create a path
static QString log_file_path()
returns the full path (including filename) of the logfile
CrashContext(QString *pContext)
Class for writing logs to the console.
static Logger * create_instance(const QString &sLogFilePath=QString(), bool bUseStdout=true, bool bLogTimestamps=false, bool bLogColors=true)
If __instance equals 0, a new H2Core::Logger singleton will be created and stored in it.
pthread_cond_t __messages_available
std::list< QString > queue_t
message queue type
static Logger * bootstrap(unsigned msk, const QString &sLogFilePath=QString(), bool bUseStdout=true, bool bLogTimestamps=false, bool bLogColors=true)
create the logger instance if not exists, set the log level and return the instance
pthread_mutex_t __mutex
lock for adding or removing elements only
void flush() const
Waits till the logger thread poped all remaining messages from __msg_queue.
Logger(const QString &sLogFilePath=QString(), bool bUseStdout=true, bool bLogTimestamps=false, bool bLogColors=true)
constructor
bool __running
set to true when the logger thread is running
static Logger * __instance
Object holding the current H2Core::Logger singleton.
static int hextoi(const char *str, long len)
convert an hex string to an integer.
queue_t __msg_queue
the message queue
static thread_local QString * pCrashContext
static const char * __levels[]
levels strings
void log(unsigned level, const QString &sClassName, const char *func_name, const QString &sMsg, const QString &sColor="")
the log function
bool should_log(unsigned lvl) const
return true if the level is set in the bitmask
static void set_bit_mask(unsigned msk)
set the bitmask
static unsigned parse_log_level(const char *lvl)
parse a log level string and return the corresponding bit mask
static unsigned __bit_msk
the bitmask of log_level_t
friend void * loggerThread_func(void *param)
needed for being able to access logger internal
std::string get_version()
Returns the current Hydrogen version string.
void * loggerThread_func(void *param)