Coverage Report

Created: 2024-07-23 06:39

/src/resiprocate/rutil/Log.cxx
Line
Count
Source (jump to first uncovered line)
1
#include "rutil/Socket.hxx"
2
3
#include "rutil/ResipAssert.h"
4
#include <chrono>
5
#include <iomanip>
6
#include <iostream>
7
#include <fstream>
8
#include <stdio.h>
9
#include "rutil/Data.hxx"
10
11
#ifndef WIN32
12
#include <sys/time.h>
13
#endif
14
15
#include <sys/types.h>
16
#include <time.h>
17
18
#include "rutil/Log.hxx"
19
#include "rutil/Logger.hxx"
20
#include "rutil/ParseBuffer.hxx"
21
#include "rutil/ThreadIf.hxx"
22
#include "rutil/Subsystem.hxx"
23
#include "rutil/SysLogStream.hxx"
24
#include "rutil/WinLeakCheck.hxx"
25
26
#ifdef USE_FMT
27
#include <fmt/format.h>
28
#endif
29
30
#ifdef HAVE_CONFIG_H
31
#include "config.h"
32
#endif
33
#ifdef HAVE_VERSION_H
34
#include "version.h"
35
#endif
36
37
using namespace resip;
38
using namespace std;
39
40
const Data Log::delim(" | ");
41
Log::ThreadData Log::mDefaultLoggerData(0, Log::Cout, Log::Info, NULL, NULL);
42
Data Log::mAppName;
43
Data Log::mInstanceName;
44
Data Log::mHostname;
45
Data Log::mFqdn;
46
#ifndef WIN32
47
int Log::mSyslogFacility = LOG_DAEMON;
48
#else
49
int Log::mSyslogFacility = -1;
50
#endif
51
0
#define RESIP_LOG_MAX_LINE_COUNT_DEFAULT 0
52
0
#define RESIP_LOG_MAX_BYTE_COUNT_DEFAULT 0
53
unsigned int Log::MaxLineCount = RESIP_LOG_MAX_LINE_COUNT_DEFAULT; // no limit by default
54
unsigned int Log::MaxByteCount = RESIP_LOG_MAX_BYTE_COUNT_DEFAULT; // no limit by default
55
bool Log::KeepAllLogFiles = false;  // do not keep all log files by default
56
57
volatile short Log::touchCount = 0;
58
59
60
/// DEPRECATED! Left for backward compatibility - use localLoggers instead
61
#ifdef LOG_ENABLE_THREAD_SETTING
62
HashMap<ThreadIf::Id, std::pair<Log::ThreadSetting, bool> > Log::mThreadToLevel;
63
HashMap<int, std::set<ThreadIf::Id> > Log::mServiceToThreads;
64
ThreadIf::TlsKey* Log::mLevelKey;
65
#endif
66
HashMap<int, Log::Level> Log::mServiceToLevel;
67
68
Log::LocalLoggerMap Log::mLocalLoggerMap;
69
ThreadIf::TlsKey* Log::mLocalLoggerKey;
70
71
const char
72
Log::mDescriptions[][32] = {"NONE", "EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG", "STACK", "CERR", ""}; 
73
74
const char
75
Log::mCEEPri[][32] = {      "",     "CRIT",  "CRIT",  "CRIT", "ERROR", "WARN",  "DEBUG", "DEBUG", "DEBUG", "DEBUG", "ERROR", ""};
76
77
#ifdef WIN32
78
#define LOG_EMERG   0 /* system is unusable */
79
#define LOG_ALERT   1 /* action must be taken immediately */
80
#define LOG_CRIT    2 /* critical conditions */
81
#define LOG_ERR     3 /* error conditions */
82
#define LOG_WARNING 4 /* warning conditions */
83
#define LOG_NOTICE  5 /* normal but significant condition */
84
#define LOG_INFO    6 /* informational */
85
#define LOG_DEBUG   7 /* debug-level messages */
86
#endif
87
const int
88
Log::mSyslogPriority[] = { 0, LOG_CRIT, LOG_CRIT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_DEBUG, LOG_ERR, 0 };
89
90
Mutex Log::_mutex;
91
92
extern "C"
93
{
94
   void freeThreadSetting(void* setting)
95
0
   {
96
0
      delete static_cast<Log::ThreadSetting*>(setting);
97
0
   }
98
99
   void freeLocalLogger(void* pThreadData)
100
0
   {
101
0
      if (pThreadData)
102
0
      {
103
         // There was some local logger installed. Decrease its use count before we
104
         // continue.
105
0
         Log::mLocalLoggerMap.decreaseUseCount((static_cast<Log::ThreadData*>(pThreadData))->id());
106
0
      }
107
0
   }
108
}
109
110
unsigned int LogStaticInitializer::mInstanceCounter=0;
111
LogStaticInitializer::LogStaticInitializer()
112
158
{
113
158
   if (mInstanceCounter++ == 0)
114
4
   {
115
4
#ifdef LOG_ENABLE_THREAD_SETTING
116
4
         Log::mLevelKey = new ThreadIf::TlsKey;
117
4
         ThreadIf::tlsKeyCreate(*Log::mLevelKey, freeThreadSetting);
118
4
#endif
119
120
4
         Log::mLocalLoggerKey = new ThreadIf::TlsKey;
121
4
         ThreadIf::tlsKeyCreate(*Log::mLocalLoggerKey, freeLocalLogger);
122
4
   }
123
158
}
124
LogStaticInitializer::~LogStaticInitializer()
125
0
{
126
0
   if (--mInstanceCounter == 0)
127
0
   {
128
0
#ifdef LOG_ENABLE_THREAD_SETTING
129
0
      ThreadIf::tlsKeyDelete(*Log::mLevelKey);
130
0
      delete Log::mLevelKey;
131
0
#endif
132
133
0
      ThreadIf::tlsKeyDelete(*Log::mLocalLoggerKey);
134
0
      delete Log::mLocalLoggerKey;
135
0
   }
136
0
}
137
138
void
139
Log::initialize(const char* typed, const char* leveld, const char* appName, const char *logFileName, ExternalLogger* externalLogger, const char* syslogFacilityName, const char* messageStructure, const char* instanceName)
140
0
{
141
0
   Log::initialize(Data(typed), Data(leveld), Data(appName), logFileName, externalLogger, syslogFacilityName, Data(messageStructure), Data(instanceName));
142
0
}
143
144
void
145
Log::initialize(const Data& typed, const Data& leveld, const Data& appName, 
146
                const char *logFileName, ExternalLogger* externalLogger,
147
                const Data& syslogFacilityName,
148
                const Data& messageStructure,
149
                const Data& instanceName)
