Coverage Report

Created: 2023-06-07 06:03

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