28#include <fmt/format.h>
52#define RESIP_LOG_MAX_LINE_COUNT_DEFAULT 0
53#define RESIP_LOG_MAX_BYTE_COUNT_DEFAULT 0
62#ifdef LOG_ENABLE_THREAD_SETTING
73Log::mDescriptions[][32] = {
"NONE",
"EMERG",
"ALERT",
"CRIT",
"ERR",
"WARNING",
"NOTICE",
"INFO",
"DEBUG",
"STACK",
"CERR",
""};
76Log::mCEEPri[][32] = {
"",
"CRIT",
"CRIT",
"CRIT",
"ERROR",
"WARN",
"DEBUG",
"DEBUG",
"DEBUG",
"DEBUG",
"ERROR",
""};
89Log::mSyslogPriority[] = { 0, LOG_CRIT, LOG_CRIT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_DEBUG, LOG_ERR, 0 };
116#ifdef LOG_ENABLE_THREAD_SETTING
129#ifdef LOG_ENABLE_THREAD_SETTING
140Log::initialize(
const char* typed,
const char* leveld,
const char* appName,
const char *logFileName,
ExternalLogger* externalLogger,
const char* syslogFacilityName,
const char* messageStructure,
const char* instanceName)
148 const Data& syslogFacilityName,
149 const Data& messageStructure,
150 const Data& instanceName)
169 Log::initialize(type,
level, appName, logFileName, externalLogger, syslogFacilityName, _messageStructure, instanceName);
182 if(facilityName ==
"LOG_AUTH")
186 else if(facilityName ==
"LOG_AUTHPRIV")
190 else if(facilityName ==
"LOG_CRON")
194 else if(facilityName ==
"LOG_DAEMON")
198 else if(facilityName ==
"LOG_FTP")
202 else if(facilityName ==
"LOG_KERN")
206 else if(facilityName ==
"LOG_LOCAL0")
210 else if(facilityName ==
"LOG_LOCAL1")
214 else if(facilityName ==
"LOG_LOCAL2")
218 else if(facilityName ==
"LOG_LOCAL3")
222 else if(facilityName ==
"LOG_LOCAL4")
226 else if(facilityName ==
"LOG_LOCAL5")
230 else if(facilityName ==
"LOG_LOCAL6")
234 else if(facilityName ==
"LOG_LOCAL7")
238 else if(facilityName ==
"LOG_LPR")
242 else if(facilityName ==
"LOG_MAIL")
246 else if(facilityName ==
"LOG_NEWS")
250 else if(facilityName ==
"LOG_SYSLOG")
254 else if(facilityName ==
"LOG_USER")
258 else if(facilityName ==
"LOG_UUCP")
269 const char * logFileName,
271 const Data& syslogFacilityName,
273 const Data& instanceName)
293 if (!syslogFacilityName.
empty())
301 syslog(LOG_DAEMON | LOG_ERR,
"invalid syslog facility name specified (%s), falling back to LOG_DAEMON", syslogFacilityName.
c_str());
308 std::cerr <<
"syslog not supported on windows, using cout!" << std::endl;
315 if(gethostname(buffer,
sizeof(buffer)) == -1)
324#ifdef USE_FQDN_FOR_JSON_CEE_HOSTNAME
328 struct addrinfo hints;
329 struct addrinfo* info =
nullptr;
331 memset (&hints, 0,
sizeof (hints));
332 hints.ai_family = AF_UNSPEC;
333 hints.ai_socktype = SOCK_STREAM;
334 hints.ai_flags = AI_CANONNAME;
336 if (getaddrinfo(buffer, 0, &hints, &info) == 0
339 mFqdn = info->ai_canonname;
354#ifdef RESIPROCATE_VERSION_STR
355#define STREAM_RESIPROCATE_VERSION_STR << RESIPROCATE_VERSION_STR
357#define STREAM_RESIPROCATE_VERSION_STR << "UNKNOWN"
359#ifdef ENABLE_LOG_REPOSITORY_DETAILS
360#define STREAM_ENABLE_LOG_REPOSITORY_DETAILS << " git-commit=" << RESIPROCATE_GIT_ID << " git-branch=" << RESIPROCATE_BRANCH_NAME
362#define STREAM_ENABLE_LOG_REPOSITORY_DETAILS << " git repository details unknown"
367 <<
"logger initialized app=" << appName
373#undef LOG_ENABLE_LOG_REPOSITORY_DETAILS
374#undef LOG_RESIPROCATE_VERSION_STR
382 const Data& syslogFacilityName,
384 const Data& instanceName)
386 initialize(type,
level, appName, 0, &logger, syslogFacilityName, messageStructure, instanceName);
397 Data syslogFacilityName = configParse.
getConfigData(
"SyslogFacility",
"LOG_DAEMON",
true);
401 configParse.
getConfigData(
"LoggingLevel",
"INFO",
true),
true);
405 Data loggingMessageStructure = configParse.
getConfigData(
"LogMessageStructure",
"Unstructured",
true);
406 Data loggingInstanceName = configParse.
getConfigData(
"LoggingInstanceName",
"",
true);
412 loggingFilename.
c_str(),
415 loggingMessageStructure,
416 loggingInstanceName);
594 cerr <<
"Choosing Debug level since string was not understood: " << l << endl;
601 if (arg ==
"cout" || arg ==
"COUT")
605 else if (arg ==
"cerr" || arg ==
"CERR")
609 else if (arg ==
"file" || arg ==
"FILE")
624 const char* methodName,
628 char buffer[256] =
"";
630#if defined( __APPLE__ )
632 pthread_threadid_np(
nullptr, &threadId);
633 const char* file = pfile;
634#elif defined( WIN32 )
635 int threadId = (int)GetCurrentThreadId();
636 const char* file = pfile + strlen(pfile);
637 while (file != pfile &&
647 std::make_unsigned<pthread_t>::type threadId = pthread_self();
648 const char* file = pfile;
651 switch(messageStructure)
655 auto now = std::chrono::high_resolution_clock::now();
656 std::time_t now_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
657 auto now_ns = now.time_since_epoch().count() % 1000000000;
662 gmtime_s(&now_tm, &now_t);
664 gmtime_r(&now_t, &now_tm);
671 strm <<
"\"hostname\":\"" <<
mFqdn <<
"\",";
673 strm <<
"\"syslog\":{";
676 strm <<
"\"time\":\"" << std::put_time(&now_tm,
"%FT%T.")
677 << std::setfill(
'0') << std::setw(9) << now_ns <<
"Z" <<
"\",";
678 strm <<
"\"pname\":\"" <<
mAppName <<
"\",";
683 strm <<
"\"subsys\":\"" << subsystem <<
"\",";
684 strm <<
"\"proc\":{";
686 strm <<
"\"id\":\"" << GetCurrentProcessId() <<
"\",";
688 strm <<
"\"id\":\"" << getpid() <<
"\",";
690 strm <<
"\"tid\":" << threadId;
692 strm <<
"\"file\":{";
693 strm <<
"\"name\":\"" << file <<
"\",";
694 strm <<
"\"line\":" << line;
696 strm <<
"\"native\":{";
697 strm <<
"\"function\":\"" << methodName <<
"\"";
699 strm <<
"\"msg\":\"";
711 <<
"0x" << std::hex << threadId << std::dec <<
Log::delim
712 << file <<
":" << line;
725 <<
"0x" << std::hex << threadId << std::dec <<
Log::delim
726 << file <<
":" << line;
735 char buffer[256] =
"";
743 char* datebuf =
const_cast<char*
>(res.
data());
744 const unsigned int datebufSize = 256;
749 SYSTEMTIME systemTime;
750 struct { time_t tv_sec;
int tv_usec; } tv = {0,0};
752 GetLocalTime(&systemTime);
753 tv.tv_usec = systemTime.wMilliseconds * 1000;
756 int result = gettimeofday (&tv, NULL);
771 struct tm localTimeResult = {};
772 const time_t timeInSeconds = (time_t) tv.tv_sec;
774 localtime_s(&localTimeResult, &timeInSeconds);
776 localtime_r(&timeInSeconds, &localTimeResult);
788 result = snprintf(msbuf, 5,
".%3.3ld",
long(tv.tv_usec / 1000));
793 memcpy(msbuf,
"0000", 5);
796 int datebufCharsRemaining = datebufSize - (int)strlen(datebuf);
797 snprintf(datebuf + strlen(datebuf), datebufCharsRemaining,
"%s", msbuf);
798 datebuf[datebufSize - 1] =
'\0';
825#ifndef LOG_ENABLE_THREAD_SETTING
837 HashMap<ThreadIf::Id, pair<ThreadSetting, bool> >::iterator res =
Log::mThreadToLevel.find(thread);
839 if (res->second.second)
841 setting->
mLevel = res->second.first.mLevel;
842 res->second.second =
false;
843 touchCount.fetch_sub(1, std::memory_order_relaxed);
868#ifndef LOG_ENABLE_THREAD_SETTING
880 touchCount.fetch_sub(1, std::memory_order_relaxed);
894#ifndef LOG_ENABLE_THREAD_SETTING
898 for (set<ThreadIf::Id>::iterator i = threads.begin(); i != threads.end(); i++)
903 Log::touchCount.fetch_add((
unsigned int)threads.size(), std::memory_order_relaxed);
910 const char * logFileName,
920 const char * logFileName,
947 return (loggerId == 0) || (pData != NULL)?0:1;
987 const char *text = result.
c_str();
989 LPWSTR lpwstrText = resip::ToWString(text);
990 OutputDebugStringW(lpwstrText);
991 FreeWString(lpwstrText);
993 OutputDebugStringA(text);
1000 const char * logFileName,
1007 externalLogger, messageStructure);
1016 const char * logFileName,
1020 Lock lock(mLoggerInstancesMapMutex);
1021 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1022 if (it == mLoggerInstancesMap.end())
1025 std::cerr <<
"Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl;
1028 it->second.first->reset();
1029 it->second.first->set(type,
level, logFileName, externalLogger, messageStructure);
1035 Lock lock(mLoggerInstancesMapMutex);
1036 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1037 if (it == mLoggerInstancesMap.end())
1040 std::cerr <<
"Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl;
1043 if (it->second.second > 0)
1046 std::cerr <<
"Log::LocalLoggerMap::remove(): Use count is non-zero (" << it->second.second <<
")!" << std::endl;
1049 delete it->second.first;
1050 mLoggerInstancesMap.erase(it);
1056 Lock lock(mLoggerInstancesMapMutex);
1057 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1058 if (it == mLoggerInstancesMap.end())
1063 it->second.second++;
1064 return it->second.first;
1069 Lock lock(mLoggerInstancesMapMutex);
1070 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1071 if (it != mLoggerInstancesMap.end())
1073 it->second.second--;
1083 const char* methodName) :
1085 mSubsystem(subsystem),
1088 mMethodName(methodName),
1089 mData(
Data::Borrow, mBuffer, sizeof(mBuffer)),
1090 mStream(mData.clear())
1098 Log::tags(mLevel, mSubsystem, mFile, mLine, mMethodName, mStream, messageStructure);
1103 mHeaderLength = mData.
size();
1120 Log::tags(mLevel, mSubsystem, mFile, mLine, mMethodName, o, messageStructure);
1125 static const char *json_special =
"\"\\/\b\f\n\r\t";
1126 static const char *json_special_replace =
"\"\\/bfnrt";
1127 const char* _data = mData.data();
1130 const char& c = _data[i];
1131 const char *special = strchr (json_special, c);
1132 if (special != NULL)
1134 const char *replace = json_special_replace + (special - json_special);
1135 o <<
'\\' << *replace;
1140 o <<
"\\u00" << std::setw(2) << std::setfill(
'0') << std::hex << std::uppercase << (int)c;
1159 mData.data() + mHeaderLength,
1160 (
int)mData.size() - mHeaderLength);
1222 (maxLineCount() && mLineCount >= maxLineCount()) ||
1223 (maxByteCount() && ((
unsigned int)mLogger->tellp() + bytesToWrite) >= maxByteCount()))
1225 Data logFileName(mLogFileName !=
"" ? mLogFileName :
"resiprocate.log");
1228 if (keepAllLogFiles())
1237 rename(logFileName.
c_str(), oldLogFileName.
c_str());
1241 Data oldLogFileName(logFileName +
".old");
1246 rename(logFileName.
c_str(), oldLogFileName.
c_str());
1249 mLogger =
new std::ofstream(logFileName.
c_str(), std::ios_base::out | std::ios_base::app);
1262 const char* logFileName,
1265 const Data& instanceName)
1273 fmt::memory_buffer _loggingFilename;
1274 fmt::format_to(std::back_inserter(_loggingFilename),
1277 fmt::arg(
"pid", (
int)GetCurrentProcess()),
1279 fmt::arg(
"pid", getpid()),
1281 fmt::arg(
"timestamp", time(0)));
1282 mLogFileName =
Data(_loggingFilename.data(), _loggingFilename.size());
1284 mLogFileName = logFileName;
1285 mLogFileName.replace(
"{timestamp}",
Data((
uint64_t)time(0)));
1287 mLogFileName.replace(
"{pid}",
Data((
uint64_t)GetCurrentProcess()));
1289 mLogFileName.replace(
"{pid}",
Data(getpid()));
1295 mLogFileName.clear();
1297 mExternalLogger = pExternalLogger;
1298 mMessageStructure = messageStructure;
1315 Data logFileName(mLogFileName !=
"" ? mLogFileName :
"resiprocate.log");
1316 if(chown(logFileName.
c_str(), uid, pid) < 0)
1319 std::cerr <<
"ERROR: chown failed on " << logFileName << std::endl;
#define STREAM_RESIPROCATE_VERSION_STR
void freeLocalLogger(void *pThreadData)
#define RESIP_LOG_MAX_BYTE_COUNT_DEFAULT
static const Data log_("LOG_")
#define STREAM_ENABLE_LOG_REPOSITORY_DETAILS
void freeThreadSetting(void *setting)
#define RESIP_LOG_MAX_LINE_COUNT_DEFAULT
#define GenericLog(system_, level_, args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
static ServerProcess * _instance
Handles cross-platform sockets compatibility.
bool AddBasePathIfRequired(Data &filename) const
resip::Data getConfigData(const resip::Data &name, const resip::Data &defaultValue, bool useDefaultIfEmpty=false) const
unsigned long getConfigUnsignedLong(const resip::Data &name, unsigned long defaultValue) const
bool getConfigBool(const resip::Data &name, bool defaultValue) const
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
const char * c_str() const
Returns a null-terminated string representing.
@ Share
The Data instance will use the buffer in a read-only mode.
@ Borrow
The Data instance is borrowing the memory from the passed in buffer.
char & at(size_type p)
Returns the character at the specified position.
bool prefix(const Data &pre) const noexcept
Returns true if this Data starts with the bytes indicated by the passed-in Data.
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
bool empty() const noexcept
Checks whether the Data is empty.
size_type size() const noexcept
Returns the number of bytes in this Data.
Data & clear()
Clears the contents of this Data.
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Interface functor for external logging.
static unsigned int mInstanceCounter
Guard(Level level, const Subsystem &system, const char *file, int line, const char *methodName)
Remember the logging values and be a a stream to receive the log contents.
Thread Local logger settings storage.
int reinitialize(LocalLoggerId loggerId, Type type, Level level, const char *logFileName=NULL, ExternalLogger *externalLogger=NULL, MessageStructure messageStructure=Unstructured)
Reinitialize all new setting for a local logger instance.
int remove(LocalLoggerId loggerId)
Remove existing logger instance from map and destroy.
Mutex mLoggerInstancesMapMutex
Mutex to synchronize access to Thread Local logger settings storage.
LocalLoggerId create(Type type, Level level, const char *logFileName=NULL, ExternalLogger *externalLogger=NULL, MessageStructure messageStructure=Unstructured)
Create new logger instance and return its ID (zero on error)
LocalLoggerId mLastLocalLoggerId
Last used LocalLoggerId.
void decreaseUseCount(LocalLoggerId loggerId)
Decrease use counter for given loggerId.
LoggerInstanceMap mLoggerInstancesMap
ThreadData * getData(LocalLoggerId loggerId)
Get pointer to ThreadData for given ID and increase use counter.
volatile MessageStructure mMessageStructure
std::ostream & Instance(unsigned int bytesToWrite)
Return logger stream instance, creating it if needed.
void droppingPrivileges(uid_t uid, pid_t pid)
void set(Type type=Cout, Level level=Info, const char *logFileName=NULL, ExternalLogger *pExternalLogger=NULL, MessageStructure messageStructure=Unstructured, const Data &instanceName="")
void setKeepAllLogFiles(bool keepAllLogFiles)
volatile unsigned int mMaxByteCount
void reset()
Frees logger stream.
volatile unsigned int mMaxLineCount
static bool isLogging(Log::Level level, const Subsystem &)
static const int mSyslogPriority[]
static HashMap< ThreadIf::Id, std::pair< ThreadSetting, bool > > mThreadToLevel
DEPRECATED! Left for backward compatibility - use localLoggers instead.
static ExternalLogger * getExternal()
static ThreadData & getLoggerData()
static void setMaxByteCount(unsigned int maxByteCount)
@ OnlyExternal
log messages are only written to external logger
@ VSDebugWindow
Use only for Visual Studio Debug Window logging - WIN32 must be defined.
@ OnlyExternalNoHeaders
same as OnlyExternal, only the messageWithHeaders param of the ExternalLogger will be empty.
static const char mCEEPri[][32]
static Data mInstanceName
static int mSyslogFacility
static const ThreadSetting * getThreadSetting()
DEPRECATED! Left for backward compatibility - use localLoggers instead.
static ThreadData mDefaultLoggerData
Default logger settings.
static int parseSyslogFacilityName(const Data &facilityName)
static void reset()
Frees logger stream.
static Data toString(Level l)
static Level getServiceLevel(int service)
static unsigned int MaxLineCount
static void setServiceLevel(int service, Level l)
DEPRECATED! Left for backward compatibility - use localLoggers instead.
static int setThreadLocalLogger(LocalLoggerId loggerId)
Set logger instance with given ID as a thread local logger.
static LocalLoggerMap mLocalLoggerMap
int LocalLoggerId
Thread Local logger ID type.
static std::atomic< unsigned int > touchCount
static Level toLevel(const Data &l)
static HashMap< int, Level > mServiceToLevel
DEPRECATED! Left for backward compatibility - use localLoggers instead.
static void setThreadSetting(ThreadSetting info)
static ThreadIf::TlsKey * mLocalLoggerKey
static void setLevel(Level level)
Set logging level for current thread.
static int localLoggerReinitialize(LocalLoggerId loggerId, Type type, Level level, const char *logFileName=NULL, ExternalLogger *externalLogger=NULL, MessageStructure messageStructure=Unstructured)
Reinitialize all new setting for a local logger instance.
static unsigned int MaxByteCount
static EncodeStream & tags(Log::Level level, const Subsystem &subsystem, const char *file, int line, const char *methodName, EncodeStream &strm, MessageStructure messageStructure)
output the loglevel, hostname, appname, pid, tid, subsystem
static HashMap< int, std::set< ThreadIf::Id > > mServiceToThreads
static int localLoggerRemove(LocalLoggerId loggerId)
Destroy existing logger instance.
static Level level()
Return logging level for current thread.
static void setKeepAllLogFiles(bool keepAllLogFiles)
static void setMaxLineCount(unsigned int maxLineCount)
static LocalLoggerId id()
static void droppingPrivileges(uid_t uid, pid_t pid)
static bool KeepAllLogFiles
static const char mDescriptions[][32]
static void initialize(Type type, Level level, const Data &appName, const char *logFileName=0, ExternalLogger *externalLogger=0, const Data &syslogFacility="LOG_DAEMON", MessageStructure messageStructure=Unstructured, const Data &instanceName="")
static void OutputToWin32DebugWindow(const Data &result)
static Type toType(const Data &t)
static ThreadIf::TlsKey * mLevelKey
static std::ostream & Instance(unsigned int bytesToWrite)
static LocalLoggerId localLoggerCreate(Type type, Level level, const char *logFileName=NULL, ExternalLogger *externalLogger=NULL, MessageStructure messageStructure=Unstructured)
Create new logger instance and return its ID (zero on error)
Provides string-parsing functionality with protection from buffer overflow.
const char * skipBackToChar(char c)
CurrentPosition skipToEnd()
CurrentPosition position() const
Class used to specify what sub-system given sections of code belong to, for use by the logging system...
void setLevel(Log::Level level)
Log::Level getLevel() const
static void * tlsGetValue(TlsKey key)
This function follows pthread_getspecific() signature.
static int tlsKeyCreate(TlsKey &key, TlsDestructor *destructor)
This function follows pthread_key_create() signature.
static int tlsKeyDelete(TlsKey key)
This function follows pthread_key_delete() signature.
static int tlsSetValue(TlsKey key, const void *val)
This function follows pthread_setspecific() signature.
An ostream that operates on an existing Data.
dcm! – add UnusedChecking(_enum) below;
std::mutex Mutex
A semaphore that can be locked by only one thread at a time.
bool isEqualNoCase(const Data &left, const Data &right)
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
unsigned long long uint64_t