150
0
{
151
0
   Type type = Log::Cout;
152
0
   if (isEqualNoCase(typed, "cout")) type = Log::Cout;
153
0
   else if (isEqualNoCase(typed, "cerr")) type = Log::Cerr;
154
0
   else if (isEqualNoCase(typed, "file")) type = Log::File;
155
0
#ifndef WIN32
156
0
   else type = Log::Syslog;
157
0
#endif
158
   
159
0
   Level level = Log::Info;
160
0
   level = toLevel(leveld);
161
162
0
   MessageStructure _messageStructure = Unstructured;
163
0
   if (isEqualNoCase(messageStructure, "JSON_CEE"))
164
0
   {
165
0
      _messageStructure = JSON_CEE;
166
0
   }
167
168
0
   Log::initialize(type, level, appName, logFileName, externalLogger, syslogFacilityName, _messageStructure, instanceName);
169
0
}
170
171
int
172
Log::parseSyslogFacilityName(const Data& facilityName)
173
4
{
174
4
#ifndef WIN32
175
   /* In theory, some platforms may not have all the log facilities
176
      defined in syslog.h.  Only LOG_USER and LOG_LOCAL[0-7] are considered
177
      mandatory.
178
      If the compile fails with errors in this method, then the unsupported
179
      facility names could be wrapped in conditional logic.
180
   */
181
4
   if(facilityName == "LOG_AUTH")
182
0
   {
183
0
      return LOG_AUTH;
184
0
   }
185
4
   else if(facilityName == "LOG_AUTHPRIV")
186
0
   {
187
0
      return LOG_AUTHPRIV;
188
0
   }
189
4
   else if(facilityName == "LOG_CRON")
190
0
   {
191
0
      return LOG_CRON;
192
0
   }
193
4
   else if(facilityName == "LOG_DAEMON")
194
4
   {
195
4
      return LOG_DAEMON;
196
4
   }
197
0
   else if(facilityName == "LOG_FTP")
198
0
   {
199
0
      return LOG_FTP;
200
0
   }
201
0
   else if(facilityName == "LOG_KERN")
202
0
   {
203
0
      return LOG_KERN;
204
0
   }
205
0
   else if(facilityName == "LOG_LOCAL0")
206
0
   {
207
0
      return LOG_LOCAL0;
208
0
   }
209
0
   else if(facilityName == "LOG_LOCAL1")
210
0
   {
211
0
      return LOG_LOCAL1;
212
0
   }
213
0
   else if(facilityName == "LOG_LOCAL2")
214
0
   {
215
0
      return LOG_LOCAL2;
216
0
   }
217
0
   else if(facilityName == "LOG_LOCAL3")
218
0
   {
219
0
      return LOG_LOCAL3;
220
0
   }
221
0
   else if(facilityName == "LOG_LOCAL4")
222
0
   {
223
0
      return LOG_LOCAL4;
224
0
   }
225
0
   else if(facilityName == "LOG_LOCAL5")
226
0
   {
227
0
      return LOG_LOCAL5;
228
0
   }
229
0
   else if(facilityName == "LOG_LOCAL6")
230
0
   {
231
0
      return LOG_LOCAL6;
232
0
   }
233
0
   else if(facilityName == "LOG_LOCAL7")
234
0
   {
235
0
      return LOG_LOCAL7;
236
0
   }
237
0
   else if(facilityName == "LOG_LPR")
238
0
   {
239
0
      return LOG_LPR;
240
0
   }
241
0
   else if(facilityName == "LOG_MAIL")
242
0
   {
243
0
      return LOG_MAIL;
244
0
   }
245
0
   else if(facilityName == "LOG_NEWS")
246
0
   {
247
0
      return LOG_NEWS;
248
0
   }
249
0
   else if(facilityName == "LOG_SYSLOG")
250
0
   {
251
0
      return LOG_SYSLOG;
252
0
   }
253
0
   else if(facilityName == "LOG_USER")
254
0
   {
255
0
      return LOG_USER;
256
0
   }
257
0
   else if(facilityName == "LOG_UUCP")
258
0
   {
259
0
      return LOG_UUCP;
260
0
   }
261
0
#endif
262
   // Nothing matched or syslog not supported on this platform
263
0
   return -1;
264
4
}
265
266
void 
267
Log::initialize(Type type, Level level, const Data& appName, 
268
                const char * logFileName,
269
                ExternalLogger* externalLogger,
270
                const Data& syslogFacilityName,
271
                MessageStructure messageStructure,
272
                const Data& instanceName)
273
4
{
274
4
   {
275
4
      Lock lock(_mutex);
276
4
      mDefaultLoggerData.reset();   
277
278
4
      mDefaultLoggerData.set(type, level, logFileName, externalLogger, messageStructure, instanceName);
279
280
4
      ParseBuffer pb(appName);
281
4
      pb.skipToEnd();
282
#ifdef _WIN32
283
      pb.skipBackToChar('\\');
284
#else
285
4
      pb.skipBackToChar('/');
286
4
#endif
287
4
      mAppName = pb.position();
288
289
4
      mInstanceName = instanceName;
290
291
4
#ifndef WIN32
292
4
      if (!syslogFacilityName.empty())
293
4
      {
294
4
         mSyslogFacility = parseSyslogFacilityName(syslogFacilityName);
295
4
         if(mSyslogFacility == -1)
296
0
         {
297
0
            mSyslogFacility = LOG_DAEMON;
298
0
            if(type == Log::Syslog)
299
0
            {
300
0
               syslog(LOG_DAEMON | LOG_ERR, "invalid syslog facility name specified (%s), falling back to LOG_DAEMON", syslogFacilityName.c_str());
301
0
            }
302
0
         }
303
4
      }
304
#else
305
      if (type == Syslog)
306
      {
307
         std::cerr << "syslog not supported on windows, using cout!" << std::endl;
308
         type = Cout;
309
      }
310
#endif
311
312
4
      char buffer[1024];  
313
4
      buffer[1023] = '\0';
314
4
      if(gethostname(buffer, sizeof(buffer)) == -1)
315
0
      {
316
0
         mHostname = "?";
317
0
      }
318
4
      else
319
4
      {
320
4
         mHostname = buffer;
321
4
      }
322
323
      // Note: for Windows users, you must call initNetwork to initialize WinSock before calling 
324
      //       Log::initialize in order for getaddrinfo to be successful
325
4
      {
326
4
         struct addrinfo hints;
327
4
         struct addrinfo* info = nullptr;
328
4
         int gai_result;
329
330
4
         memset (&hints, 0, sizeof (hints));
331
4
         hints.ai_family = AF_UNSPEC;    /*either IPV4 or IPV6 */
332
4
         hints.ai_socktype = SOCK_STREAM;
333
4
         hints.ai_flags = AI_CANONNAME;
334
335
4
         if ((gai_result = getaddrinfo (buffer, 0, &hints, &info)) != 0) {
336
0
            mFqdn = mHostname;
337
4
         } else if (info == NULL) {
338
0
            mFqdn = mHostname;
339
4
         } else {
340
4
            mFqdn = info->ai_canonname;
341
4
         }
342
343
4
         freeaddrinfo (info);
344
4
      }
345
346
4
   }
347
348
   // pre declare to prevent msvc build error C2121
349
4
#ifdef RESIPROCATE_VERSION_STR
350
4
#define STREAM_RESIPROCATE_VERSION_STR << RESIPROCATE_VERSION_STR
351
#else 
352
#define STREAM_RESIPROCATE_VERSION_STR << "UNKNOWN"
353
#endif  // RESIPROCATE_VERSION_STR
354
4
#ifdef ENABLE_LOG_REPOSITORY_DETAILS
355
4
#define STREAM_ENABLE_LOG_REPOSITORY_DETAILS << " git-commit=" << RESIPROCATE_GIT_ID << " git-branch=" << RESIPROCATE_BRANCH_NAME
356
#else
357
#define STREAM_ENABLE_LOG_REPOSITORY_DETAILS << " git repository details unknown"
358
#endif  // ENABLE_LOG_REPOSITORY_DETAILS
359
360
4
   GenericLog(resip::Subsystem::NONE,
361
4
              resip::Log::Info,
362
4
              << "logger initialized app=" << appName
363
4
              << " version="
364
4
              STREAM_RESIPROCATE_VERSION_STR
365
4
              STREAM_ENABLE_LOG_REPOSITORY_DETAILS
366
4
              );
367
368
4
#undef LOG_ENABLE_LOG_REPOSITORY_DETAILS
369
4
#undef LOG_RESIPROCATE_VERSION_STR
370
4
}
371
372
void
373
Log::initialize(Type type,
374
                Level level,
375
                const Data& appName,
376
                ExternalLogger& logger,
377
                const Data& syslogFacilityName,
378
                MessageStructure messageStructure,
379
                const Data& instanceName)
380
0
{
381
0
   initialize(type, level, appName, 0, &logger, syslogFacilityName, messageStructure, instanceName);
382
0
}
383
384
void
385
Log::initialize(const ConfigParse& configParse, const Data& appName, ExternalLogger* externalLogger)
386
0
{
387
0
   Log::setMaxByteCount(configParse.getConfigUnsignedLong("LogFileMaxBytes", RESIP_LOG_MAX_BYTE_COUNT_DEFAULT));
388
389
0
   Log::setKeepAllLogFiles(configParse.getConfigBool("KeepAllLogFiles", false));
390
391
0
   Data loggingType = configParse.getConfigData("LoggingType", "cout", true);
392
0
   Data syslogFacilityName = configParse.getConfigData("SyslogFacility", "LOG_DAEMON", true);
393
   // Most applications now use LogLevel
394
   // Some applications had been using LoggingLevel, that is not deprecated
395
0
   Data loggingLevel = configParse.getConfigData("LogLevel",
396
0
      configParse.getConfigData("LoggingLevel", "INFO", true), true);
397
0
   Data loggingFilename = configParse.getConfigData("LogFilename",
398
0
      configParse.getConfigData("LoggingFilename", appName + Data(".log")), true);
399
0
   configParse.AddBasePathIfRequired(loggingFilename);
400
0
   Data loggingMessageStructure = configParse.getConfigData("LogMessageStructure", "Unstructured", true);
401
0
   Data loggingInstanceName = configParse.getConfigData("LoggingInstanceName", "", true);
402
403
0
   Log::initialize(
404
0
      loggingType,
405
0
      loggingLevel,
406
0
      appName.c_str(),
407
0
      loggingFilename.c_str(),
408
0
      externalLogger,
409
0
      syslogFacilityName,
410
0
      loggingMessageStructure,
411
0
      loggingInstanceName);
412
413
0
   unsigned int loggingFileMaxLineCount = configParse.getConfigUnsignedLong("LogFileMaxLines", RESIP_LOG_MAX_LINE_COUNT_DEFAULT);
414
0
   Log::setMaxLineCount(loggingFileMaxLineCount);
415
0
}
416
417
void
418
Log::setLevel(Level level)
419
0
{
420
0
   Lock lock(_mutex);
421
0
   getLoggerData().mLevel = level; 
422
0
}
423
424
void
425
Log::setLevel(Level level, Subsystem& s)
426
0
{
427
0
   Lock lock(_mutex);
428
0
   s.setLevel(level); 
429
0
}
430
431
void
432
Log::setLevel(Level level, Log::LocalLoggerId loggerId)
433
0
{
434
0
   if (loggerId)
435
0
   {
436
0
      ThreadData *pData = mLocalLoggerMap.getData(loggerId);
437
0
      if (pData)
438
0
      {
439
         // Local logger found. Set logging level.
440
0
         pData->mLevel = level;
441
442
         // We don't need local logger instance anymore.
443
0
         mLocalLoggerMap.decreaseUseCount(loggerId);
444
0
         pData = NULL;
445
0
      }
446
0
   }
447
0
   else
448
0
   {
449
0
      Lock lock(_mutex);
450
0
      mDefaultLoggerData.mLevel = level;
451
0
   }
452
0
}
453
454
Log::Level 
455
Log::level(Log::LocalLoggerId loggerId)
456
0
{
457
0
   Level level;
458
0
   ThreadData *pData;
459
0
   if (loggerId && (pData = mLocalLoggerMap.getData(loggerId)))
460
0
   {
461
      // Local logger found. Set logging level.
462
0
      level = pData->mLevel;
463
464
      // We don't need local logger instance anymore.
465
0
      mLocalLoggerMap.decreaseUseCount(loggerId);
466
0
      pData = NULL;
467
0
   }
468
0
   else
469
0
   {
470
0
      Lock lock(_mutex);
471
0
      level = mDefaultLoggerData.mLevel;
472
0
   }
473
0
   return level;
474
0
}
475
476
void 
477
Log::setMaxLineCount(unsigned int maxLineCount)
478
0
{
479
0
   Lock lock(_mutex);
480
0
   getLoggerData().mMaxLineCount = maxLineCount; 
481
0
}
482
483
void 
484
Log::setMaxLineCount(unsigned int maxLineCount, Log::LocalLoggerId loggerId)
485
0
{
486
0
   if (loggerId)
487
0
   {
488
0
      ThreadData *pData = mLocalLoggerMap.getData(loggerId);
489
0
      if (pData)
490
0
      {
491
         // Local logger found. Set logging level.
492
0
         pData->mMaxLineCount = maxLineCount;
493
494
         // We don't need local logger instance anymore.
495
0
         mLocalLoggerMap.decreaseUseCount(loggerId);
496
0
         pData = NULL;
497
0
      }
498
0
   }
499
0
   else
500
0
   {
501
0
      Lock lock(_mutex);
502
0
      mDefaultLoggerData.mMaxLineCount = maxLineCount;
503
0
   }
504
0
}
505
506
void 
507
Log::setMaxByteCount(unsigned int maxByteCount)
508
0
{
509
0
   Lock lock(_mutex);
510
0
   getLoggerData().mMaxByteCount = maxByteCount; 
511
0
}
512
513
void 
514
Log::setMaxByteCount(unsigned int maxByteCount, Log::LocalLoggerId loggerId)
515
0
{
516
0
   if (loggerId)
517
0
   {
518
0
      ThreadData *pData = mLocalLoggerMap.getData(loggerId);
519
0
      if (pData)
520
0
      {
521
         // Local logger found. Set logging level.
522
0
         pData->mMaxByteCount = maxByteCount;
523
524
         // We don't need local logger instance anymore.
525
0
         mLocalLoggerMap.decreaseUseCount(loggerId);
526
0
         pData = NULL;
527
0
      }
528
0
   }
529
0
   else
530
0
   {
531
0
      Lock lock(_mutex);
532
0
      mDefaultLoggerData.mMaxByteCount = maxByteCount;
533
0
   }
534
0
}
535
536
void
537
Log::setKeepAllLogFiles(bool keepAllLogFiles)
538
0
{
539
0
    Lock lock(_mutex);
540
0
    getLoggerData().setKeepAllLogFiles(keepAllLogFiles);
541
0
}
542
543
void
544
Log::setKeepAllLogFiles(bool keepAllLogFiles, Log::LocalLoggerId loggerId)
545
0
{
546
0
    if (loggerId)
547
0
    {
548
0
        ThreadData *pData = mLocalLoggerMap.getData(loggerId);
549
0
        if (pData)
550
0
        {
551
            // Local logger found. Set logging level.
552
0
            pData->setKeepAllLogFiles(keepAllLogFiles);
553
554
            // We don't need local logger instance anymore.
555
0
            mLocalLoggerMap.decreaseUseCount(loggerId);
556
0
            pData = NULL;
557
0
        }
558
0
    }
559
0
    else
560
0
    {
561
0
        Lock lock(_mutex);
562
0
        mDefaultLoggerData.setKeepAllLogFiles(keepAllLogFiles);
563
0
    }
564
0
}
565
566
const static Data log_("LOG_");
567
568
Data
569
Log::toString(Level l)
570
0
{
571
0
   return log_ + mDescriptions[l+1];
572
0
}
573
574
Log::Level
575
Log::toLevel(const Data& l)
576
0
{
577
0
   Data pri( l.prefix("LOG_") ? l.substr(4) : l);
578
579
0
   int i=0;
580
0
   while (strlen(mDescriptions[i]))
581
0
   {
582
0
      if (isEqualNoCase(pri, Data(mDescriptions[i])))
583
0
      {
584
0
         return Level(i-1);
585
0
      }
586
0
      i++;
587
0
   }
588
589
0
   cerr << "Choosing Debug level since string was not understood: " << l << endl;
590
0
   return Log::Debug;
591
0
}
592
593
Log::Type
594
Log::toType(const Data& arg)
595
0
{
596
0
   if (arg == "cout" || arg == "COUT")
597
0
   {
598
0
      return Log::Cout;
599
0
   }
600
0
   else if (arg == "cerr" || arg == "CERR")
601
0
   {
602
0
      return Log::Cerr;
603
0
   }
604
0
   else if (arg == "file" || arg == "FILE")
605
0
   {
606
0
      return Log::File;
607
0
   }
608
0
   else
609
0
   {
610
0
      return Log::Syslog;
611
0
   }
612
0
}
613
614
EncodeStream &
615
Log::tags(Log::Level level,
616
          const Subsystem& subsystem,
617
          const char* pfile,
618
          int line,
619
          const char* methodName,
620
          EncodeStream& strm,
621
          MessageStructure messageStructure)
