Coverage Report

Created: 2026-06-07 06:35

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