/[resiprocate]/main/rutil/Log.cxx
ViewVC logotype

Contents of /main/rutil/Log.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11224 - (show annotations) (download)
Mon Sep 1 14:28:01 2014 UTC (5 years, 3 months ago) by sgodin
File MIME type: text/plain
File size: 27852 byte(s)
-fix for broken build in Windows - thanks to Dario Bozzali
 -set mSyslogFacility to LOG_DAEMON (default value) instead of LOG_DEBUG (undefined under WIN32)
1 #include "rutil/Socket.hxx"
2
3 #include <cassert>
4 #include <iostream>
5 #include <fstream>
6 #include <stdio.h>
7 #include "rutil/Data.hxx"
8
9 #ifndef WIN32
10 #include <sys/time.h>
11 #endif
12
13 #include <sys/types.h>
14 #include <time.h>
15
16 #include "rutil/Log.hxx"
17 #include "rutil/Logger.hxx"
18 #include "rutil/ParseBuffer.hxx"
19 #include "rutil/ThreadIf.hxx"
20 #include "rutil/Subsystem.hxx"
21 #include "rutil/SysLogStream.hxx"
22 #include "rutil/WinLeakCheck.hxx"
23
24 using namespace resip;
25 using namespace std;
26
27 const Data Log::delim(" | ");
28 Log::ThreadData Log::mDefaultLoggerData(0, Log::Cout, Log::Info, NULL, NULL);
29 Data Log::mAppName;
30 Data Log::mHostname;
31 int Log::mSyslogFacility = LOG_DAEMON;
32 unsigned int Log::MaxLineCount = 0; // no limit by default
33 unsigned int Log::MaxByteCount = 0; // no limit by default
34
35 #ifdef WIN32
36 int Log::mPid=0;
37 #else
38 pid_t Log::mPid=0;
39 #endif
40
41 volatile short Log::touchCount = 0;
42
43
44 /// DEPRECATED! Left for backward compatibility - use localLoggers instead
45 #ifdef LOG_ENABLE_THREAD_SETTING
46 #if defined(__APPLE__) || defined(__CYGWIN__)
47 HashValueImp(ThreadIf::Id, (size_t)data);
48 #endif
49 HashMap<ThreadIf::Id, std::pair<Log::ThreadSetting, bool> > Log::mThreadToLevel;
50 HashMap<int, std::set<ThreadIf::Id> > Log::mServiceToThreads;
51 ThreadIf::TlsKey* Log::mLevelKey;
52 #endif
53 HashMap<int, Log::Level> Log::mServiceToLevel;
54
55 Log::LocalLoggerMap Log::mLocalLoggerMap;
56 ThreadIf::TlsKey* Log::mLocalLoggerKey;
57
58 const char
59 Log::mDescriptions[][32] = {"NONE", "EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG", "STACK", "CERR", ""};
60
61 Mutex Log::_mutex;
62
63 extern "C"
64 {
65 void freeThreadSetting(void* setting)
66 {
67 delete static_cast<Log::ThreadSetting*>(setting);
68 }
69
70 void freeLocalLogger(void* pThreadData)
71 {
72 if (pThreadData)
73 {
74 // There was some local logger installed. Decrease its use count before we
75 // continue.
76 Log::mLocalLoggerMap.decreaseUseCount((static_cast<Log::ThreadData*>(pThreadData))->id());
77 }
78 }
79 }
80
81 unsigned int LogStaticInitializer::mInstanceCounter=0;
82 LogStaticInitializer::LogStaticInitializer()
83 {
84 if (mInstanceCounter++ == 0)
85 {
86 #ifdef LOG_ENABLE_THREAD_SETTING
87 Log::mLevelKey = new ThreadIf::TlsKey;
88 ThreadIf::tlsKeyCreate(*Log::mLevelKey, freeThreadSetting);
89 #endif
90
91 Log::mLocalLoggerKey = new ThreadIf::TlsKey;
92 ThreadIf::tlsKeyCreate(*Log::mLocalLoggerKey, freeLocalLogger);
93 }
94 }
95 LogStaticInitializer::~LogStaticInitializer()
96 {
97 if (--mInstanceCounter == 0)
98 {
99 #ifdef LOG_ENABLE_THREAD_SETTING
100 ThreadIf::tlsKeyDelete(*Log::mLevelKey);
101 delete Log::mLevelKey;
102 #endif
103
104 ThreadIf::tlsKeyDelete(*Log::mLocalLoggerKey);
105 delete Log::mLocalLoggerKey;
106 }
107 }
108
109 void
110 Log::initialize(const char* typed, const char* leveld, const char* appName, const char *logFileName, ExternalLogger* externalLogger, const char* syslogFacilityName)
111 {
112 Log::initialize(Data(typed), Data(leveld), Data(appName), logFileName, externalLogger, syslogFacilityName);
113 }
114
115 void
116 Log::initialize(const Data& typed, const Data& leveld, const Data& appName,
117 const char *logFileName, ExternalLogger* externalLogger,
118 const Data& syslogFacilityName)
119 {
120 Type type = Log::Cout;
121 if (isEqualNoCase(typed, "cout")) type = Log::Cout;
122 else if (isEqualNoCase(typed, "cerr")) type = Log::Cerr;
123 else if (isEqualNoCase(typed, "file")) type = Log::File;
124 else type = Log::Syslog;
125
126 Level level = Log::Info;
127 level = toLevel(leveld);
128
129 Log::initialize(type, level, appName, logFileName, externalLogger, syslogFacilityName);
130 }
131
132 int
133 Log::parseSyslogFacilityName(const Data& facilityName)
134 {
135 #ifndef WIN32
136 /* In theory, some platforms may not have all the log facilities
137 defined in syslog.h. Only LOG_USER and LOG_LOCAL[0-7] are considered
138 mandatory.
139 If the compile fails with errors in this method, then the unsupported
140 facility names could be wrapped in conditional logic.
141 */
142 if(facilityName == "LOG_AUTH")
143 {
144 return LOG_AUTH;
145 }
146 else if(facilityName == "LOG_AUTHPRIV")
147 {
148 return LOG_AUTHPRIV;
149 }
150 else if(facilityName == "LOG_CRON")
151 {
152 return LOG_CRON;
153 }
154 else if(facilityName == "LOG_DAEMON")
155 {
156 return LOG_DAEMON;
157 }
158 else if(facilityName == "LOG_FTP")
159 {
160 return LOG_FTP;
161 }
162 else if(facilityName == "LOG_KERN")
163 {
164 return LOG_KERN;
165 }
166 else if(facilityName == "LOG_LOCAL0")
167 {
168 return LOG_LOCAL0;
169 }
170 else if(facilityName == "LOG_LOCAL1")
171 {
172 return LOG_LOCAL1;
173 }
174 else if(facilityName == "LOG_LOCAL2")
175 {
176 return LOG_LOCAL2;
177 }
178 else if(facilityName == "LOG_LOCAL3")
179 {
180 return LOG_LOCAL3;
181 }
182 else if(facilityName == "LOG_LOCAL4")
183 {
184 return LOG_LOCAL4;
185 }
186 else if(facilityName == "LOG_LOCAL5")
187 {
188 return LOG_LOCAL5;
189 }
190 else if(facilityName == "LOG_LOCAL6")
191 {
192 return LOG_LOCAL6;
193 }
194 else if(facilityName == "LOG_LOCAL7")
195 {
196 return LOG_LOCAL7;
197 }
198 else if(facilityName == "LOG_LPR")
199 {
200 return LOG_LPR;
201 }
202 else if(facilityName == "LOG_MAIL")
203 {
204 return LOG_MAIL;
205 }
206 else if(facilityName == "LOG_NEWS")
207 {
208 return LOG_NEWS;
209 }
210 else if(facilityName == "LOG_SYSLOG")
211 {
212 return LOG_SYSLOG;
213 }
214 else if(facilityName == "LOG_USER")
215 {
216 return LOG_USER;
217 }
218 else if(facilityName == "LOG_UUCP")
219 {
220 return LOG_UUCP;
221 }
222 #endif
223 // FIXME - maybe we should throw an exception or log
224 // an error about use of a bad facility name?
225 return -1;
226 }
227
228 void
229 Log::initialize(Type type, Level level, const Data& appName,
230 const char * logFileName,
231 ExternalLogger* externalLogger,
232 const Data& syslogFacilityName)
233 {
234 Lock lock(_mutex);
235 mDefaultLoggerData.reset();
236
237 mDefaultLoggerData.set(type, level, logFileName, externalLogger);
238
239 ParseBuffer pb(appName);
240 pb.skipToEnd();
241 #ifdef _WIN32
242 pb.skipBackToChar('\\');
243 #else
244 pb.skipBackToChar('/');
245 #endif
246 mAppName = pb.position();
247
248 if(!syslogFacilityName.empty())
249 {
250 mSyslogFacility = parseSyslogFacilityName(syslogFacilityName);
251 if(mSyslogFacility == -1)
252 {
253 mSyslogFacility = LOG_DAEMON;
254 }
255 }
256
257 char buffer[1024];
258 gethostname(buffer, sizeof(buffer));
259 mHostname = buffer;
260 #ifdef WIN32
261 mPid = (int)GetCurrentProcess();
262 #else
263 mPid = getpid();
264 #endif
265 }
266
267 void
268 Log::initialize(Type type,
269 Level level,
270 const Data& appName,
271 ExternalLogger& logger,
272 const Data& syslogFacilityName)
273 {
274 initialize(type, level, appName, 0, &logger, syslogFacilityName);
275 }
276
277 void
278 Log::setLevel(Level level)
279 {
280 Lock lock(_mutex);
281 getLoggerData().mLevel = level;
282 }
283
284 void
285 Log::setLevel(Level level, Subsystem& s)
286 {
287 Lock lock(_mutex);
288 s.setLevel(level);
289 }
290
291 void
292 Log::setLevel(Level level, Log::LocalLoggerId loggerId)
293 {
294 if (loggerId)
295 {
296 ThreadData *pData = mLocalLoggerMap.getData(loggerId);
297 if (pData)
298 {
299 // Local logger found. Set logging level.
300 pData->mLevel = level;
301
302 // We don't need local logger instance anymore.
303 mLocalLoggerMap.decreaseUseCount(loggerId);
304 pData = NULL;
305 }
306 }
307 else
308 {
309 Lock lock(_mutex);
310 mDefaultLoggerData.mLevel = level;
311 }
312 }
313
314 Log::Level
315 Log::level(Log::LocalLoggerId loggerId)
316 {
317 Level level;
318 ThreadData *pData;
319 if (loggerId && (pData = mLocalLoggerMap.getData(loggerId)))
320 {
321 // Local logger found. Set logging level.
322 level = pData->mLevel;
323
324 // We don't need local logger instance anymore.
325 mLocalLoggerMap.decreaseUseCount(loggerId);
326 pData = NULL;
327 }
328 else
329 {
330 Lock lock(_mutex);
331 level = mDefaultLoggerData.mLevel;
332 }
333 return level;
334 }
335
336 void
337 Log::setMaxLineCount(unsigned int maxLineCount)
338 {
339 Lock lock(_mutex);
340 getLoggerData().mMaxLineCount = maxLineCount;
341 }
342
343 void
344 Log::setMaxLineCount(unsigned int maxLineCount, Log::LocalLoggerId loggerId)
345 {
346 if (loggerId)
347 {
348 ThreadData *pData = mLocalLoggerMap.getData(loggerId);
349 if (pData)
350 {
351 // Local logger found. Set logging level.
352 pData->mMaxLineCount = maxLineCount;
353
354 // We don't need local logger instance anymore.
355 mLocalLoggerMap.decreaseUseCount(loggerId);
356 pData = NULL;
357 }
358 }
359 else
360 {
361 Lock lock(_mutex);
362 mDefaultLoggerData.mMaxLineCount = maxLineCount;
363 }
364 }
365
366 void
367 Log::setMaxByteCount(unsigned int maxByteCount)
368 {
369 Lock lock(_mutex);
370 getLoggerData().mMaxByteCount = maxByteCount;
371 }
372
373 void
374 Log::setMaxByteCount(unsigned int maxByteCount, Log::LocalLoggerId loggerId)
375 {
376 if (loggerId)
377 {
378 ThreadData *pData = mLocalLoggerMap.getData(loggerId);
379 if (pData)
380 {
381 // Local logger found. Set logging level.
382 pData->mMaxByteCount = maxByteCount;
383
384 // We don't need local logger instance anymore.
385 mLocalLoggerMap.decreaseUseCount(loggerId);
386 pData = NULL;
387 }
388 }
389 else
390 {
391 Lock lock(_mutex);
392 mDefaultLoggerData.mMaxByteCount = maxByteCount;
393 }
394 }
395
396 const static Data log_("LOG_");
397
398 Data
399 Log::toString(Level l)
400 {
401 return log_ + mDescriptions[l+1];
402 }
403
404 Log::Level
405 Log::toLevel(const Data& l)
406 {
407 Data pri( l.prefix("LOG_") ? l.substr(4) : l);
408
409 int i=0;
410 while (strlen(mDescriptions[i]))
411 {
412 if (isEqualNoCase(pri, Data(mDescriptions[i])))
413 {
414 return Level(i-1);
415 }
416 i++;
417 }
418
419 cerr << "Choosing Debug level since string was not understood: " << l << endl;
420 return Log::Debug;
421 }
422
423 Log::Type
424 Log::toType(const Data& arg)
425 {
426 if (arg == "cout" || arg == "COUT")
427 {
428 return Log::Cout;
429 }
430 else if (arg == "cerr" || arg == "CERR")
431 {
432 return Log::Cerr;
433 }
434 else if (arg == "file" || arg == "FILE")
435 {
436 return Log::File;
437 }
438 else
439 {
440 return Log::Syslog;
441 }
442 }
443
444 EncodeStream &
445 Log::tags(Log::Level level,
446 const Subsystem& subsystem,
447 const char* pfile,
448 int line,
449 EncodeStream& strm)
450 {
451 char buffer[256];
452 Data ts(Data::Borrow, buffer, sizeof(buffer));
453 #if defined( __APPLE__ )
454 strm << mDescriptions[level+1] << Log::delim
455 << timestamp(ts) << Log::delim
456 << mAppName << Log::delim
457 << subsystem << Log::delim
458 << pthread_self() << Log::delim
459 << pfile << ":" << line;
460 #elif defined( WIN32 )
461 const char* file = pfile + strlen(pfile);
462 while (file != pfile &&
463 *file != '\\')
464 {
465 --file;
466 }
467 if (file != pfile)
468 {
469 ++file;
470 }
471 strm << mDescriptions[level+1] << Log::delim
472 << timestamp(ts) << Log::delim
473 << mAppName << Log::delim
474 << subsystem << Log::delim
475 << GetCurrentThreadId() << Log::delim
476 << file << ":" << line;
477 #else // #if defined( WIN32 ) || defined( __APPLE__ )
478 if(resip::Log::getLoggerData().type() == Syslog)
479 {
480 strm // << mDescriptions[level+1] << Log::delim
481 // << timestamp(ts) << Log::delim
482 // << mHostname << Log::delim
483 // << mAppName << Log::delim
484 << subsystem << Log::delim
485 // << mPid << Log::delim
486 << pthread_self() << Log::delim
487 << pfile << ":" << line;
488 }
489 else
490 strm << mDescriptions[level+1] << Log::delim
491 << timestamp(ts) << Log::delim
492 // << mHostname << Log::delim
493 << mAppName << Log::delim
494 << subsystem << Log::delim
495 // << mPid << Log::delim
496 << pthread_self() << Log::delim
497 << pfile << ":" << line;
498 #endif
499 return strm;
500 }
501
502 Data
503 Log::timestamp()
504 {
505 char buffer[256];
506 Data result(Data::Borrow, buffer, sizeof(buffer));
507 return timestamp(result);
508 }
509
510 Data&
511 Log::timestamp(Data& res)
512 {
513 char* datebuf = const_cast<char*>(res.data());
514 const unsigned int datebufSize = 256;
515 res.clear();
516
517 #ifdef WIN32
518 int result = 1;
519 SYSTEMTIME systemTime;
520 struct { time_t tv_sec; int tv_usec; } tv = {0,0};
521 time(&tv.tv_sec);
522 GetLocalTime(&systemTime);
523 tv.tv_usec = systemTime.wMilliseconds * 1000;
524 #else
525 struct tm localTimeResult;
526 struct timeval tv;
527 int result = gettimeofday (&tv, NULL);
528 #endif
529
530 if (result == -1)
531 {
532 /* If we can't get the time of day, don't print a timestamp.
533 Under Unix, this will never happen: gettimeofday can fail only
534 if the timezone is invalid which it can't be, since it is
535 uninitialized]or if tv or tz are invalid pointers. */
536 datebuf [0] = 0;
537 }
538 else
539 {
540 /* The tv_sec field represents the number of seconds passed since
541 the Epoch, which is exactly the argument gettimeofday needs. */
542 const time_t timeInSeconds = (time_t) tv.tv_sec;
543 strftime (datebuf,
544 datebufSize,
545 "%Y%m%d-%H%M%S", /* guaranteed to fit in 256 chars,
546 hence don't check return code */
547 #ifdef WIN32
548 localtime (&timeInSeconds)); // Thread safe call on Windows
549 #else
550 localtime_r (&timeInSeconds, &localTimeResult)); // Thread safe version of localtime on linux
551 #endif
552 }
553
554 char msbuf[5];
555 /* Dividing (without remainder) by 1000 rounds the microseconds
556 measure to the nearest millisecond. */
557 snprintf(msbuf, 5, ".%3.3ld", long(tv.tv_usec / 1000));
558
559 int datebufCharsRemaining = datebufSize - (int)strlen(datebuf);
560 strncat (datebuf, msbuf, datebufCharsRemaining - 1);
561
562 datebuf[datebufSize - 1] = '\0'; /* Just in case strncat truncated msbuf,
563 thereby leaving its last character at
564 the end, instead of a null terminator */
565
566 // ugh, resize the Data
567 res.at(strlen(datebuf)-1);
568 return res;
569 }
570
571 Log::Level
572 Log::getServiceLevel(int service)
573 {
574 Lock lock(_mutex);
575 HashMap<int, Level>::iterator res = Log::mServiceToLevel.find(service);
576 if(res == Log::mServiceToLevel.end())
577 {
578 //!dcm! -- should perhaps throw an exception here, instead of setting a
579 //default level of LOG_ERROR, but nobody uses this yet
580 Log::mServiceToLevel[service] = Err;
581 return Err;
582 }
583 return res->second;
584 }
585
586 const Log::ThreadSetting*
587 Log::getThreadSetting()
588 {
589 #ifndef LOG_ENABLE_THREAD_SETTING
590 return 0;
591 #else
592 ThreadSetting* setting = static_cast<ThreadSetting*>(ThreadIf::tlsGetValue(*Log::mLevelKey));
593 if (setting == 0)
594 {
595 return 0;
596 }
597 if (Log::touchCount > 0)
598 {
599 Lock lock(_mutex);
600 ThreadIf::Id thread = ThreadIf::selfId();
601 HashMap<ThreadIf::Id, pair<ThreadSetting, bool> >::iterator res = Log::mThreadToLevel.find(thread);
602 assert(res != Log::mThreadToLevel.end());
603 if (res->second.second)
604 {
605 setting->mLevel = res->second.first.mLevel;
606 res->second.second = false;
607 touchCount--;
608 // cerr << "**Log::getThreadSetting:touchCount: " << Log::touchCount << "**" << endl;
609
610 //cerr << "touchcount decremented" << endl;
611 }
612 }
613 return setting;
614 #endif
615 }
616
617 void
618 Log::setThreadSetting(int serv)
619 {
620 Log::setThreadSetting(ThreadSetting(serv, getServiceLevel(serv)));
621 }
622
623 void
624 Log::setThreadSetting(int serv, Log::Level l)
625 {
626 Log::setThreadSetting(ThreadSetting(serv, l));
627 }
628
629 void
630 Log::setThreadSetting(ThreadSetting info)
631 {
632 #ifndef LOG_ENABLE_THREAD_SETTING
633 assert(0);
634 #else
635 //cerr << "Log::setThreadSetting: " << "service: " << info.service << " level " << toString(info.level) << " for " << pthread_self() << endl;
636 ThreadIf::Id thread = ThreadIf::selfId();
637 ThreadIf::tlsSetValue(*mLevelKey, (void *) new ThreadSetting(info));
638 Lock lock(_mutex);
639
640 if (Log::mThreadToLevel.find(thread) != Log::mThreadToLevel.end())
641 {
642 if (Log::mThreadToLevel[thread].second == true)
643 {
644 touchCount--;
645 }
646 }
647 Log::mThreadToLevel[thread].first = info;
648 Log::mThreadToLevel[thread].second = false;
649 Log::mServiceToThreads[info.mService].insert(thread);
650 #endif
651 }
652
653 void
654 Log::setServiceLevel(int service, Level l)
655 {
656 Lock lock(_mutex);
657 Log::mServiceToLevel[service] = l;
658 #ifndef LOG_ENABLE_THREAD_SETTING
659 assert(0);
660 #else
661 set<ThreadIf::Id>& threads = Log::mServiceToThreads[service];
662 for (set<ThreadIf::Id>::iterator i = threads.begin(); i != threads.end(); i++)
663 {
664 Log::mThreadToLevel[*i].first.mLevel = l;
665 Log::mThreadToLevel[*i].second = true;
666 }
667 Log::touchCount += (short)threads.size();
668 #endif
669 // cerr << "**Log::setServiceLevel:touchCount: " << Log::touchCount << "**" << endl;
670 }
671
672 Log::LocalLoggerId Log::localLoggerCreate(Log::Type type,
673 Log::Level level,
674 const char * logFileName,
675 ExternalLogger* externalLogger)
676 {
677 return mLocalLoggerMap.create(type, level, logFileName, externalLogger);
678 }
679
680 int Log::localLoggerReinitialize(Log::LocalLoggerId loggerId,
681 Log::Type type,
682 Log::Level level,
683 const char * logFileName,
684 ExternalLogger* externalLogger)
685 {
686 return mLocalLoggerMap.reinitialize(loggerId, type, level, logFileName, externalLogger);
687 }
688
689 int Log::localLoggerRemove(Log::LocalLoggerId loggerId)
690 {
691 return mLocalLoggerMap.remove(loggerId);
692 }
693
694 int Log::setThreadLocalLogger(Log::LocalLoggerId loggerId)
695 {
696 ThreadData* pData = static_cast<ThreadData*>(ThreadIf::tlsGetValue(*Log::mLocalLoggerKey));
697 if (pData)
698 {
699 // There was some local logger installed. Decrease its use count before we
700 // continue.
701 mLocalLoggerMap.decreaseUseCount(pData->id());
702 pData = NULL;
703 }
704 if (loggerId)
705 {
706 pData = mLocalLoggerMap.getData(loggerId);
707 }
708 ThreadIf::tlsSetValue(*mLocalLoggerKey, (void *) pData);
709 return (loggerId == 0) || (pData != NULL)?0:1;
710 }
711
712 std::ostream&
713 Log::Instance(unsigned int bytesToWrite)
714 {
715 return getLoggerData().Instance(bytesToWrite);
716 }
717
718 void
719 Log::reset()
720 {
721 getLoggerData().reset();
722 }
723
724 #ifndef WIN32
725 void
726 Log::droppingPrivileges(uid_t uid, pid_t pid)
727 {
728 getLoggerData().droppingPrivileges(uid, pid);
729 }
730 #endif
731
732 bool
733 Log::isLogging(Log::Level level, const resip::Subsystem& sub)
734 {
735 if (sub.getLevel() != Log::None)
736 {
737 return level <= sub.getLevel();
738 }
739 else
740 {
741 return (level <= Log::getLoggerData().mLevel);
742 }
743 }
744
745 void
746 Log::OutputToWin32DebugWindow(const Data& result)
747 {
748 #ifdef WIN32
749 const char *text = result.c_str();
750 #ifdef UNDER_CE
751 LPWSTR lpwstrText = resip::ToWString(text);
752 OutputDebugStringW(lpwstrText);
753 FreeWString(lpwstrText);
754 #else
755 OutputDebugStringA(text);
756 #endif
757 #endif
758 }
759
760 Log::LocalLoggerId Log::LocalLoggerMap::create(Log::Type type,
761 Log::Level level,
762 const char * logFileName,
763 ExternalLogger* externalLogger)
764 {
765 Lock lock(mLoggerInstancesMapMutex);
766 Log::LocalLoggerId id = ++mLastLocalLoggerId;
767 Log::ThreadData *pNewData = new Log::ThreadData(id, type, level, logFileName,
768 externalLogger);
769 mLoggerInstancesMap[id].first = pNewData;
770 mLoggerInstancesMap[id].second = 0;
771 return id;
772 }
773
774 int Log::LocalLoggerMap::reinitialize(Log::LocalLoggerId loggerId,
775 Log::Type type,
776 Log::Level level,
777 const char * logFileName,
778 ExternalLogger* externalLogger)
779 {
780 Lock lock(mLoggerInstancesMapMutex);
781 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
782 if (it == mLoggerInstancesMap.end())
783 {
784 // No such logger ID
785 std::cerr << "Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl;
786 return 1;
787 }
788 it->second.first->reset();
789 it->second.first->set(type, level, logFileName, externalLogger);
790 return 0;
791 }
792
793 int Log::LocalLoggerMap::remove(Log::LocalLoggerId loggerId)
794 {
795 Lock lock(mLoggerInstancesMapMutex);
796 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
797 if (it == mLoggerInstancesMap.end())
798 {
799 // No such logger ID
800 std::cerr << "Log::LocalLoggerMap::remove(): Unknown local logger id=" << loggerId << std::endl;
801 return 1;
802 }
803 if (it->second.second > 0)
804 {
805 // Non-zero use-count.
806 std::cerr << "Log::LocalLoggerMap::remove(): Use count is non-zero (" << it->second.second << ")!" << std::endl;
807 return 2;
808 }
809 delete it->second.first; // delete ThreadData
810 mLoggerInstancesMap.erase(it);
811 return 0;
812 }
813
814 Log::ThreadData *Log::LocalLoggerMap::getData(Log::LocalLoggerId loggerId)
815 {
816 Lock lock(mLoggerInstancesMapMutex);
817 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
818 if (it == mLoggerInstancesMap.end())
819 {
820 // No such logger ID
821 return NULL;
822 }
823 it->second.second++;
824 return it->second.first;
825 }
826
827 void Log::LocalLoggerMap::decreaseUseCount(Log::LocalLoggerId loggerId)
828 {
829 Lock lock(mLoggerInstancesMapMutex);
830 LoggerInstanceMap::iterator it = mLoggerInstancesMap.find(loggerId);
831 if (it != mLoggerInstancesMap.end())
832 {
833 it->second.second--;
834 assert(it->second.second >= 0);
835 }
836 }
837
838
839 Log::Guard::Guard(resip::Log::Level level,
840 const resip::Subsystem& subsystem,
841 const char* file,
842 int line) :
843 mLevel(level),
844 mSubsystem(subsystem),
845 mFile(file),
846 mLine(line),
847 mData(Data::Borrow, mBuffer, sizeof(mBuffer)),
848 mStream(mData.clear())
849 {
850
851 if (resip::Log::getLoggerData().mType != resip::Log::OnlyExternalNoHeaders)
852 {
853 Log::tags(mLevel, mSubsystem, mFile, mLine, mStream);
854 mStream << resip::Log::delim;
855 mStream.flush();
856
857 mHeaderLength = mData.size();
858 }
859 else
860 {
861 mHeaderLength = 0;
862 }
863 }
864
865 Log::Guard::~Guard()
866 {
867 mStream.flush();
868
869 if (resip::Log::getExternal())
870 {
871 const resip::Data rest(resip::Data::Share,
872 mData.data() + mHeaderLength,
873 (int)mData.size() - mHeaderLength);
874 if (!(*resip::Log::getExternal())(mLevel,
875 mSubsystem,
876 resip::Log::getAppName(),
877 mFile,
878 mLine,
879 rest,
880 mData))
881 {
882 return;
883 }
884 }
885
886 Type logType = resip::Log::getLoggerData().mType;
887
888 if(logType == resip::Log::OnlyExternal ||
889 logType == resip::Log::OnlyExternalNoHeaders)
890 {
891 return;
892 }
893
894 resip::Lock lock(resip::Log::_mutex);
895 // !dlb! implement VSDebugWindow as an external logger
896 if (logType == resip::Log::VSDebugWindow)
897 {
898 mData += "\r\n";
899 OutputToWin32DebugWindow(mData);
900 }
901 else
902 {
903 // endl is magic in syslog -- so put it here
904 std::ostream& _instance = Instance((int)mData.size()+2);
905 if (logType == resip::Log::Syslog)
906 {
907 _instance << mLevel;
908 }
909 _instance << mData << std::endl;
910 }
911 }
912
913 std::ostream&
914 Log::ThreadData::Instance(unsigned int bytesToWrite)
915 {
916 // std::cerr << "Log::ThreadData::Instance() id=" << mId << " type=" << mType << std::endl;
917 switch (mType)
918 {
919 case Log::Syslog:
920 if (mLogger == 0)
921 {
922 std::cerr << "Creating a syslog stream" << std::endl;
923 mLogger = new SysLogStream(mAppName, mSyslogFacility);
924 }
925 return *mLogger;
926
927 case Log::Cerr:
928 return std::cerr;
929
930 case Log::Cout:
931 return std::cout;
932
933 case Log::File:
934 if (mLogger == 0 ||
935 (maxLineCount() && mLineCount >= maxLineCount()) ||
936 (maxByteCount() && ((unsigned int)mLogger->tellp()+bytesToWrite) >= maxByteCount()))
937 {
938 std::cerr << "Creating a logger for file \"" << mLogFileName.c_str() << "\"" << std::endl;
939 Data logFileName(mLogFileName != "" ? mLogFileName : "resiprocate.log");
940 if (mLogger)
941 {
942 Data oldLogFileName(logFileName + ".old");
943 delete mLogger;
944 // Keep one backup file: Delete .old file, Rename log file to .old
945 // Could be expanded in the future to keep X backup log files
946 remove(oldLogFileName.c_str());
947 rename(logFileName.c_str(), oldLogFileName.c_str());
948 }
949 mLogger = new std::ofstream(logFileName.c_str(), std::ios_base::out | std::ios_base::app);
950 mLineCount = 0;
951 }
952 mLineCount++;
953 return *mLogger;
954 default:
955 assert(0);
956 return std::cout;
957 }
958 }
959
960 void
961 Log::ThreadData::reset()
962 {
963 delete mLogger;
964 mLogger = NULL;
965 }
966
967 #ifndef WIN32
968 void
969 Log::ThreadData::droppingPrivileges(uid_t uid, pid_t pid)
970 {
971 if(mType == Log::File)
972 {
973 Data logFileName(mLogFileName != "" ? mLogFileName : "resiprocate.log");
974 if(chown(logFileName.c_str(), uid, pid) < 0)
975 {
976 // Some error occurred
977 std::cerr << "ERROR: chown failed on " << logFileName << std::endl;
978 }
979 }
980 }
981 #endif
982
983 /* ====================================================================
984 * The Vovida Software License, Version 1.0
985 *
986 * Copyright (c) 2000-2005
987 *
988 * Redistribution and use in source and binary forms, with or without
989 * modification, are permitted provided that the following conditions
990 * are met:
991 *
992 * 1. Redistributions of source code must retain the above copyright
993 * notice, this list of conditions and the following disclaimer.
994 *
995 * 2. Redistributions in binary form must reproduce the above copyright
996 * notice, this list of conditions and the following disclaimer in
997 * the documentation and/or other materials provided with the
998 * distribution.
999 *
1000 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1001 * and "Vovida Open Communication Application Library (VOCAL)" must
1002 * not be used to endorse or promote products derived from this
1003 * software without prior written permission. For written
1004 * permission, please contact vocal@vovida.org.
1005 *
1006 * 4. Products derived from this software may not be called "VOCAL", nor
1007 * may "VOCAL" appear in their name, without prior written
1008 * permission of Vovida Networks, Inc.
1009 *
1010 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1011 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1012 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1013 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1014 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1015 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1016 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1017 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1018 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1019 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1020 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1021 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1022 * DAMAGE.
1023 *
1024 * ====================================================================
1025 *
1026 * This software consists of voluntary contributions made by Vovida
1027 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1028 * Inc. For more information on Vovida Networks, Inc., please see
1029 * <http://www.vovida.org/>.
1030 *
1031 */

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27