622
0
{
623
0
   char buffer[256] = "";
624
0
   Data ts(Data::Borrow, buffer, sizeof(buffer));
625
#if defined( __APPLE__ )
626
   uint64_t threadId;
627
   pthread_threadid_np(nullptr, &threadId);
628
   const char* file = pfile;
629
#elif defined( WIN32 )
630
   int threadId = (int)GetCurrentThreadId();
631
   const char* file = pfile + strlen(pfile);
632
   while (file != pfile &&
633
          *file != '\\')
634
   {
635
      --file;
636
   }
637
   if (file != pfile)
638
   {
639
      ++file;
640
   }
641
#else // #if defined( WIN32 ) || defined( __APPLE__ )
642
0
   std::make_unsigned<pthread_t>::type threadId = pthread_self();
643
0
   const char* file = pfile;
644
0
#endif
645
646
0
   switch(messageStructure)
647
0
   {
648
0
   case JSON_CEE:
649
0
      {
650
0
         auto now = std::chrono::high_resolution_clock::now();
651
0
         std::time_t now_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
652
0
         auto now_ns = now.time_since_epoch().count() % 1000000000;
653
654
0
         if(resip::Log::getLoggerData().type() == Syslog)
655
0
         {
656
0
            strm << "@cee: ";
657
0
         }
658
0
         strm << "{";
659
0
         strm << "\"hostname\":\"" << mFqdn << "\",";
660
0
         strm << "\"pri\":\"" << mCEEPri[level+1] << "\",";
661
0
         strm << "\"syslog\":{";
662
0
         strm << "\"level\":" << mSyslogPriority[level+1];
663
0
         strm << "},"; // "syslog"
664
0
         strm << "\"time\":\"" << std::put_time(gmtime(&now_t), "%FT%T.")
665
0
              << std::setfill('0') << std::setw(9) << now_ns << "Z" << "\",";
666
0
         strm << "\"pname\":\"" << mAppName << "\",";
667
0
         if(!mInstanceName.empty())
668
0
         {
669
0
            strm << "\"appname\":\"" << mInstanceName << "\",";
670
0
         }
671
0
         strm << "\"subsys\":\"" << subsystem << "\",";
672
0
         strm << "\"proc\":{";
673
#ifdef WIN32
674
         strm << "\"id\":\"" << GetCurrentProcessId() << "\",";
675
#else
676
0
         strm << "\"id\":\"" << getpid() << "\",";
677
0
#endif
678
0
         strm << "\"tid\":" << threadId;
679
0
         strm << "},"; // "proc"
680
0
         strm << "\"file\":{";
681
0
         strm << "\"name\":\"" << file << "\",";
682
0
         strm << "\"line\":" << line;
683
0
         strm << "},"; // "file"
684
0
         strm << "\"native\":{";
685
0
         strm << "\"function\":\"" << methodName << "\"";
686
0
         strm << "},"; // "native"
687
0
         strm << "\"msg\":\"";
688
0
      }
689
0
      break;
690
0
   case Unstructured:
691
0
   default:
692
0
      if(resip::Log::getLoggerData().type() == Syslog)
693
0
      {
694
0
         strm // << mDescriptions[level+1] << Log::delim
695
      //        << timestamp(ts) << Log::delim
696
      //        << mHostname << Log::delim
697
      //        << mAppName << Log::delim
698
0
              << subsystem << Log::delim
699
0
              << "0x" << std::hex << threadId << std::dec << Log::delim
700
0
              << file << ":" << line;
701
0
      }
702
0
      else
703
0
      {
704
0
         strm << mDescriptions[level+1] << Log::delim
705
0
              << timestamp(ts) << Log::delim
706
0
              << mAppName;
707
0
         if(!mInstanceName.empty())
708
0
         {
709
0
            strm << '[' << mInstanceName << ']';
710
0
         }
711
0
         strm << Log::delim
712
0
              << subsystem << Log::delim
713
0
              << "0x" << std::hex << threadId << std::dec << Log::delim
714
0
              << file << ":" << line;
715
0
      }
716
0
   }
717
0
   return strm;
718
0
}
719
720
Data
721
Log::timestamp()
722
0
{
723
0
   char buffer[256] = "";
724
0
   Data result(Data::Borrow, buffer, sizeof(buffer));
725
0
   return timestamp(result);
726
0
}
727
728
Data&
729
Log::timestamp(Data& res) 
730
0
{
731
0
   char* datebuf = const_cast<char*>(res.data());
732
0
   const unsigned int datebufSize = 256;
733
0
   res.clear();
734
   
735
#ifdef WIN32 
736
   int result = 1; 
737
   SYSTEMTIME systemTime;
738
   struct { time_t tv_sec; int tv_usec; } tv = {0,0};
739
   time(&tv.tv_sec);
740
   GetLocalTime(&systemTime);
741
   tv.tv_usec = systemTime.wMilliseconds * 1000; 
742
#else 
743
0
   struct tm localTimeResult;
744
0
   struct timeval tv; 
745
0
   int result = gettimeofday (&tv, NULL);
746
0
#endif   
747
748
0
   if (result == -1)
749
0
   {
750
      /* If we can't get the time of day, don't print a timestamp.
751
         Under Unix, this will never happen:  gettimeofday can fail only
752
         if the timezone is invalid which it can't be, since it is
753
         uninitialized]or if tv or tz are invalid pointers. */
754
0
      datebuf [0] = 0;
755
0
   }
756
0
   else
757
0
   {
758
      /* The tv_sec field represents the number of seconds passed since
759
         the Epoch, which is exactly the argument gettimeofday needs. */
760
0
      const time_t timeInSeconds = (time_t) tv.tv_sec;
761
0
      strftime (datebuf,
762
0
                datebufSize,
763
0
                "%Y%m%d-%H%M%S", /* guaranteed to fit in 256 chars,
764
                                    hence don't check return code */
765
#ifdef WIN32
766
                localtime (&timeInSeconds));  // Thread safe call on Windows
767
#else
768
0
                localtime_r (&timeInSeconds, &localTimeResult));  // Thread safe version of localtime on linux
769
0
#endif
770
0
   }
