Commit b0521e81 authored by Vadim Troshchinskiy's avatar Vadim Troshchinskiy Committed by Mihai Moldovan

New logging implementation

Features: * Works without ifdefs * Configurable with commandline arguments * Log level configurable per file * Thread safe
parent 381c39b8
/**************************************************************************/
/* */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */
/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */
/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
/* */
/* NXCOMP, NX protocol compression and NX extensions to this software */
/* are copyright of the aforementioned persons and companies. */
/* */
/* Redistribution and use of the present software is allowed according */
/* to terms specified in the file LICENSE.nxcomp which comes in the */
/* source distribution. */
/* */
/* All rights reserved. */
/* */
/* NOTE: This software has received contributions from various other */
/* contributors, only the core maintainers and supporters are listed as */
/* copyright holders. Please contact us, if you feel you should be listed */
/* as copyright holder, as well. */
/* */
/**************************************************************************/
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include "Log.h"
NXLog nx_log;
bool NXLog::will_log() const
{
std::map<std::string, NXLogLevel>::const_iterator item = per_file_levels_.find(current_file());
if ( item != per_file_levels_.end() )
{
return current_level() <= item->second;
}
else
{
return current_level() <= level();
}
}
std::string NXLog::stamp_to_string(const NXLogStamp& stamp) const
{
std::ostringstream oss;
static const char* level_names[] = {
"FATAL",
"ERROR",
"WARN ",
"INFO ",
"DEBUG"
};
if ( log_level() )
oss << ((stamp.level() >=0 && stamp.level() < NXLOG_LEVEL_COUNT ) ? level_names[stamp.level()] : "???") << " ";
if ( log_time() )
{
struct timeval timestamp = stamp.timestamp();
struct tm timeinfo;
localtime_r(&timestamp.tv_sec, &timeinfo);
if ( log_unix_time() )
{
oss << timestamp.tv_sec;
}
else
{
#if __cplusplus >= 201103L && (!defined(__GNUC__) || __GNUC__ >= 5)
oss << " " << std::put_time(&timeinfo, "%Y/%m/%d %H:%M:%S");
#else
oss << timestamp.tv_sec;
#endif
}
oss << "." << std::setw(3) << std::setfill('0') << (int)(timestamp.tv_usec / 1000) << " ";
}
if ( log_location() )
oss << stamp.file() << "/" << stamp.function() << ":" << stamp.line() << " ";
if ( log_thread_id() )
{
if ( thread_name().empty() )
oss << pthread_self() << " ";
else
oss << "[" << thread_name() << "] ";
}
return oss.str();
}
NXLog& operator<< (NXLog& out, const NXLogStamp& value)
{
out.current_level( value.level() );
out.current_file( value.file() );
// Writing an NXLogStamp to the stream indicates the start of a new entry.
// If there's any content in the buffer, we flush it to finalize the previous
// log entry.
if ( out.synchronized() )
out.flush();
out << out.stamp_to_string(value);
return out;
}
......@@ -101,6 +101,7 @@ typedef int socklen_t;
#include "Message.h"
#include "ChannelEndPoint.h"
#include "Log.h"
//
// System specific defines.
......@@ -9339,6 +9340,102 @@ int ParseCommandLineOptions(int argc, const char **argv)
return -1;
}
case 'd':
{
if ( argi+1 >= argc )
{
PrintUsageInfo(nextArg, 0);
return -1;
}
int level = 0;
errno = 0;
level = strtol(argv[argi+1], NULL, 10);
if ( errno && (level == 0) )
{
cerr << "Warning: Failed to parse log level. Ignoring option." << std::endl;
}
if ( level < 0 )
{
cerr << "Warning: Log level must be a positive integer. Ignoring option." << std::endl;
level = nx_log.level();
}
else if ( level >= NXLOG_LEVEL_COUNT )
{
cerr << "Warning: Log level is greater than the maximum " << NXLOG_LEVEL_COUNT-1 << ". Setting to the maximum." << std::endl;
level = NXLOG_LEVEL_COUNT-1;
}
nx_log.level( (NXLogLevel)level );
argi++;
break;
}
case 'o':
{
if ( argi + 1 >= argc )
{
PrintUsageInfo(nextArg, 0);
return -1;
}
std::ofstream *logfile = new std::ofstream();
// Unbuffered output
logfile->rdbuf()->pubsetbuf(0, 0);
logfile->open(argv[argi+1], std::ofstream::app);
if ( logfile->is_open() )
{
nx_log.stream(logfile);
}
else
{
cerr << "Failed to open log file " << argv[argi+1] << endl;
return -1;
}
argi++;
break;
}
case 'f':
{
if ( argi + 1 >= argc )
{
PrintUsageInfo(nextArg, 0);
return -1;
}
const char *format = argv[argi+1];
size_t pos = 0;
nx_log.log_level(false);
nx_log.log_time(false);
nx_log.log_unix_time(false);
nx_log.log_location(false);
nx_log.log_thread_id(false);
for(pos =0;pos<strlen(format);pos++)
{
switch(format[pos])
{
case '0': break;
case 't': nx_log.log_time(true); break;
case 'u': nx_log.log_time(true); nx_log.log_unix_time(true); break;
case 'l': nx_log.log_level(true); break;
case 'T': nx_log.log_thread_id(true); break;
case 'L': nx_log.log_location(true); break;
default : cerr << "Unrecognized format specifier: " << format[pos] << endl; break;
}
}
argi++;
break;
}
default:
{
PrintUsageInfo(nextArg, 1);
......
......@@ -114,6 +114,7 @@ libXcomp_la_SOURCES = \
WriteBuffer.cpp \
XidCache.cpp \
Z.cpp \
Log.cpp \
$(NULL)
libXcomp_la_LIBADD = \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment