• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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".
StaticInstance(CountOperation count_operation,const TraceLevel level)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 
GetTrace(const TraceLevel level)55 TraceImpl* TraceImpl::GetTrace(const TraceLevel level) {
56   return StaticInstance(kAddRefNoCreate, level);
57 }
58 
CreateInstance()59 TraceImpl* TraceImpl::CreateInstance() {
60 #if defined(_WIN32)
61   return new TraceWindows();
62 #else
63   return new TracePosix();
64 #endif
65 }
66 
TraceImpl()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 
StopThread()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 
~TraceImpl()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 
AddThreadId(char * trace_message) const133 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 
AddLevel(char * sz_message,const TraceLevel level) const139 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 
AddModuleAndId(char * trace_message,const TraceModule module,const int32_t id) const188 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 
SetTraceFileImpl(const char * file_name_utf8,const bool add_file_counter)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 
TraceFileImpl(char file_name_utf8[FileWrapper::kMaxFileNameSize])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 
SetTraceCallbackImpl(TraceCallback * callback)375 int32_t TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) {
376   CriticalSectionScoped lock(critsect_interface_);
377   callback_ = callback;
378   return 0;
379 }
380 
AddMessage(char * trace_message,const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],const uint16_t written_so_far) const381 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 
AddMessageToList(const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],const uint16_t length,const TraceLevel level)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 
Run(void * obj)469 bool TraceImpl::Run(void* obj) {
470   return static_cast<TraceImpl*>(obj)->Process();
471 }
472 
Process()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 
WriteToFile()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 
AddImpl(const TraceLevel level,const TraceModule module,const int32_t id,const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE])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 
TraceCheck(const TraceLevel level) const625 bool TraceImpl::TraceCheck(const TraceLevel level) const {
626   return (level & level_filter()) ? true : false;
627 }
628 
UpdateFileName(const char file_name_utf8[FileWrapper::kMaxFileNameSize],char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],const uint32_t new_count) const629 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 
CreateFileName(const char file_name_utf8[FileWrapper::kMaxFileNameSize],char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],const uint32_t new_count) const665 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 
CreateTrace()693 void Trace::CreateTrace() {
694   TraceImpl::StaticInstance(kAddRef);
695 }
696 
ReturnTrace()697 void Trace::ReturnTrace() {
698   TraceImpl::StaticInstance(kRelease);
699 }
700 
TraceFile(char file_name[FileWrapper::kMaxFileNameSize])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 
SetTraceFile(const char * file_name,const bool add_file_counter)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 
SetTraceCallback(TraceCallback * callback)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 
Add(const TraceLevel level,const TraceModule module,const int32_t id,const char * msg,...)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