771
   
772
0
   char msbuf[5];
773
   /* Dividing (without remainder) by 1000 rounds the microseconds
774
      measure to the nearest millisecond. */
775
0
   result = snprintf(msbuf, 5, ".%3.3ld", long(tv.tv_usec / 1000));
776
0
   if(result < 0)
777
0
   {
778
      // snprint can error (negative return code) and the compiler now generates a warning
779
      // if we don't act on the return code
780
0
      memcpy(msbuf, "0000", 5);
781
0
   }
782
783
0
   int datebufCharsRemaining = datebufSize - (int)strlen(datebuf);
784
#if defined(WIN32) && defined(_M_ARM)
785
   // There is a bug under ARM with strncat - we use strcat instead - buffer is plenty large accomdate our timestamp, no
786
   // real need to be safe here anyway.
787
   strcat(datebuf, msbuf);
788
#else
789
0
   strncat (datebuf, msbuf, datebufCharsRemaining - 1);
790
0
#endif
791
0
   datebuf[datebufSize - 1] = '\0'; /* Just in case strncat truncated msbuf,
792
                                       thereby leaving its last character at
793
                                       the end, instead of a null terminator */
794
795
   // ugh, resize the Data
796
0
   res.at(strlen(datebuf)-1);
797
0
   return res;
798
0
}
799
800
Log::Level 
801
Log::getServiceLevel(int service)
802
0
{
803
0
   Lock lock(_mutex);
804
0
   HashMap<int, Level>::iterator res = Log::mServiceToLevel.find(service);
805
0
   if(res == Log::mServiceToLevel.end())
806
0
   {
807
      //!dcm! -- should perhaps throw an exception here, instead of setting a
808
      //default level of LOG_ERROR, but nobody uses this yet
809
0
      Log::mServiceToLevel[service] = Err;
810
0
      return Err;
811
0
   }
812
0
   return res->second;
813
0
}
814
   
