blob: c9be30ab9f1eb9fbf0a414c498477edcc8761f96 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "trace_impl.h"
12
13#include <cassert>
14#include <string.h> // memset
15
16#ifdef _WIN32
17#include "trace_windows.h"
18#include "fix_interlocked_exchange_pointer_windows.h"
19#else
20#include <stdio.h>
21#include <time.h>
22#include <stdarg.h>
ajm@google.comb5c49ff2011-08-01 17:04:04 +000023#include "trace_posix.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000024#endif // _WIN32
25
26#define KEY_LEN_CHARS 31
27
28#ifdef _WIN32
29 #pragma warning(disable:4355)
30// VS 2005: Disable warnings for default initialized arrays.
31 #pragma warning(disable:4351)
32#endif // _WIN32
33
34namespace webrtc {
35static WebRtc_UWord32 levelFilter = kTraceDefault;
36
37// Construct On First Use idiom. Avoids "static initialization order fiasco".
38Trace* TraceImpl::StaticInstance(TraceCount inc, const TraceLevel level)
39{
40 // TODO (hellner): use atomic wrapper instead.
41 static volatile long theTraceCount = 0;
42 static Trace* volatile theTrace = NULL;
43
44 TraceCreate state = WEBRTC_TRACE_EXIST;
45
46 // Sanitys to avoid taking lock unless absolutely necessary (for
47 // performance reasons). inc == WEBRTC_TRACE_INC_NO_CREATE) implies that
48 // a message will be written to file.
49 if(level != kTraceAll && inc == WEBRTC_TRACE_INC_NO_CREATE)
50 {
51 if(!(level & levelFilter))
52 {
53 return NULL;
54 }
55 }
56
57#ifndef _WIN32
58 // TODO (pwestin): crtiSect is never reclaimed. Fix memory leak.
59 static CriticalSectionWrapper* crtiSect(
60 CriticalSectionWrapper::CreateCriticalSection());
61 CriticalSectionScoped lock(*crtiSect);
62
63 if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0)
64 {
65 return NULL;
66 }
67
68 if(inc == WEBRTC_TRACE_INC || inc == WEBRTC_TRACE_INC_NO_CREATE)
69 {
70 theTraceCount++;
71 if(theTraceCount == 1)
72 {
73 state = WEBRTC_TRACE_CREATE;
74 }
75 } else {
76 theTraceCount--;
77 if(theTraceCount == 0)
78 {
79 state = WEBRTC_TRACE_DESTROY;
80 }
81 }
82 if(state == WEBRTC_TRACE_CREATE)
83 {
84 theTrace = TraceImpl::CreateTrace();
85
86 } else if(state == WEBRTC_TRACE_DESTROY) {
87 Trace* oldValue = theTrace;
88 theTrace = NULL;
89 // The lock is held by the scoped critical section. Release the lock
90 // temporarily so that the trace can be safely deleted. If the lock
91 // was kept during the delete, e.g. creating and destroying the trace
92 // too quickly may lead to a deadlock.
93 // This is due to the fact that starting and stopping a ThreadWrapper
94 // thread will trigger writing of trace messages.
95 // TODO (hellner): remove the tight coupling with the thread
96 // implementation.
97 crtiSect->Leave();
98 if(oldValue)
99 {
100 delete static_cast<TraceImpl*>(oldValue);
101 }
102 // Re-aqcuire the lock.
103 crtiSect->Enter();
104 return NULL;
105 }
106#else // _WIN32
107 if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0)
108 {
109 return NULL;
110 }
111 if(inc == WEBRTC_TRACE_INC_NO_CREATE)
112 {
113 if(1 == InterlockedIncrement(&theTraceCount))
114 {
115 // The trace has been destroyed by some other thread. Rollback.
116 InterlockedDecrement(&theTraceCount);
117 assert(false);
118 return NULL;
119 }
120 // Sanity to catch corrupt state.
121 if(theTrace == NULL)
122 {
123 assert(false);
124 InterlockedDecrement(&theTraceCount);
125 return NULL;
126 }
127 } else if(inc == WEBRTC_TRACE_INC) {
128 if(theTraceCount == 0)
129 {
130 state = WEBRTC_TRACE_CREATE;
131 } else {
132 if(1 == InterlockedIncrement(&theTraceCount))
133 {
134 // InterlockedDecrement because reference count should not be
135 // updated just yet (that's done when the trace is created).
136 InterlockedDecrement(&theTraceCount);
137 state = WEBRTC_TRACE_CREATE;
138 }
139 }
140 } else {
141 int newValue = InterlockedDecrement(&theTraceCount);
142 if(newValue == 0)
143 {
144 state = WEBRTC_TRACE_DESTROY;
145 }
146 }
147
148 if(state == WEBRTC_TRACE_CREATE)
149 {
150 // Create trace and let whichever thread finishes first assign its local
151 // copy to the global instance. All other threads reclaim their local
152 // copy.
153 Trace* newTrace = TraceImpl::CreateTrace();
154 if(1 == InterlockedIncrement(&theTraceCount))
155 {
156 Trace* oldValue = (Trace*)InterlockedExchangePointer(
157 reinterpret_cast<void* volatile*>(&theTrace), newTrace);
158 assert(oldValue == NULL);
159 assert(theTrace);
160 } else {
161 InterlockedDecrement(&theTraceCount);
162 if(newTrace)
163 {
164 delete static_cast<TraceImpl*>(newTrace);
165 }
166 }
167 return NULL;
168 } else if(state == WEBRTC_TRACE_DESTROY)
169 {
170 Trace* oldValue = (Trace*)InterlockedExchangePointer(
171 reinterpret_cast<void* volatile*>(&theTrace), NULL);
172 if(oldValue)
173 {
174 delete static_cast<TraceImpl*>(oldValue);
175 }
176 return NULL;
177 }
178#endif // #ifndef _WIN32
179 return theTrace;
180}
181
182void Trace::CreateTrace()
183{
184 TraceImpl::StaticInstance(WEBRTC_TRACE_INC);
185}
186
187void Trace::ReturnTrace()
188{
189 TraceImpl::StaticInstance(WEBRTC_TRACE_DEC);
190}
191
192TraceImpl* TraceImpl::GetTrace(const TraceLevel level)
193{
194 return (TraceImpl*)StaticInstance(WEBRTC_TRACE_INC_NO_CREATE, level);
195}
196
197Trace* TraceImpl::CreateTrace()
198{
199#if defined(_WIN32)
200 return new TraceWindows();
201#else
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000202 return new TracePosix();
niklase@google.com470e71d2011-07-07 08:21:25 +0000203#endif
204}
205
206TraceImpl::TraceImpl()
207 : _critsectInterface(*CriticalSectionWrapper::CreateCriticalSection()),
208 _callback(NULL),
209 _rowCountText(0),
210 _fileCountText(0),
211 _traceFile(*FileWrapper::Create()),
212 _thread(*ThreadWrapper::CreateThread(TraceImpl::Run, this,
213 kHighestPriority, "Trace")),
214 _event(*EventWrapper::Create()),
215 _critsectArray(*CriticalSectionWrapper::CreateCriticalSection()),
216 _nextFreeIdx(),
217 _level(),
218 _length(),
219 _messageQueue(),
220 _activeQueue(0)
221{
222 _nextFreeIdx[0] = 0;
223 _nextFreeIdx[1] = 0;
224
225 unsigned int tid = 0;
226 _thread.Start(tid);
227
228 for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
229 {
230 for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
231 {
232 _messageQueue[m][n] = new
233 WebRtc_Word8[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
234 }
235 }
236}
237
238bool TraceImpl::StopThread()
239{
240 // Release the worker thread so that it can flush any lingering messages.
241 _event.Set();
242
243 // Allow 10 ms for pending messages to be flushed out.
244 // TODO (hellner): why not use condition variables to do this? Or let the
245 // worker thread die and let this thread flush remaining
246 // messages?
247#ifdef _WIN32
248 Sleep(10);
249#else
250 timespec t;
251 t.tv_sec = 0;
252 t.tv_nsec = 10*1000000;
253 nanosleep(&t,NULL);
254#endif
255
256 _thread.SetNotAlive();
257 // Make sure the thread finishes as quickly as possible (instead of having
258 // to wait for the timeout).
259 _event.Set();
260 bool stopped = _thread.Stop();
261
262 CriticalSectionScoped lock(_critsectInterface);
263 _traceFile.Flush();
264 _traceFile.CloseFile();
265 return stopped;
266}
267
268TraceImpl::~TraceImpl()
269{
270 StopThread();
271 delete &_event;
272 delete &_traceFile;
273 delete &_thread;
274 delete &_critsectInterface;
275 delete &_critsectArray;
276
277 for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
278 {
279 for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
280 {
281 delete [] _messageQueue[m][n];
282 }
283 }
284}
285
286WebRtc_Word32 TraceImpl::AddLevel(char* szMessage, const TraceLevel level) const
287{
288 switch (level)
289 {
290 case kTraceStateInfo:
291 sprintf (szMessage, "STATEINFO ; ");
292 break;
293 case kTraceWarning:
294 sprintf (szMessage, "WARNING ; ");
295 break;
296 case kTraceError:
297 sprintf (szMessage, "ERROR ; ");
298 break;
299 case kTraceCritical:
300 sprintf (szMessage, "CRITICAL ; ");
301 break;
302 case kTraceInfo:
303 sprintf (szMessage, "DEBUGINFO ; ");
304 break;
305 case kTraceModuleCall:
306 sprintf (szMessage, "MODULECALL; ");
307 break;
308 case kTraceMemory:
309 sprintf (szMessage, "MEMORY ; ");
310 break;
311 case kTraceTimer:
312 sprintf (szMessage, "TIMER ; ");
313 break;
314 case kTraceStream:
315 sprintf (szMessage, "STREAM ; ");
316 break;
317 case kTraceApiCall:
318 sprintf (szMessage, "APICALL ; ");
319 break;
320 case kTraceDebug:
321 sprintf (szMessage, "DEBUG ; ");
322 break;
323 default:
324 assert(false);
325 return 0;
326 }
327 // All messages are 12 characters.
328 return 12;
329}
330
331WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage,
332 const TraceModule module,
333 const WebRtc_Word32 id) const
334{
335 // Use long int to prevent problems with different definitions of
336 // WebRtc_Word32.
337 // TODO (hellner): is this actually a problem? If so, it should be better to
338 // clean up WebRtc_Word32
339 const long int idl = id;
340 if(idl != -1)
341 {
342 const unsigned long int idEngine = id>>16;
343 const unsigned long int idChannel = id & 0xffff;
344
345 switch (module)
346 {
347 case kTraceVoice:
348 sprintf(traceMessage, " VOICE:%5ld %5ld;", idEngine,
349 idChannel);
350 break;
351 case kTraceVideo:
352 sprintf(traceMessage, " VIDEO:%5ld %5ld;", idEngine,
353 idChannel);
354 break;
355 case kTraceUtility:
356 sprintf(traceMessage, " UTILITY:%5ld %5ld;", idEngine,
357 idChannel);
358 break;
359 case kTraceRtpRtcp:
360 sprintf(traceMessage, " RTP/RTCP:%5ld %5ld;", idEngine,
361 idChannel);
362 break;
363 case kTraceTransport:
364 sprintf(traceMessage, " TRANSPORT:%5ld %5ld;", idEngine,
365 idChannel);
366 break;
367 case kTraceAudioCoding:
368 sprintf(traceMessage, "AUDIO CODING:%5ld %5ld;", idEngine,
369 idChannel);
370 break;
371 case kTraceSrtp:
372 sprintf(traceMessage, " SRTP:%5ld %5ld;", idEngine,
373 idChannel);
374 break;
375 case kTraceAudioMixerServer:
376 sprintf(traceMessage, " AUDIO MIX/S:%5ld %5ld;", idEngine,
377 idChannel);
378 break;
379 case kTraceAudioMixerClient:
380 sprintf(traceMessage, " AUDIO MIX/C:%5ld %5ld;", idEngine,
381 idChannel);
382 break;
383 case kTraceVideoCoding:
384 sprintf(traceMessage, "VIDEO CODING:%5ld %5ld;", idEngine,
385 idChannel);
386 break;
387 case kTraceVideoMixer:
388 // Print sleep time and API call
389 sprintf(traceMessage, " VIDEO MIX:%5ld %5ld;", idEngine,
390 idChannel);
391 break;
392 case kTraceFile:
393 sprintf(traceMessage, " FILE:%5ld %5ld;", idEngine,
394 idChannel);
395 break;
396 case kTraceAudioProcessing:
397 sprintf(traceMessage, " AUDIO PROC:%5ld %5ld;", idEngine,
398 idChannel);
399 break;
400 case kTraceAudioDevice:
401 sprintf(traceMessage, "AUDIO DEVICE:%5ld %5ld;", idEngine,
402 idChannel);
403 break;
404 case kTraceVideoRenderer:
405 sprintf(traceMessage, "VIDEO RENDER:%5ld %5ld;", idEngine,
406 idChannel);
407 break;
408 case kTraceVideoCapture:
409 sprintf(traceMessage, "VIDEO CAPTUR:%5ld %5ld;", idEngine,
410 idChannel);
411 break;
412 case kTraceVideoPreocessing:
413 sprintf(traceMessage, " VIDEO PROC:%5ld %5ld;", idEngine,
414 idChannel);
415 break;
416 default:
417 assert(false);
418 return 0;
419 }
420 } else {
421 switch (module)
422 {
423 case kTraceVoice:
424 sprintf (traceMessage, " VOICE:%11ld;", idl);
425 break;
426 case kTraceVideo:
427 sprintf (traceMessage, " VIDEO:%11ld;", idl);
428 break;
429 case kTraceUtility:
430 sprintf (traceMessage, " UTILITY:%11ld;", idl);
431 break;
432 case kTraceRtpRtcp:
433 sprintf (traceMessage, " RTP/RTCP:%11ld;", idl);
434 break;
435 case kTraceTransport:
436 sprintf (traceMessage, " TRANSPORT:%11ld;", idl);
437 break;
438 case kTraceAudioCoding:
439 sprintf (traceMessage, "AUDIO CODING:%11ld;", idl);
440 break;
441 case kTraceSrtp:
442 sprintf (traceMessage, " SRTP:%11ld;", idl);
443 break;
444 case kTraceAudioMixerServer:
445 sprintf (traceMessage, " AUDIO MIX/S:%11ld;", idl);
446 break;
447 case kTraceAudioMixerClient:
448 sprintf (traceMessage, " AUDIO MIX/C:%11ld;", idl);
449 break;
450 case kTraceVideoCoding:
451 sprintf (traceMessage, "VIDEO CODING:%11ld;", idl);
452 break;
453 case kTraceVideoMixer:
454 sprintf (traceMessage, " VIDEO MIX:%11ld;", idl);
455 break;
456 case kTraceFile:
457 sprintf (traceMessage, " FILE:%11ld;", idl);
458 break;
459 case kTraceAudioProcessing:
460 sprintf (traceMessage, " AUDIO PROC:%11ld;", idl);
461 break;
462 case kTraceAudioDevice:
463 sprintf (traceMessage, "AUDIO DEVICE:%11ld;", idl);
464 break;
465 case kTraceVideoRenderer:
466 sprintf (traceMessage, "VIDEO RENDER:%11ld;", idl);
467 break;
468 case kTraceVideoCapture:
469 sprintf (traceMessage, "VIDEO CAPTUR:%11ld;", idl);
470 break;
471 case kTraceVideoPreocessing:
472 sprintf (traceMessage, " VIDEO PROC:%11ld;", idl);
473 break;
474 default:
475 assert(false);
476 return 0;
477 }
478 }
479 // All messages are 25 characters.
480 return 25;
481}
482
483WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8,
484 const bool addFileCounter)
485{
486 CriticalSectionScoped lock(_critsectInterface);
487
488 _traceFile.Flush();
489 _traceFile.CloseFile();
490
491 if(fileNameUTF8)
492 {
493 if(addFileCounter)
494 {
495 _fileCountText = 1;
496
497 WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize];
498 CreateFileName(fileNameUTF8, fileNameWithCounterUTF8,
499 _fileCountText);
500 if(_traceFile.OpenFile(fileNameWithCounterUTF8, false, false,
501 true) == -1)
502 {
503 return -1;
504 }
505 }else {
506 _fileCountText = 0;
507 if(_traceFile.OpenFile(fileNameUTF8, false, false, true) == -1)
508 {
509 return -1;
510 }
511 }
512 }
513 _rowCountText = 0;
514 return 0;
515}
516
517WebRtc_Word32 TraceImpl::TraceFileImpl(
518 WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize])
519{
520 CriticalSectionScoped lock(_critsectInterface);
521 return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize);
522}
523
524WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback)
525{
526 CriticalSectionScoped lock(_critsectInterface);
527 _callback = callback;
528 return 0;
529}
530
531WebRtc_Word32 TraceImpl::AddMessage(
532 char* traceMessage,
533 const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
534 const WebRtc_UWord16 writtenSoFar) const
535
536{
537 int length = 0;
538 if(writtenSoFar >= WEBRTC_TRACE_MAX_MESSAGE_SIZE)
539 {
540 return -1;
541 }
542 // - 2 to leave room for newline and NULL termination
543#ifdef _WIN32
544 length = _snprintf(traceMessage,
545 WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2,
546 "%s",msg);
547 if(length < 0)
548 {
549 length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
550 traceMessage[length] = 0;
551 }
552#else
553 length = snprintf(traceMessage,
554 WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar-2, "%s",msg);
555 if(length < 0 || length > WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar - 2)
556 {
557 length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
558 traceMessage[length] = 0;
559 }
560#endif
561 // Length with NULL termination.
562 return length+1;
563}
564
565void TraceImpl::AddMessageToList(
566 const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
567 const WebRtc_UWord16 length,
568 const TraceLevel level)
569{
570 CriticalSectionScoped lock(_critsectArray);
571
572 if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE)
573 {
574 if( ! _traceFile.Open() &&
575 !_callback)
576 {
577 // Keep at least the last 1/4 of old messages when not logging.
578 // TODO (hellner): isn't this redundant. The user will make it known
579 // when to start logging. Why keep messages before
580 // that?
581 for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE/4; n++)
582 {
583 const int lastQuarterOffset = (3*WEBRTC_TRACE_MAX_QUEUE/4);
584 memcpy(_messageQueue[_activeQueue][n],
585 _messageQueue[_activeQueue][n + lastQuarterOffset],
586 WEBRTC_TRACE_MAX_MESSAGE_SIZE);
587 }
588 _nextFreeIdx[_activeQueue] = WEBRTC_TRACE_MAX_QUEUE/4;
589 } else {
590 // More messages are being written than there is room for in the
591 // buffer. Drop any new messages.
592 // TODO (hellner): its probably better to drop old messages instead
593 // of new ones. One step further: if this happens
594 // it's due to writing faster than what can be
595 // processed. Maybe modify the filter at this point.
596 // E.g. turn of STREAM.
597 return;
598 }
599 }
600
601 WebRtc_UWord16 idx = _nextFreeIdx[_activeQueue];
602 _nextFreeIdx[_activeQueue]++;
603
604 _level[_activeQueue][idx] = level;
605 _length[_activeQueue][idx] = length;
606 memcpy(_messageQueue[_activeQueue][idx], traceMessage, length);
607
608 if(_nextFreeIdx[_activeQueue] == WEBRTC_TRACE_MAX_QUEUE-1)
609 {
610 // Loggin more messages than can be worked off. Log a warning.
611 memcpy(_messageQueue[_activeQueue][_nextFreeIdx[_activeQueue]],
612 "WARNING MISSING TRACE MESSAGES\n", 32);
613 _nextFreeIdx[_activeQueue]++;
614 }
615}
616
617bool TraceImpl::Run(void* obj)
618{
619 return static_cast<TraceImpl*>(obj)->Process();
620}
621
622bool TraceImpl::Process()
623{
624 if(_event.Wait(1000) == kEventSignaled)
625 {
626 if(_traceFile.Open() || _callback)
627 {
628 // File mode (not calback mode).
629 WriteToFile();
630 }
631 } else {
632 _traceFile.Flush();
633 }
634 return true;
635}
636
637void TraceImpl::WriteToFile()
638{
639 WebRtc_UWord8 localQueueActive = 0;
640 WebRtc_UWord16 localNextFreeIdx = 0;
641
642 // There are two buffer. One for reading (for writing to file) and one for
643 // writing (for storing new messages). Let new messages be posted to the
644 // unused buffer so that the current buffer can be flushed safely.
645 {
646 CriticalSectionScoped lock(_critsectArray);
647 localNextFreeIdx = _nextFreeIdx[_activeQueue];
648 _nextFreeIdx[_activeQueue] = 0;
649 localQueueActive = _activeQueue;
650 if(_activeQueue == 0)
651 {
652 _activeQueue = 1;
653 } else
654 {
655 _activeQueue = 0;
656 }
657 }
658 if(localNextFreeIdx == 0)
659 {
660 return;
661 }
662
663 CriticalSectionScoped lock(_critsectInterface);
664
665 for(WebRtc_UWord16 idx = 0; idx <localNextFreeIdx; idx++)
666 {
667 TraceLevel localLevel = _level[localQueueActive][idx];
668 if(_callback)
669 {
670 _callback->Print(localLevel, _messageQueue[localQueueActive][idx],
671 _length[localQueueActive][idx]);
672 }
673 if(_traceFile.Open())
674 {
675 if(_rowCountText > WEBRTC_TRACE_MAX_FILE_SIZE)
676 {
677 // wrap file
678 _rowCountText = 0;
679 _traceFile.Flush();
680
681 if(_fileCountText == 0)
682 {
683 _traceFile.Rewind();
684 } else
685 {
686 WebRtc_Word8 oldFileName[FileWrapper::kMaxFileNameSize];
687 WebRtc_Word8 newFileName[FileWrapper::kMaxFileNameSize];
688
689 // get current name
690 _traceFile.FileName(oldFileName,
691 FileWrapper::kMaxFileNameSize);
692 _traceFile.CloseFile();
693
694 _fileCountText++;
695
696 UpdateFileName(oldFileName, newFileName, _fileCountText);
697
698 if(_traceFile.OpenFile(newFileName, false, false,
699 true) == -1)
700 {
701 return;
702 }
703 }
704 }
705 if(_rowCountText == 0)
706 {
707 WebRtc_Word8 message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
708 WebRtc_Word32 length = AddDateTimeInfo(message);
709 if(length != -1)
710 {
711 message[length] = 0;
712 message[length-1] = '\n';
713 _traceFile.Write(message, length);
714 _rowCountText++;
715 }
716 length = AddBuildInfo(message);
717 if(length != -1)
718 {
719 message[length+1] = 0;
720 message[length] = '\n';
721 message[length-1] = '\n';
722 _traceFile.Write(message, length+1);
723 _rowCountText++;
724 _rowCountText++;
725 }
726 }
727 WebRtc_UWord16 length = _length[localQueueActive][idx];
728 _messageQueue[localQueueActive][idx][length] = 0;
729 _messageQueue[localQueueActive][idx][length-1] = '\n';
730 _traceFile.Write(_messageQueue[localQueueActive][idx], length);
731 _rowCountText++;
732 }
733 }
734}
735
736void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module,
737 const WebRtc_Word32 id,
738 const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE])
739{
740 if (TraceCheck(level))
741 {
742 char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
743 char* meassagePtr = traceMessage;
744
745 WebRtc_Word32 len = 0;
746 WebRtc_Word32 ackLen = 0;
747
748 len = AddLevel(meassagePtr, level);
749 if(len == -1)
750 {
751 return;
752 }
753 meassagePtr += len;
754 ackLen += len;
755
756 len = AddTime(meassagePtr, level);
757 if(len == -1)
758 {
759 return;
760 }
761 meassagePtr += len;
762 ackLen += len;
763
764 len = AddModuleAndId(meassagePtr, module, id);
765 if(len == -1)
766 {
767 return;
768 }
769 meassagePtr += len;
770 ackLen += len;
771
772 len = AddThreadId(meassagePtr);
773 if(len == -1)
774 {
775 return;
776 }
777 meassagePtr += len;
778 ackLen += len;
779
780 len = AddMessage(meassagePtr, msg, (WebRtc_UWord16)ackLen);
781 if(len == -1)
782 {
783 return;
784 }
785 ackLen += len;
786 AddMessageToList(traceMessage,(WebRtc_UWord16)ackLen, level);
787
788 // Make sure that messages are written as soon as possible.
789 _event.Set();
790 }
791}
792
793bool TraceImpl::TraceCheck(const TraceLevel level) const
794{
795 return (level & levelFilter)? true:false;
796}
797
798bool TraceImpl::UpdateFileName(
799 const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize],
800 WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
801 const WebRtc_UWord32 newCount) const
802{
803 WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
804 if(length < 0)
805 {
806 return false;
807 }
808
809 WebRtc_Word32 lengthWithoutFileEnding = length-1;
810 while(lengthWithoutFileEnding > 0)
811 {
812 if(fileNameUTF8[lengthWithoutFileEnding] == '.')
813 {
814 break;
815 } else {
816 lengthWithoutFileEnding--;
817 }
818 }
819 if(lengthWithoutFileEnding == 0)
820 {
821 lengthWithoutFileEnding = length;
822 }
823 WebRtc_Word32 lengthTo_ = lengthWithoutFileEnding - 1;
824 while(lengthTo_ > 0)
825 {
826 if(fileNameUTF8[lengthTo_] == '_')
827 {
828 break;
829 } else {
830 lengthTo_--;
831 }
832 }
833
834 memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthTo_);
hellner@google.com064a8df2011-08-16 15:52:28 +0000835 sprintf(fileNameWithCounterUTF8+lengthTo_, "_%lu%s",
836 static_cast<long unsigned int> (newCount),
niklase@google.com470e71d2011-07-07 08:21:25 +0000837 fileNameUTF8+lengthWithoutFileEnding);
838 return true;
839}
840
841bool TraceImpl::CreateFileName(
842 const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize],
843 WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
844 const WebRtc_UWord32 newCount) const
845{
846 WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
847 if(length < 0)
848 {
849 return false;
850 }
851
852 WebRtc_Word32 lengthWithoutFileEnding = length-1;
853 while(lengthWithoutFileEnding > 0)
854 {
855 if(fileNameUTF8[lengthWithoutFileEnding] == '.')
856 {
857 break;
858 }else
859 {
860 lengthWithoutFileEnding--;
861 }
862 }
863 if(lengthWithoutFileEnding == 0)
864 {
865 lengthWithoutFileEnding = length;
866 }
867 memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthWithoutFileEnding);
868 sprintf(fileNameWithCounterUTF8+lengthWithoutFileEnding, "_%lu%s",
hellner@google.com064a8df2011-08-16 15:52:28 +0000869 static_cast<long unsigned int> (newCount),
870 fileNameUTF8+lengthWithoutFileEnding);
niklase@google.com470e71d2011-07-07 08:21:25 +0000871 return true;
872}
873
874WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter)
875{
876 levelFilter = filter;
877 return 0;
878};
879
880WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter)
881{
882 filter = levelFilter;
883 return 0;
884};
885
886WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize])
887{
888 TraceImpl* trace = TraceImpl::GetTrace();
889 if(trace)
890 {
891 int retVal = trace->TraceFileImpl(fileName);
892 ReturnTrace();
893 return retVal;
894 }
895 return -1;
896}
897
898WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* fileName,
899 const bool addFileCounter)
900{
901 TraceImpl* trace = TraceImpl::GetTrace();
902 if(trace)
903 {
904 int retVal = trace->SetTraceFileImpl(fileName, addFileCounter);
905 ReturnTrace();
906 return retVal;
907 }
908 return -1;
909}
910
911WebRtc_Word32 Trace::SetTraceCallback(TraceCallback* callback)
912{
913 TraceImpl* trace = TraceImpl::GetTrace();
914 if(trace)
915 {
916 int retVal = trace->SetTraceCallbackImpl(callback);
917 ReturnTrace();
918 return retVal;
919 }
920 return -1;
921}
922
923void Trace::Add(const TraceLevel level, const TraceModule module,
924 const WebRtc_Word32 id, const char* msg, ...)
925
926{
927 TraceImpl* trace = TraceImpl::GetTrace(level);
928 if(trace)
929 {
930 if(trace->TraceCheck(level))
931 {
932 char tempBuff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
933 char* buff = 0;
934 if(msg)
935 {
936 va_list args;
937 va_start(args, msg);
938#ifdef _WIN32
939 _vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
940#else
941 vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
942#endif
943 va_end(args);
944 buff = tempBuff;
945 }
946 trace->AddImpl(level, module, id, buff);
947 }
948 ReturnTrace();
949 }
950}
951} // namespace webrtc