1 /* 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> 23 #include "trace_linux.h" 24 #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 34 namespace webrtc { 35 static WebRtc_UWord32 levelFilter = kTraceDefault; 36 37 // Construct On First Use idiom. Avoids "static initialization order fiasco". 38 Trace* 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 182 void Trace::CreateTrace() 183 { 184 TraceImpl::StaticInstance(WEBRTC_TRACE_INC); 185 } 186 187 void Trace::ReturnTrace() 188 { 189 TraceImpl::StaticInstance(WEBRTC_TRACE_DEC); 190 } 191 192 TraceImpl* TraceImpl::GetTrace(const TraceLevel level) 193 { 194 return (TraceImpl*)StaticInstance(WEBRTC_TRACE_INC_NO_CREATE, level); 195 } 196 197 Trace* TraceImpl::CreateTrace() 198 { 199 #if defined(_WIN32) 200 return new TraceWindows(); 201 #else 202 return new TraceLinux(); 203 #endif 204 } 205 206 TraceImpl::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 238 bool 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 268 TraceImpl::~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 286 WebRtc_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 331 WebRtc_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 483 WebRtc_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 517 WebRtc_Word32 TraceImpl::TraceFileImpl( 518 WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize]) 519 { 520 CriticalSectionScoped lock(_critsectInterface); 521 return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize); 522 } 523 524 WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) 525 { 526 CriticalSectionScoped lock(_critsectInterface); 527 _callback = callback; 528 return 0; 529 } 530 531 WebRtc_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 565 void 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 617 bool TraceImpl::Run(void* obj) 618 { 619 return static_cast<TraceImpl*>(obj)->Process(); 620 } 621 622 bool 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 637 void 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 736 void 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 793 bool TraceImpl::TraceCheck(const TraceLevel level) const 794 { 795 return (level & levelFilter)? true:false; 796 } 797 798 bool 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_); 835 sprintf(fileNameWithCounterUTF8+lengthTo_, "_%lu%s", newCount, 836 fileNameUTF8+lengthWithoutFileEnding); 837 return true; 838 } 839 840 bool TraceImpl::CreateFileName( 841 const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], 842 WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], 843 const WebRtc_UWord32 newCount) const 844 { 845 WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); 846 if(length < 0) 847 { 848 return false; 849 } 850 851 WebRtc_Word32 lengthWithoutFileEnding = length-1; 852 while(lengthWithoutFileEnding > 0) 853 { 854 if(fileNameUTF8[lengthWithoutFileEnding] == '.') 855 { 856 break; 857 }else 858 { 859 lengthWithoutFileEnding--; 860 } 861 } 862 if(lengthWithoutFileEnding == 0) 863 { 864 lengthWithoutFileEnding = length; 865 } 866 memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthWithoutFileEnding); 867 sprintf(fileNameWithCounterUTF8+lengthWithoutFileEnding, "_%lu%s", 868 newCount, fileNameUTF8+lengthWithoutFileEnding); 869 return true; 870 } 871 872 WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter) 873 { 874 levelFilter = filter; 875 return 0; 876 }; 877 878 WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter) 879 { 880 filter = levelFilter; 881 return 0; 882 }; 883 884 WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize]) 885 { 886 TraceImpl* trace = TraceImpl::GetTrace(); 887 if(trace) 888 { 889 int retVal = trace->TraceFileImpl(fileName); 890 ReturnTrace(); 891 return retVal; 892 } 893 return -1; 894 } 895 896 WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* fileName, 897 const bool addFileCounter) 898 { 899 TraceImpl* trace = TraceImpl::GetTrace(); 900 if(trace) 901 { 902 int retVal = trace->SetTraceFileImpl(fileName, addFileCounter); 903 ReturnTrace(); 904 return retVal; 905 } 906 return -1; 907 } 908 909 WebRtc_Word32 Trace::SetTraceCallback(TraceCallback* callback) 910 { 911 TraceImpl* trace = TraceImpl::GetTrace(); 912 if(trace) 913 { 914 int retVal = trace->SetTraceCallbackImpl(callback); 915 ReturnTrace(); 916 return retVal; 917 } 918 return -1; 919 } 920 921 void Trace::Add(const TraceLevel level, const TraceModule module, 922 const WebRtc_Word32 id, const char* msg, ...) 923 924 { 925 TraceImpl* trace = TraceImpl::GetTrace(level); 926 if(trace) 927 { 928 if(trace->TraceCheck(level)) 929 { 930 char tempBuff[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; 931 char* buff = 0; 932 if(msg) 933 { 934 va_list args; 935 va_start(args, msg); 936 #ifdef _WIN32 937 _vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args); 938 #else 939 vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args); 940 #endif 941 va_end(args); 942 buff = tempBuff; 943 } 944 trace->AddImpl(level, module, id, buff); 945 } 946 ReturnTrace(); 947 } 948 } 949 } // namespace webrtc 950