815
const Log::ThreadSetting*
816
Log::getThreadSetting()
817
0
{
818
#ifndef LOG_ENABLE_THREAD_SETTING
819
   return 0;
820
#else
821
0
   ThreadSetting* setting = static_cast<ThreadSetting*>(ThreadIf::tlsGetValue(*Log::mLevelKey));
822
0
   if (setting == 0)
823
0
   {
824
0
      return 0;
825
0
   }
826
0
   if (Log::touchCount > 0)
827
0
   {
828
0
      Lock lock(_mutex);
829
0
      ThreadIf::Id thread = ThreadIf::selfId();
830
0
      HashMap<ThreadIf::Id, pair<ThreadSetting, bool> >::iterator res = Log::mThreadToLevel.find(thread);
831
0
      resip_assert(res != Log::mThreadToLevel.end());
832
0
      if (res->second.second)
833
0
      {
834
0
         setting->mLevel = res->second.first.mLevel;
835
0
         res->second.second = false;
836
0
         touchCount--;
837
//         cerr << "**Log::getThreadSetting:touchCount: " << Log::touchCount << "**" << endl;
838
839
         //cerr << "touchcount decremented" << endl;
840
0
      }
841
0
   }
842
0
   return setting;
843
0
#endif
844
0
}
845
846
void 
847
Log::setThreadSetting(int serv)
848
0
{
849
0
   Log::setThreadSetting(ThreadSetting(serv, getServiceLevel(serv)));
850
0
}
851
852
void 
853
Log::setThreadSetting(int serv, Log::Level l)
854
0
{
855
0
   Log::setThreadSetting(ThreadSetting(serv, l));
856
0
}
857
858
void 
859
Log::setThreadSetting(ThreadSetting info)
860
0
{
861
#ifndef LOG_ENABLE_THREAD_SETTING
862
   resip_assert(0);
863
#else
864
   //cerr << "Log::setThreadSetting: " << "service: " << info.service << " level " << toString(info.level) << " for " << pthread_self() << endl;
865
0
   ThreadIf::Id thread = ThreadIf::selfId();
866
0
   ThreadIf::tlsSetValue(*mLevelKey, (void *) new ThreadSetting(info));
867
0
   Lock lock(_mutex);
868
869
0
   if (Log::mThreadToLevel.find(thread) != Log::mThreadToLevel.end())
870
0
   {
871
0
      if (Log::mThreadToLevel[thread].second == true)
872
0
      {
873
0
         touchCount--;
874
0
      }
875
0
   }
876
0
   Log::mThreadToLevel[thread].first = info;
877
0
   Log::mThreadToLevel[thread].second = false;
878
0
   Log::mServiceToThreads[info.mService].insert(thread);
879
0
#endif
880
0
}
881
   
882
void 
883
Log::setServiceLevel(int service, Level l)
884
0
{
885
0
   Lock lock(_mutex);
886
0
   Log::mServiceToLevel[service] = l;
887
#ifndef LOG_ENABLE_THREAD_SETTING
888
   resip_assert(0);
889
#else
890
0
   set<ThreadIf::Id>& threads = Log::mServiceToThreads[service];
891
0
   for (set<ThreadIf::Id>::iterator i = threads.begin(); i != threads.end(); i++)
892
0
   {
893
0
      Log::mThreadToLevel[*i].first.mLevel = l;
894
0
      Log::mThreadToLevel[*i].second = true;
895
0
   }
896
0
   Log::touchCount += (short)threads.size();
897
0
#endif
898
//   cerr << "**Log::setServiceLevel:touchCount: " << Log::touchCount << "**" << endl;
899
0
}
900
901
Log::LocalLoggerId Log::localLoggerCreate(Log::Type type,
902
                                          Log::Level level,
903
                                          const char * logFileName,
904
                                          ExternalLogger* externalLogger,
905
                                          MessageStructure messageStructure)
906
0
{
907
0
   return mLocalLoggerMap.create(type, level, logFileName, externalLogger, messageStructure);
908
0
}
909
910
int Log::localLoggerReinitialize(Log::LocalLoggerId loggerId,
911
                                 Log::Type type,
912
                                 Log::Level level,
913
                                 const char * logFileName,
914
                                 ExternalLogger* externalLogger,
915
                                 MessageStructure messageStructure)
916
0
{
917
0
   return mLocalLoggerMap.reinitialize(loggerId, type, level, logFileName, externalLogger, messageStructure);
918
0
}
919
920
int Log::localLoggerRemove(Log::LocalLoggerId loggerId)
921
0
{
922
0
   return mLocalLoggerMap.remove(loggerId);
923
0
}
924
925
int Log::setThreadLocalLogger(Log::LocalLoggerId loggerId)
926
0
{
927
0
   ThreadData* pData = static_cast<ThreadData*>(ThreadIf::tlsGetValue(*Log::mLocalLoggerKey));
928
0
   if (pData)
929
0
   {
930
      // There was some local logger installed. Decrease its use count before we
931
      // continue.
932
0
      mLocalLoggerMap.decreaseUseCount(pData->id());
933
0
      pData = NULL;
934
0
   }
935
0
   if (loggerId)
936
0
   {
937
0
      pData = mLocalLoggerMap.getData(loggerId);
938
0
   }
939
0
   ThreadIf::tlsSetValue(*mLocalLoggerKey, (void *) pData);
940
0
   return (loggerId == 0) || (pData != NULL)?0:1;
941
0
}
942
943
std::ostream&
944
Log::Instance(unsigned int bytesToWrite)
945
0
{
946
0
   return getLoggerData().Instance(bytesToWrite);
947
0
}
948
949
void 
950
Log::reset()
951
0
{
952
0
   getLoggerData().reset();
953
0
}
954
955
#ifndef WIN32
956
void
957
Log::droppingPrivileges(uid_t uid, pid_t pid)
958
0
{
959
0
   getLoggerData().droppingPrivileges(uid, pid);
960
0
}
961
#endif
962
963
bool
964
Log::isLogging(Log::Level level, const resip::Subsystem& sub)
965
1.68M
{
966
1.68M
   if (sub.getLevel() != Log::None)
967
0
   {
968
0
      return level <= sub.getLevel();
969
0
   }
970
1.68M
   else
971
1.68M
   {
972
1.68M
      return (level <= Log::getLoggerData().mLevel);
973
1.68M
   }
974
1.68M
}
975
976
void
977
Log::OutputToWin32DebugWindow(const Data& result)
978
0
{
979
#ifdef WIN32
980
   const char *text = result.c_str();
981
#ifdef UNDER_CE
982
   LPWSTR lpwstrText = resip::ToWString(text);
983
   OutputDebugStringW(lpwstrText);
984
   FreeWString(lpwstrText);
985
#else
986
   OutputDebugStringA(text);
987
#endif
988
#endif
989
0
}
990
991
Log::LocalLoggerId Log::LocalLoggerMap::create(Log::Type type,
992
                                                    Log::Level level,
993
                                                    const char * logFileName,
994
                                                    ExternalLogger* externalLogger,
995
                                                    MessageStructure messageStructure)
996
0
{
997
0
   Lock lock(mLoggerInstancesMapMutex);
998
0
   Log::LocalLoggerId id = ++mLastLocalLoggerId;
999
0
   Log::ThreadData *pNewData = new Log::ThreadData(id, type, level, logFileName,
1000
0
                                                   externalLogger, messageStructure);
1001
0
   mLoggerInstancesMap[id].first = pNewData;
1002
0
   mLoggerInstancesMap[id].second = 0;
1003
0
   return id;
1004
0
}
1005
1006
int Log::LocalLoggerMap::reinitialize(Log::LocalLoggerId loggerId,
1007
                                      Log::Type type,
1008
                                      Log::Level level,
1009
                                      const char * logFileName,
1010
                                      ExternalLogger* externalLogger,
1011
                                      MessageStructure messageStructure)
