diff --git a/Daemon.cpp b/Daemon.cpp index bd89250e..8b8dfac1 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -159,7 +159,10 @@ namespace i2p if (isDaemon && (logs == "" || logs == "stdout")) logs = "file"; - if (logs == "file") { + if (logs == "syslog") { + // use syslog only no stdout + StartSyslog(); + } else if (logs == "file") { if (logfile == "") logfile = i2p::fs::DataDirPath("i2pd.log"); StartLog (logfile); diff --git a/Log.cpp b/Log.cpp index 6bba1b62..bb4f8231 100644 --- a/Log.cpp +++ b/Log.cpp @@ -10,9 +10,35 @@ static const char * g_LogLevelStr[eNumLogLevels] = "info", // eLogInfo "debug" // eLogDebug }; +#ifndef _WIN32 +/** convert LogLevel enum to syslog priority level */ +static int ToSyslogLevel(LogLevel lvl) +{ + switch (lvl) { + case eLogError: + return LOG_ERR; + case eLogWarning: + return LOG_WARNING; + case eLogInfo: + return LOG_INFO; + case eLogDebug: + return LOG_DEBUG; + default: + // WTF? invalid log level? + return LOG_CRIT; + } +} +#endif void LogMsg::Process() { +#ifndef _WIN32 + if (log && log->SyslogEnabled()) { + // only log to syslog + syslog(ToSyslogLevel(level), "%s", s.str().c_str()); + return; + } +#endif auto stream = log ? log->GetLogStream () : nullptr; auto& output = stream ? *stream : std::cout; if (log) @@ -84,3 +110,24 @@ void Log::SetLogStream (std::shared_ptr logStream) { m_LogStream = logStream; } + +void Log::StartSyslog(const std::string & ident, const int facility) +{ +#ifndef _WIN32 + m_Ident = ident; + openlog(m_Ident.c_str(), LOG_PID, facility); +#endif +} + +void Log::StopSyslog() +{ +#ifndef _WIN32 + closelog(); + m_Ident.clear(); +#endif +} + +bool Log::SyslogEnabled() +{ + return m_Ident.size() > 0; +} diff --git a/Log.h b/Log.h index 363a23b5..76866590 100644 --- a/Log.h +++ b/Log.h @@ -10,6 +10,10 @@ #include #include "Queue.h" +#ifndef _WIN32 +#include +#endif + enum LogLevel { eLogError = 0, @@ -45,14 +49,19 @@ class Log: public i2p::util::MsgQueue std::shared_ptr GetLogStream () const { return m_LogStream; }; const std::string& GetTimestamp (); LogLevel GetLogLevel () { return m_MinLevel; }; - const std::string& GetFullFilePath () const { return m_FullFilePath; }; - + const std::string& GetFullFilePath () const { return m_FullFilePath; }; + /** start logging to syslog */ + void StartSyslog(const std::string & ident, const int facility); + /** stop logging to syslog */ + void StopSyslog(); + /** are we logging to syslog right now? */ + bool SyslogEnabled(); private: void Flush (); private: - + std::string m_FullFilePath; // empty if stream std::shared_ptr m_LogStream; enum LogLevel m_MinLevel; @@ -61,7 +70,8 @@ class Log: public i2p::util::MsgQueue std::chrono::monotonic_clock::time_point m_LastTimestampUpdate; #else std::chrono::steady_clock::time_point m_LastTimestampUpdate; -#endif +#endif + std::string m_Ident; }; extern Log * g_Log; @@ -116,6 +126,20 @@ inline bool IsLogToFile () return g_Log ? !g_Log->GetFullFilePath ().empty () : false; } +inline void StartSyslog() +{ + StartLog(""); +#ifndef _WIN32 + g_Log->StartSyslog("i2pd", LOG_USER); +#endif +} + +inline void StopSyslog() +{ + if(g_Log) + g_Log->StopSyslog(); +} + template void LogPrint (std::stringstream& s, TValue arg) { diff --git a/docs/i2pd.conf b/docs/i2pd.conf index 32c524ca..92595311 100644 --- a/docs/i2pd.conf +++ b/docs/i2pd.conf @@ -16,7 +16,10 @@ ## Logging configuration section ## By default logs go to stdout with level info ## -## Logs destination (stdout, file) +## Logs destination (stdout, file, syslog) +## stdout - print log entries to stdout +## file - log entries to a file +## syslog - use syslog, see man 3 syslog #log = file ## Path to logfile (default - autodetect) #logfile = /var/log/i2pd.log @@ -40,7 +43,7 @@ ## don't just uncomment this #port = 4321 ##Enable communication through ipv6 -ipv6 +ipv6 = true ## Bandwidth configuration ## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited ## Default is P for floodfill, L for regular node