Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2012 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 "webrtc/system_wrappers/source/trace_impl.h"
     12 
     13 #include <assert.h>
     14 #include <stdarg.h>
     15 #include <stdio.h>
     16 #include <string.h>
     17 
     18 #ifdef _WIN32
     19 #include "webrtc/system_wrappers/source/trace_win.h"
     20 #else
     21 #include "webrtc/system_wrappers/source/trace_posix.h"
     22 #endif  // _WIN32
     23 
     24 #include "webrtc/system_wrappers/interface/sleep.h"
     25 
     26 #define KEY_LEN_CHARS 31
     27 
     28 #ifdef _WIN32
     29 #pragma warning(disable:4355)
     30 #endif  // _WIN32
     31 
     32 namespace webrtc {
     33 
     34 const int Trace::kBoilerplateLength = 71;
     35 const int Trace::kTimestampPosition = 13;
     36 const int Trace::kTimestampLength = 12;
     37 uint32_t Trace::level_filter_ = kTraceDefault;
     38 
     39 // Construct On First Use idiom. Avoids "static initialization order fiasco".
     40 TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation,
     41                                      const TraceLevel level) {
     42   // Sanities to avoid taking lock unless absolutely necessary (for
     43   // performance reasons). count_operation == kAddRefNoCreate implies that a
     44   // message will be written to file.
     45   if ((level != kTraceAll) && (count_operation == kAddRefNoCreate)) {
     46     if (!(level & level_filter())) {
     47       return NULL;
     48     }
     49   }
     50   TraceImpl* impl =
     51     GetStaticInstance<TraceImpl>(count_operation);
     52   return impl;
     53 }
     54 
     55 TraceImpl* TraceImpl::GetTrace(const TraceLevel level) {
     56   return StaticInstance(kAddRefNoCreate, level);
     57 }
     58 
     59 TraceImpl* TraceImpl::CreateInstance() {
     60 #if defined(_WIN32)
     61   return new TraceWindows();
     62 #else
     63   return new TracePosix();
     64 #endif
     65 }
     66 
     67 TraceImpl::TraceImpl()
     68     : critsect_interface_(CriticalSectionWrapper::CreateCriticalSection()),
     69       callback_(NULL),
     70       row_count_text_(0),
     71       file_count_text_(0),
     72       trace_file_(*FileWrapper::Create()),
     73       thread_(*ThreadWrapper::CreateThread(TraceImpl::Run, this,
     74                                            kHighestPriority, "Trace")),
     75       event_(*EventWrapper::Create()),
     76       critsect_array_(CriticalSectionWrapper::CreateCriticalSection()),
     77       next_free_idx_(),
     78       level_(),
     79       length_(),
     80       message_queue_(),
     81       active_queue_(0) {
     82   next_free_idx_[0] = 0;
     83   next_free_idx_[1] = 0;
     84 
     85   unsigned int tid = 0;
     86   thread_.Start(tid);
     87 
     88   for (int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; ++m) {
     89     for (int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; ++n) {
     90       message_queue_[m][n] = new
     91       char[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
     92     }
     93   }
     94 }
     95 
     96 bool TraceImpl::StopThread() {
     97   // Release the worker thread so that it can flush any lingering messages.
     98   event_.Set();
     99 
    100   // Allow 10 ms for pending messages to be flushed out.
    101   // TODO(hellner): why not use condition variables to do this? Or let the
    102   //                worker thread die and let this thread flush remaining
    103   //                messages?
    104   SleepMs(10);
    105 
    106   thread_.SetNotAlive();
    107   // Make sure the thread finishes as quickly as possible (instead of having
    108   // to wait for the timeout).
    109   event_.Set();
    110   bool stopped = thread_.Stop();
    111 
    112   CriticalSectionScoped lock(critsect_interface_);
    113   trace_file_.Flush();
    114   trace_file_.CloseFile();
    115   return stopped;
    116 }
    117 
    118 TraceImpl::~TraceImpl() {
    119   StopThread();
    120   delete &event_;
    121   delete &trace_file_;
    122   delete &thread_;
    123   delete critsect_interface_;
    124   delete critsect_array_;
    125 
    126   for (int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; ++m) {
    127     for (int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; ++n) {
    128       delete [] message_queue_[m][n];
    129     }
    130   }
    131 }
    132 
    133 int32_t TraceImpl::AddThreadId(char* trace_message) const {
    134   uint32_t thread_id = ThreadWrapper::GetThreadId();
    135   // Messages is 12 characters.
    136   return sprintf(trace_message, "%10u; ", thread_id);
    137 }
    138 
    139 int32_t TraceImpl::AddLevel(char* sz_message, const TraceLevel level) const {
    140   const int kMessageLength = 12;
    141   switch (level) {
    142     case kTraceTerseInfo:
    143       // Add the appropriate amount of whitespace.
    144       memset(sz_message, ' ', kMessageLength);
    145       sz_message[kMessageLength] = '\0';
    146       break;
    147     case kTraceStateInfo:
    148       sprintf(sz_message, "STATEINFO ; ");
    149       break;
    150     case kTraceWarning:
    151       sprintf(sz_message, "WARNING   ; ");
    152       break;
    153     case kTraceError:
    154       sprintf(sz_message, "ERROR     ; ");
    155       break;
    156     case kTraceCritical:
    157       sprintf(sz_message, "CRITICAL  ; ");
    158       break;
    159     case kTraceInfo:
    160       sprintf(sz_message, "DEBUGINFO ; ");
    161       break;
    162     case kTraceModuleCall:
    163       sprintf(sz_message, "MODULECALL; ");
    164       break;
    165     case kTraceMemory:
    166       sprintf(sz_message, "MEMORY    ; ");
    167       break;
    168     case kTraceTimer:
    169       sprintf(sz_message, "TIMER     ; ");
    170       break;
    171     case kTraceStream:
    172       sprintf(sz_message, "STREAM    ; ");
    173       break;
    174     case kTraceApiCall:
    175       sprintf(sz_message, "APICALL   ; ");
    176       break;
    177     case kTraceDebug:
    178       sprintf(sz_message, "DEBUG     ; ");
    179       break;
    180     default:
    181       assert(false);
    182       return 0;
    183   }
    184   // All messages are 12 characters.
    185   return kMessageLength;
    186 }
    187 
    188 int32_t TraceImpl::AddModuleAndId(char* trace_message,
    189                                   const TraceModule module,
    190                                   const int32_t id) const {
    191   // Use long int to prevent problems with different definitions of
    192   // int32_t.
    193   // TODO(hellner): is this actually a problem? If so, it should be better to
    194   //                clean up int32_t
    195   const long int idl = id;
    196   const int kMessageLength = 25;
    197   if (idl != -1) {
    198     const unsigned long int id_engine = id >> 16;
    199     const unsigned long int id_channel = id & 0xffff;
    200 
    201     switch (module) {
    202       case kTraceUndefined:
    203         // Add the appropriate amount of whitespace.
    204         memset(trace_message, ' ', kMessageLength);
    205         trace_message[kMessageLength] = '\0';
    206         break;
    207       case kTraceVoice:
    208         sprintf(trace_message, "       VOICE:%5ld %5ld;", id_engine,
    209                 id_channel);
    210         break;
    211       case kTraceVideo:
    212         sprintf(trace_message, "       VIDEO:%5ld %5ld;", id_engine,
    213                 id_channel);
    214         break;
    215       case kTraceUtility:
    216         sprintf(trace_message, "     UTILITY:%5ld %5ld;", id_engine,
    217                 id_channel);
    218         break;
    219       case kTraceRtpRtcp:
    220         sprintf(trace_message, "    RTP/RTCP:%5ld %5ld;", id_engine,
    221                 id_channel);
    222         break;
    223       case kTraceTransport:
    224         sprintf(trace_message, "   TRANSPORT:%5ld %5ld;", id_engine,
    225                 id_channel);
    226         break;
    227       case kTraceAudioCoding:
    228         sprintf(trace_message, "AUDIO CODING:%5ld %5ld;", id_engine,
    229                 id_channel);
    230         break;
    231       case kTraceSrtp:
    232         sprintf(trace_message, "        SRTP:%5ld %5ld;", id_engine,
    233                 id_channel);
    234         break;
    235       case kTraceAudioMixerServer:
    236         sprintf(trace_message, " AUDIO MIX/S:%5ld %5ld;", id_engine,
    237                 id_channel);
    238         break;
    239       case kTraceAudioMixerClient:
    240         sprintf(trace_message, " AUDIO MIX/C:%5ld %5ld;", id_engine,
    241                 id_channel);
    242         break;
    243       case kTraceVideoCoding:
    244         sprintf(trace_message, "VIDEO CODING:%5ld %5ld;", id_engine,
    245                 id_channel);
    246         break;
    247       case kTraceVideoMixer:
    248         // Print sleep time and API call
    249         sprintf(trace_message, "   VIDEO MIX:%5ld %5ld;", id_engine,
    250                 id_channel);
    251         break;
    252       case kTraceFile:
    253         sprintf(trace_message, "        FILE:%5ld %5ld;", id_engine,
    254                 id_channel);
    255         break;
    256       case kTraceAudioProcessing:
    257         sprintf(trace_message, "  AUDIO PROC:%5ld %5ld;", id_engine,
    258                 id_channel);
    259         break;
    260       case kTraceAudioDevice:
    261         sprintf(trace_message, "AUDIO DEVICE:%5ld %5ld;", id_engine,
    262                 id_channel);
    263         break;
    264       case kTraceVideoRenderer:
    265         sprintf(trace_message, "VIDEO RENDER:%5ld %5ld;", id_engine,
    266                 id_channel);
    267         break;
    268       case kTraceVideoCapture:
    269         sprintf(trace_message, "VIDEO CAPTUR:%5ld %5ld;", id_engine,
    270                 id_channel);
    271         break;
    272       case kTraceRemoteBitrateEstimator:
    273         sprintf(trace_message, "     BWE RBE:%5ld %5ld;", id_engine,
    274                 id_channel);
    275         break;
    276     }
    277   } else {
    278     switch (module) {
    279       case kTraceUndefined:
    280         // Add the appropriate amount of whitespace.
    281         memset(trace_message, ' ', kMessageLength);
    282         trace_message[kMessageLength] = '\0';
    283         break;
    284       case kTraceVoice:
    285         sprintf(trace_message, "       VOICE:%11ld;", idl);
    286         break;
    287       case kTraceVideo:
    288         sprintf(trace_message, "       VIDEO:%11ld;", idl);
    289         break;
    290       case kTraceUtility:
    291         sprintf(trace_message, "     UTILITY:%11ld;", idl);
    292         break;
    293       case kTraceRtpRtcp:
    294         sprintf(trace_message, "    RTP/RTCP:%11ld;", idl);
    295         break;
    296       case kTraceTransport:
    297         sprintf(trace_message, "   TRANSPORT:%11ld;", idl);
    298         break;
    299       case kTraceAudioCoding:
    300         sprintf(trace_message, "AUDIO CODING:%11ld;", idl);
    301         break;
    302       case kTraceSrtp:
    303         sprintf(trace_message, "        SRTP:%11ld;", idl);
    304         break;
    305       case kTraceAudioMixerServer:
    306         sprintf(trace_message, " AUDIO MIX/S:%11ld;", idl);
    307         break;
    308       case kTraceAudioMixerClient:
    309         sprintf(trace_message, " AUDIO MIX/C:%11ld;", idl);
    310         break;
    311       case kTraceVideoCoding:
    312         sprintf(trace_message, "VIDEO CODING:%11ld;", idl);
    313         break;
    314       case kTraceVideoMixer:
    315         sprintf(trace_message, "   VIDEO MIX:%11ld;", idl);
    316         break;
    317       case kTraceFile:
    318         sprintf(trace_message, "        FILE:%11ld;", idl);
    319         break;
    320       case kTraceAudioProcessing:
    321         sprintf(trace_message, "  AUDIO PROC:%11ld;", idl);
    322         break;
    323       case kTraceAudioDevice:
    324         sprintf(trace_message, "AUDIO DEVICE:%11ld;", idl);
    325         break;
    326       case kTraceVideoRenderer:
    327         sprintf(trace_message, "VIDEO RENDER:%11ld;", idl);
    328         break;
    329       case kTraceVideoCapture:
    330         sprintf(trace_message, "VIDEO CAPTUR:%11ld;", idl);
    331         break;
    332       case kTraceRemoteBitrateEstimator:
    333         sprintf(trace_message, "     BWE RBE:%11ld;", idl);
    334         break;
    335     }
    336   }
    337   return kMessageLength;
    338 }
    339 
    340 int32_t TraceImpl::SetTraceFileImpl(const char* file_name_utf8,
    341                                     const bool add_file_counter) {
    342   CriticalSectionScoped lock(critsect_interface_);
    343 
    344   trace_file_.Flush();
    345   trace_file_.CloseFile();
    346 
    347   if (file_name_utf8) {
    348     if (add_file_counter) {
    349       file_count_text_ = 1;
    350 
    351       char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize];
    352       CreateFileName(file_name_utf8, file_name_with_counter_utf8,
    353                      file_count_text_);
    354       if (trace_file_.OpenFile(file_name_with_counter_utf8, false, false,
    355                                true) == -1) {
    356         return -1;
    357       }
    358     } else {
    359       file_count_text_ = 0;
    360       if (trace_file_.OpenFile(file_name_utf8, false, false, true) == -1) {
    361         return -1;
    362       }
    363     }
    364   }
    365   row_count_text_ = 0;
    366   return 0;
    367 }
    368 
    369 int32_t TraceImpl::TraceFileImpl(
    370     char file_name_utf8[FileWrapper::kMaxFileNameSize]) {
    371   CriticalSectionScoped lock(critsect_interface_);
    372   return trace_file_.FileName(file_name_utf8, FileWrapper::kMaxFileNameSize);
    373 }
    374 
    375 int32_t TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) {
    376   CriticalSectionScoped lock(critsect_interface_);
    377   callback_ = callback;
    378   return 0;
    379 }
    380 
    381 int32_t TraceImpl::AddMessage(
    382     char* trace_message,
    383     const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
    384     const uint16_t written_so_far) const {
    385   int length = 0;
    386   if (written_so_far >= WEBRTC_TRACE_MAX_MESSAGE_SIZE) {
    387     return -1;
    388   }
    389   // - 2 to leave room for newline and NULL termination.
    390 #ifdef _WIN32
    391   length = _snprintf(trace_message,
    392                      WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
    393                      "%s", msg);
    394   if (length < 0) {
    395     length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
    396     trace_message[length] = 0;
    397   }
    398 #else
    399   length = snprintf(trace_message,
    400                     WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
    401                     "%s", msg);
    402   if (length < 0 ||
    403       length > WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2) {
    404     length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
    405     trace_message[length] = 0;
    406   }
    407 #endif
    408   // Length with NULL termination.
    409   return length + 1;
    410 }
    411 
    412 void TraceImpl::AddMessageToList(
    413     const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
    414     const uint16_t length,
    415     const TraceLevel level) {
    416 // NOTE(andresp): Enabled externally.
    417 #ifdef WEBRTC_DIRECT_TRACE
    418   if (callback_) {
    419     callback_->Print(level, trace_message, length);
    420   }
    421   return;
    422 #endif
    423 
    424   CriticalSectionScoped lock(critsect_array_);
    425 
    426   if (next_free_idx_[active_queue_] >= WEBRTC_TRACE_MAX_QUEUE) {
    427     if (!trace_file_.Open() && !callback_) {
    428       // Keep at least the last 1/4 of old messages when not logging.
    429       // TODO(hellner): isn't this redundant. The user will make it known
    430       //                when to start logging. Why keep messages before
    431       //                that?
    432       for (int n = 0; n < WEBRTC_TRACE_MAX_QUEUE / 4; ++n) {
    433         const int last_quarter_offset = (3 * WEBRTC_TRACE_MAX_QUEUE / 4);
    434         memcpy(message_queue_[active_queue_][n],
    435                message_queue_[active_queue_][n + last_quarter_offset],
    436                WEBRTC_TRACE_MAX_MESSAGE_SIZE);
    437       }
    438       next_free_idx_[active_queue_] = WEBRTC_TRACE_MAX_QUEUE / 4;
    439     } else {
    440       // More messages are being written than there is room for in the
    441       // buffer. Drop any new messages.
    442       // TODO(hellner): its probably better to drop old messages instead
    443       //                of new ones. One step further: if this happens
    444       //                it's due to writing faster than what can be
    445       //                processed. Maybe modify the filter at this point.
    446       //                E.g. turn of STREAM.
    447       return;
    448     }
    449   }
    450 
    451   uint16_t idx = next_free_idx_[active_queue_];
    452   next_free_idx_[active_queue_]++;
    453 
    454   level_[active_queue_][idx] = level;
    455   length_[active_queue_][idx] = length;
    456   memcpy(message_queue_[active_queue_][idx], trace_message, length);
    457 
    458   if (next_free_idx_[active_queue_] == WEBRTC_TRACE_MAX_QUEUE - 1) {
    459     // Logging more messages than can be worked off. Log a warning.
    460     const char warning_msg[] = "WARNING MISSING TRACE MESSAGES\n";
    461     level_[active_queue_][next_free_idx_[active_queue_]] = kTraceWarning;
    462     length_[active_queue_][next_free_idx_[active_queue_]] = strlen(warning_msg);
    463     memcpy(message_queue_[active_queue_][next_free_idx_[active_queue_]],
    464            warning_msg, strlen(warning_msg));
    465     next_free_idx_[active_queue_]++;
    466   }
    467 }
    468 
    469 bool TraceImpl::Run(void* obj) {
    470   return static_cast<TraceImpl*>(obj)->Process();
    471 }
    472 
    473 bool TraceImpl::Process() {
    474   if (event_.Wait(1000) == kEventSignaled) {
    475     // This slightly odd construction is to avoid locking |critsect_interface_|
    476     // while calling WriteToFile() since it's locked inside the function.
    477     critsect_interface_->Enter();
    478     bool write_to_file = trace_file_.Open() || callback_;
    479     critsect_interface_->Leave();
    480     if (write_to_file) {
    481       WriteToFile();
    482     }
    483   } else {
    484     CriticalSectionScoped lock(critsect_interface_);
    485     trace_file_.Flush();
    486   }
    487   return true;
    488 }
    489 
    490 void TraceImpl::WriteToFile() {
    491   uint8_t local_queue_active = 0;
    492   uint16_t local_next_free_idx = 0;
    493 
    494   // There are two buffers. One for reading (for writing to file) and one for
    495   // writing (for storing new messages). Let new messages be posted to the
    496   // unused buffer so that the current buffer can be flushed safely.
    497   {
    498     CriticalSectionScoped lock(critsect_array_);
    499     local_next_free_idx = next_free_idx_[active_queue_];
    500     next_free_idx_[active_queue_] = 0;
    501     local_queue_active = active_queue_;
    502     if (active_queue_ == 0) {
    503       active_queue_ = 1;
    504     } else {
    505       active_queue_ = 0;
    506     }
    507   }
    508   if (local_next_free_idx == 0) {
    509     return;
    510   }
    511 
    512   CriticalSectionScoped lock(critsect_interface_);
    513 
    514   for (uint16_t idx = 0; idx < local_next_free_idx; ++idx) {
    515     TraceLevel local_level = level_[local_queue_active][idx];
    516     if (callback_) {
    517       callback_->Print(local_level, message_queue_[local_queue_active][idx],
    518                        length_[local_queue_active][idx]);
    519     }
    520     if (trace_file_.Open()) {
    521       if (row_count_text_ > WEBRTC_TRACE_MAX_FILE_SIZE) {
    522         // wrap file
    523         row_count_text_ = 0;
    524         trace_file_.Flush();
    525 
    526         if (file_count_text_ == 0) {
    527           trace_file_.Rewind();
    528         } else {
    529           char old_file_name[FileWrapper::kMaxFileNameSize];
    530           char new_file_name[FileWrapper::kMaxFileNameSize];
    531 
    532           // get current name
    533           trace_file_.FileName(old_file_name,
    534                                FileWrapper::kMaxFileNameSize);
    535           trace_file_.CloseFile();
    536 
    537           file_count_text_++;
    538 
    539           UpdateFileName(old_file_name, new_file_name, file_count_text_);
    540 
    541           if (trace_file_.OpenFile(new_file_name, false, false,
    542                                    true) == -1) {
    543             return;
    544           }
    545         }
    546       }
    547       if (row_count_text_ ==  0) {
    548         char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
    549         int32_t length = AddDateTimeInfo(message);
    550         if (length != -1) {
    551           message[length] = 0;
    552           message[length - 1] = '\n';
    553           trace_file_.Write(message, length);
    554           row_count_text_++;
    555         }
    556         length = AddBuildInfo(message);
    557         if (length != -1) {
    558           message[length + 1] = 0;
    559           message[length] = '\n';
    560           message[length - 1] = '\n';
    561           trace_file_.Write(message, length + 1);
    562           row_count_text_++;
    563           row_count_text_++;
    564         }
    565       }
    566       uint16_t length = length_[local_queue_active][idx];
    567       message_queue_[local_queue_active][idx][length] = 0;
    568       message_queue_[local_queue_active][idx][length - 1] = '\n';
    569       trace_file_.Write(message_queue_[local_queue_active][idx], length);
    570       row_count_text_++;
    571     }
    572   }
    573 }
    574 
    575 void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module,
    576                         const int32_t id,
    577                         const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE]) {
    578   if (TraceCheck(level)) {
    579     char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
    580     char* message_ptr = trace_message;
    581 
    582     int32_t len = 0;
    583     int32_t ack_len = 0;
    584 
    585     len = AddLevel(message_ptr, level);
    586     if (len == -1) {
    587       return;
    588     }
    589     message_ptr += len;
    590     ack_len += len;
    591 
    592     len = AddTime(message_ptr, level);
    593     if (len == -1) {
    594       return;
    595     }
    596     message_ptr += len;
    597     ack_len += len;
    598 
    599     len = AddModuleAndId(message_ptr, module, id);
    600     if (len == -1) {
    601       return;
    602     }
    603     message_ptr += len;
    604     ack_len += len;
    605 
    606     len = AddThreadId(message_ptr);
    607     if (len < 0) {
    608       return;
    609     }
    610     message_ptr += len;
    611     ack_len += len;
    612 
    613     len = AddMessage(message_ptr, msg, (uint16_t)ack_len);
    614     if (len == -1) {
    615       return;
    616     }
    617     ack_len += len;
    618     AddMessageToList(trace_message, (uint16_t)ack_len, level);
    619 
    620     // Make sure that messages are written as soon as possible.
    621     event_.Set();
    622   }
    623 }
    624 
    625 bool TraceImpl::TraceCheck(const TraceLevel level) const {
    626   return (level & level_filter()) ? true : false;
    627 }
    628 
    629 bool TraceImpl::UpdateFileName(
    630     const char file_name_utf8[FileWrapper::kMaxFileNameSize],
    631     char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
    632     const uint32_t new_count) const {
    633   int32_t length = (int32_t)strlen(file_name_utf8);
    634   if (length < 0) {
    635     return false;
    636   }
    637 
    638   int32_t length_without_file_ending = length - 1;
    639   while (length_without_file_ending > 0) {
    640     if (file_name_utf8[length_without_file_ending] == '.') {
    641       break;
    642     } else {
    643       length_without_file_ending--;
    644     }
    645   }
    646   if (length_without_file_ending == 0) {
    647     length_without_file_ending = length;
    648   }
    649   int32_t length_to_ = length_without_file_ending - 1;
    650   while (length_to_ > 0) {
    651     if (file_name_utf8[length_to_] == '_') {
    652       break;
    653     } else {
    654       length_to_--;
    655     }
    656   }
    657 
    658   memcpy(file_name_with_counter_utf8, file_name_utf8, length_to_);
    659   sprintf(file_name_with_counter_utf8 + length_to_, "_%lu%s",
    660           static_cast<long unsigned int>(new_count),
    661           file_name_utf8 + length_without_file_ending);
    662   return true;
    663 }
    664 
    665 bool TraceImpl::CreateFileName(
    666     const char file_name_utf8[FileWrapper::kMaxFileNameSize],
    667     char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
    668     const uint32_t new_count) const {
    669   int32_t length = (int32_t)strlen(file_name_utf8);
    670   if (length < 0) {
    671     return false;
    672   }
    673 
    674   int32_t length_without_file_ending = length - 1;
    675   while (length_without_file_ending > 0) {
    676     if (file_name_utf8[length_without_file_ending] == '.') {
    677       break;
    678     } else {
    679       length_without_file_ending--;
    680     }
    681   }
    682   if (length_without_file_ending == 0) {
    683     length_without_file_ending = length;
    684   }
    685   memcpy(file_name_with_counter_utf8, file_name_utf8,
    686          length_without_file_ending);
    687   sprintf(file_name_with_counter_utf8 + length_without_file_ending, "_%lu%s",
    688           static_cast<long unsigned int>(new_count),
    689           file_name_utf8 + length_without_file_ending);
    690   return true;
    691 }
    692 
    693 void Trace::CreateTrace() {
    694   TraceImpl::StaticInstance(kAddRef);
    695 }
    696 
    697 void Trace::ReturnTrace() {
    698   TraceImpl::StaticInstance(kRelease);
    699 }
    700 
    701 int32_t Trace::TraceFile(char file_name[FileWrapper::kMaxFileNameSize]) {
    702   TraceImpl* trace = TraceImpl::GetTrace();
    703   if (trace) {
    704     int ret_val = trace->TraceFileImpl(file_name);
    705     ReturnTrace();
    706     return ret_val;
    707   }
    708   return -1;
    709 }
    710 
    711 int32_t Trace::SetTraceFile(const char* file_name,
    712                             const bool add_file_counter) {
    713   TraceImpl* trace = TraceImpl::GetTrace();
    714   if (trace) {
    715     int ret_val = trace->SetTraceFileImpl(file_name, add_file_counter);
    716     ReturnTrace();
    717     return ret_val;
    718   }
    719   return -1;
    720 }
    721 
    722 int32_t Trace::SetTraceCallback(TraceCallback* callback) {
    723   TraceImpl* trace = TraceImpl::GetTrace();
    724   if (trace) {
    725     int ret_val = trace->SetTraceCallbackImpl(callback);
    726     ReturnTrace();
    727     return ret_val;
    728   }
    729   return -1;
    730 }
    731 
    732 void Trace::Add(const TraceLevel level, const TraceModule module,
    733                 const int32_t id, const char* msg, ...) {
    734   TraceImpl* trace = TraceImpl::GetTrace(level);
    735   if (trace) {
    736     if (trace->TraceCheck(level)) {
    737       char temp_buff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
    738       char* buff = 0;
    739       if (msg) {
    740         va_list args;
    741         va_start(args, msg);
    742 #ifdef _WIN32
    743         _vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
    744 #else
    745         vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
    746 #endif
    747         va_end(args);
    748         buff = temp_buff;
    749       }
    750       trace->AddImpl(level, module, id, buff);
    751     }
    752     ReturnTrace();
    753   }
    754 }
    755 
    756 }  // namespace webrtc
    757