1012
0
{
1013
0
   Lock lock(mLoggerInstancesMapMutex);
1014
0
   LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1015
0
   if (it == mLoggerInstancesMap.end())
1016
0
   {
1017
      // No such logger ID
1018
0
      std::cerr << "Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl;
1019
0
      return 1;
1020
0
   }
1021
0
   it->second.first->reset();
1022
0
   it->second.first->set(type, level, logFileName, externalLogger, messageStructure);
1023
0
   return 0;
1024
0
}
1025
1026
int Log::LocalLoggerMap::remove(Log::LocalLoggerId loggerId)
1027
0
{
1028
0
   Lock lock(mLoggerInstancesMapMutex);
1029
0
   LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1030
0
   if (it == mLoggerInstancesMap.end())
1031
0
   {
1032
      // No such logger ID
1033
0
      std::cerr << "Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl;
1034
0
      return 1;
1035
0
   }
1036
0
   if (it->second.second > 0)
1037
0
   {
1038
      // Non-zero use-count.
1039
0
      std::cerr << "Log::LocalLoggerMap::remove(): Use count is non-zero (" << it->second.second << ")!" << std::endl;
1040
0
      return 2;
1041
0
   }
1042
0
   delete it->second.first;  // delete ThreadData
1043
0
   mLoggerInstancesMap.erase(it);
1044
0
   return 0;
1045
0
}
1046
1047
Log::ThreadData *Log::LocalLoggerMap::getData(Log::LocalLoggerId loggerId)
1048
0
{
1049
0
   Lock lock(mLoggerInstancesMapMutex);
1050
0
   LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1051
0
   if (it == mLoggerInstancesMap.end())
1052
0
   {
1053
      // No such logger ID
1054
0
      return NULL;
1055
0
   }
1056
0
   it->second.second++;
1057
0
   return it->second.first;
1058
0
}
1059
1060
void Log::LocalLoggerMap::decreaseUseCount(Log::LocalLoggerId loggerId)
1061
0
{
1062
0
   Lock lock(mLoggerInstancesMapMutex);
1063
0
   LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
1064
0
   if (it != mLoggerInstancesMap.end())
1065
0
   {
1066
0
      it->second.second--;
1067
0
      resip_assert(it->second.second >= 0);
1068
0
   }
1069
0
}
1070
1071
1072
Log::Guard::Guard(resip::Log::Level level,
1073
                  const resip::Subsystem& subsystem,
1074
                  const char* file,
1075
                  int line,
1076
                  const char* methodName) :
1077
   mLevel(level),
1078
   mSubsystem(subsystem),
1079
   mFile(file),
1080
   mLine(line),
1081
   mMethodName(methodName),
1082
   mData(Data::Borrow, mBuffer, sizeof(mBuffer)),
1083
   mStream(mData.clear())
1084
0
{
1085
  
1086
0
   if (resip::Log::getLoggerData().mType != resip::Log::OnlyExternalNoHeaders)
1087
0
   {
1088
0
      MessageStructure messageStructure = resip::Log::getLoggerData().mMessageStructure;
1089
0
      if(messageStructure == Unstructured)
1090
0
      {
1091
0
         Log::tags(mLevel, mSubsystem, mFile, mLine, mMethodName, mStream, messageStructure);
1092
0
         mStream << resip::Log::delim;
1093
0
         mStream.flush();
1094
0
      }
1095
1096
0
      mHeaderLength = mData.size();
1097
0
   }
1098
0
   else
1099
0
   {
1100
0
      mHeaderLength = 0;
1101
0
   }
1102
0
}
1103
1104
Log::Guard::~Guard()
1105
0
{
1106
0
   MessageStructure messageStructure = resip::Log::getLoggerData().mMessageStructure;
1107
0
   if(messageStructure == JSON_CEE)
1108
0
   {
1109
0
      mStream.flush();
1110
0
      Data msg;
1111
0
      oDataStream o(msg);
1112
      // add the JSON message attributes
1113
0
      Log::tags(mLevel, mSubsystem, mFile, mLine, mMethodName, o, messageStructure);
1114
1115
      // JSON encode the message body
1116
      // FIXME - this could be done on the fly in DataStream
1117
1118
0
      static const char *json_special = "\"\\/\b\f\n\r\t";
1119
0
      static const char *json_special_replace = "\"\\/bfnrt";
1120
0
      const char* _data = mData.data();
1121
0
      for(Data::size_type i = 0; i < mData.size(); i++)
1122
0
      {
1123
0
         const char& c = _data[i];
1124
0
         const char *special = strchr (json_special, c);
1125
0
         if (special != NULL)
1126
0
         {
1127
0
            const char *replace = json_special_replace + (special - json_special);
1128
0
            o << '\\' << *replace;
1129
0
         }
1130
0
         else if (c < 0x20)
1131
0
         {
1132
            /* Everything below 0x20 must be escaped */
1133
0
            o << "\\u00" << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)c;
1134
0
         }
1135
0
         else
1136
0
         {
1137
0
            o << _data[i];
1138
0
         }
1139
0
      }
1140
      // add the trailing JSON
1141
0
      o << "\"}";
1142
0
      o.flush();
1143
1144
0
      mData.takeBuf(msg);
1145
0
   }
1146
1147
0
   mStream.flush();
1148
1149
0
   if (resip::Log::getExternal())
1150
0
   {
1151
0
      const resip::Data rest(resip::Data::Share,
1152
0
                             mData.data() + mHeaderLength,
1153
0
                             (int)mData.size() - mHeaderLength);
1154
0
      if (!(*resip::Log::getExternal())(mLevel, 
1155
0
                                        mSubsystem, 
1156
0
                                        resip::Log::getAppName(),
1157
0
                                        mFile,
1158
0
                                        mLine, 
1159
0
                                        rest, 
1160
0
                                        mData,
1161
0
                                        mInstanceName))
1162
0
      {
1163
0
         return;
1164
0
      }
1165
0
   }
1166
    
1167
0
   Type logType = resip::Log::getLoggerData().mType;
1168
1169
0
   if(logType == resip::Log::OnlyExternal ||
1170
0
      logType == resip::Log::OnlyExternalNoHeaders) 
1171
0
   {
1172
0
      return;
1173
0
   }
1174
1175
0
   resip::Lock lock(resip::Log::_mutex);
1176
   // !dlb! implement VSDebugWindow as an external logger
1177
0
   if (logType == resip::Log::VSDebugWindow)
1178
0
   {
1179
0
      mData += "\r\n";
1180
0
      OutputToWin32DebugWindow(mData);
1181
0
   }
1182
0
   else 
1183
0
   {
1184
      // endl is magic in syslog -- so put it here
1185
0
      std::ostream& _instance = Instance((int)mData.size()+2);
1186
0
      if (logType == resip::Log::Syslog)
1187
0
      {
1188
0
         _instance << mLevel;
1189
0
      }
1190
0
      _instance << mData << std::endl;  
1191
0
   }
1192
0
}
1193
1194
std::ostream&
1195
Log::ThreadData::Instance(unsigned int bytesToWrite)
1196
0
{
1197
//   std::cerr << "Log::ThreadData::Instance() id=" << mId << " type=" << mType <<  std::endl;
1198
0
   switch (mType)
1199
0
   {
1200
0
      case Log::Syslog:
1201
0
         if (mLogger == 0)
1202
0
         {
1203
0
            mLogger = new SysLogStream(mAppName, mSyslogFacility);
1204
0
         }
1205
0
         return *mLogger;
1206
1207
0
      case Log::Cerr:
1208
0
         return std::cerr;
1209
1210
0
      case Log::Cout:
1211
0
         return std::cout;
1212
1213
0
      case Log::File:
1214
0
         if (mLogger == 0 ||
1215
0
            (maxLineCount() && mLineCount >= maxLineCount()) ||
1216
0
            (maxByteCount() && ((unsigned int)mLogger->tellp() + bytesToWrite) >= maxByteCount()))
1217
0
         {
1218
0
            Data logFileName(mLogFileName != "" ? mLogFileName : "resiprocate.log");
1219
0
            if (mLogger)
1220
0
            {
1221
0
               if (keepAllLogFiles())
1222
0
               {
1223
0
                  char buffer[256];
1224
0
                  Data ts(Data::Borrow, buffer, sizeof(buffer));
1225
0
                  Data oldLogFileName(logFileName + "_" + timestamp(ts));
1226
1227
0
                  delete mLogger;
1228
1229
                  // Keep all log files, rename the log file with timestamp
1230
0
                  rename(logFileName.c_str(), oldLogFileName.c_str());
1231
0
               }
1232
0
               else
1233
0
               {
1234
0
                  Data oldLogFileName(logFileName + ".old");
1235
0
                  delete mLogger;
1236
                  // Keep one backup file: Delete .old file, Rename log file to .old
1237
                  // Could be expanded in the future to keep X backup log files
1238
0
                  remove(oldLogFileName.c_str());
1239
0
                  rename(logFileName.c_str(), oldLogFileName.c_str());
1240
0
               }
1241
0
            }
1242
0
            mLogger = new std::ofstream(logFileName.c_str(), std::ios_base::out | std::ios_base::app);
1243
0
            mLineCount = 0;
1244
0
         }
1245
0
         mLineCount++;
1246
0
         return *mLogger;
1247
0
      default:
1248
0
         resip_assert(0);
1249
0
         return std::cout;
1250
0
   }
1251
0
}
1252
1253
void 
1254
Log::ThreadData::set(Type type, Level level,
1255
                     const char* logFileName,
1256
                     ExternalLogger* pExternalLogger,
1257
                     MessageStructure messageStructure,
1258
                     const Data& instanceName)
1259
4
{
1260
4
   mType = type;
1261
4
   mLevel = level;
1262
1263
4
   if (logFileName)
1264
0
   {
1265
#ifdef USE_FMT
1266
      fmt::memory_buffer _loggingFilename;
1267
      fmt::format_to(std::back_inserter(_loggingFilename),
1268
                     logFileName,
1269
#ifdef WIN32
1270
                     fmt::arg("pid", (int)GetCurrentProcess()),
1271
#else
1272
                     fmt::arg("pid", getpid()),
1273
#endif
1274
                     fmt::arg("timestamp", time(0)));
1275
      mLogFileName = Data(_loggingFilename.data(), _loggingFilename.size());
1276
#else
1277
0
      mLogFileName = logFileName;
1278
0
      mLogFileName.replace("{timestamp}", Data((uint64_t)time(0)));
1279
#ifdef WIN32
1280
      mLogFileName.replace("{pid}", Data((int)GetCurrentProcess()));
1281
#else
1282
0
      mLogFileName.replace("{pid}", Data(getpid()));
1283
0
#endif
1284
0
#endif
1285
0
   }
1286
4
   else
1287
4
   {
1288
4
      mLogFileName.clear();
1289
4
   }
1290
4
   mExternalLogger = pExternalLogger;
1291
4
   mMessageStructure = messageStructure;
1292
4
   mInstanceName = instanceName;
1293
4
}
1294
1295
void 
1296
Log::ThreadData::reset()
1297
4
{
1298
4
   delete mLogger;
1299
4
   mLogger = NULL;
1300
4
}
1301
1302
#ifndef WIN32
1303
void
1304
Log::ThreadData::droppingPrivileges(uid_t uid, pid_t pid)
1305
0
{
1306
0
   if(mType == Log::File)
1307
0
   {
1308
0
      Data logFileName(mLogFileName != "" ? mLogFileName : "resiprocate.log");
1309
0
      if(chown(logFileName.c_str(), uid, pid) < 0)
1310
0
      {
1311
         // Some error occurred
1312
0
         std::cerr << "ERROR: chown failed on " << logFileName << std::endl;
1313
0
      }
1314
0
   }
1315
0
}
1316
#endif
1317
1318
/* ====================================================================
1319
 * The Vovida Software License, Version 1.0 
1320
 * 
1321
 * Copyright (c) 2000-2005
1322
 * 
1323
 * Redistribution and use in source and binary forms, with or without
1324
 * modification, are permitted provided that the following conditions
1325
 * are met:
1326
 * 
1327
 * 1. Redistributions of source code must retain the above copyright
1328
 *    notice, this list of conditions and the following disclaimer.
1329
 * 
1330
 * 2. Redistributions in binary form must reproduce the above copyright
1331
 *    notice, this list of conditions and the following disclaimer in
1332
 *    the documentation and/or other materials provided with the
1333
 *    distribution.
1334
 * 
1335
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1336
 *    and "Vovida Open Communication Application Library (VOCAL)" must
1337
 *    not be used to endorse or promote products derived from this
1338
 *    software without prior written permission. For written
1339
 *    permission, please contact vocal@vovida.org.
1340
 *
1341
 * 4. Products derived from this software may not be called "VOCAL", nor
1342
 *    may "VOCAL" appear in their name, without prior written
1343
 *    permission of Vovida Networks, Inc.
1344
 * 
1345
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1346
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1347
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1348
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
1349
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1350
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1351
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1352
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1353
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1354
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1355
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1356
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1357
 * DAMAGE.
1358
 * 
1359
 * ====================================================================
1360
 * 
1361
 * This software consists of voluntary contributions made by Vovida
1362
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1363
 * Inc.  For more information on Vovida Networks, Inc., please see
1364
 * <http://www.vovida.org/>.
1365
 *
1366
 */