blob: c1ec984f6d30d234236934438e4d2eced7843edc [file] [log] [blame]
Fredrik Solenberg729b9102017-10-03 13:39:39 +00001/*
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 "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#include "rtc_base/atomicops.h"
19#include "rtc_base/platform_thread.h"
20#ifdef _WIN32
21#include "system_wrappers/source/trace_win.h"
22#else
23#include "system_wrappers/source/trace_posix.h"
24#endif // _WIN32
25
26#define KEY_LEN_CHARS 31
27
28#ifdef _WIN32
29#pragma warning(disable:4355)
30#endif // _WIN32
31
32namespace webrtc {
33
34const int Trace::kBoilerplateLength = 71;
35const int Trace::kTimestampPosition = 13;
36const int Trace::kTimestampLength = 12;
37volatile int Trace::level_filter_ = kTraceDefault;
38
39// Construct On First Use idiom. Avoids "static initialization order fiasco".
40TraceImpl* 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
55TraceImpl* TraceImpl::GetTrace(const TraceLevel level) {
56 return StaticInstance(kAddRefNoCreate, level);
57}
58
59TraceImpl* TraceImpl::CreateInstance() {
60#if defined(_WIN32)
61 return new TraceWindows();
62#else
63 return new TracePosix();
64#endif
65}
66
67TraceImpl::TraceImpl()
68 : callback_(NULL),
69 row_count_text_(0),
70 file_count_text_(0),
71 trace_file_(FileWrapper::Create()) {
72}
73
74TraceImpl::~TraceImpl() {
75 trace_file_->CloseFile();
76}
77
78int32_t TraceImpl::AddThreadId(char* trace_message) const {
79 uint32_t thread_id = rtc::CurrentThreadId();
80 // Messages is 12 characters.
81 return sprintf(trace_message, "%10u; ", thread_id);
82}
83
84int32_t TraceImpl::AddLevel(char* sz_message, const TraceLevel level) const {
85 const int kMessageLength = 12;
86 switch (level) {
87 case kTraceTerseInfo:
88 // Add the appropriate amount of whitespace.
89 memset(sz_message, ' ', kMessageLength);
90 sz_message[kMessageLength] = '\0';
91 break;
92 case kTraceStateInfo:
93 sprintf(sz_message, "STATEINFO ; ");
94 break;
95 case kTraceWarning:
96 sprintf(sz_message, "WARNING ; ");
97 break;
98 case kTraceError:
99 sprintf(sz_message, "ERROR ; ");
100 break;
101 case kTraceCritical:
102 sprintf(sz_message, "CRITICAL ; ");
103 break;
104 case kTraceInfo:
105 sprintf(sz_message, "DEBUGINFO ; ");
106 break;
107 case kTraceModuleCall:
108 sprintf(sz_message, "MODULECALL; ");
109 break;
110 case kTraceMemory:
111 sprintf(sz_message, "MEMORY ; ");
112 break;
113 case kTraceTimer:
114 sprintf(sz_message, "TIMER ; ");
115 break;
116 case kTraceStream:
117 sprintf(sz_message, "STREAM ; ");
118 break;
119 case kTraceApiCall:
120 sprintf(sz_message, "APICALL ; ");
121 break;
122 case kTraceDebug:
123 sprintf(sz_message, "DEBUG ; ");
124 break;
125 default:
126 assert(false);
127 return 0;
128 }
129 // All messages are 12 characters.
130 return kMessageLength;
131}
132
133int32_t TraceImpl::AddModuleAndId(char* trace_message,
134 const TraceModule module,
135 const int32_t id) const {
136 // Use long int to prevent problems with different definitions of
137 // int32_t.
138 // TODO(hellner): is this actually a problem? If so, it should be better to
139 // clean up int32_t
140 const long int idl = id;
141 const int kMessageLength = 25;
142 if (idl != -1) {
143 const unsigned long int id_engine = id >> 16;
144 const unsigned long int id_channel = id & 0xffff;
145
146 switch (module) {
147 case kTraceUndefined:
148 // Add the appropriate amount of whitespace.
149 memset(trace_message, ' ', kMessageLength);
150 trace_message[kMessageLength] = '\0';
151 break;
152 case kTraceVoice:
153 sprintf(trace_message, " VOICE:%5ld %5ld;", id_engine,
154 id_channel);
155 break;
156 case kTraceVideo:
157 sprintf(trace_message, " VIDEO:%5ld %5ld;", id_engine,
158 id_channel);
159 break;
160 case kTraceUtility:
161 sprintf(trace_message, " UTILITY:%5ld %5ld;", id_engine,
162 id_channel);
163 break;
164 case kTraceRtpRtcp:
165 sprintf(trace_message, " RTP/RTCP:%5ld %5ld;", id_engine,
166 id_channel);
167 break;
168 case kTraceTransport:
169 sprintf(trace_message, " TRANSPORT:%5ld %5ld;", id_engine,
170 id_channel);
171 break;
172 case kTraceAudioCoding:
173 sprintf(trace_message, "AUDIO CODING:%5ld %5ld;", id_engine,
174 id_channel);
175 break;
176 case kTraceSrtp:
177 sprintf(trace_message, " SRTP:%5ld %5ld;", id_engine,
178 id_channel);
179 break;
180 case kTraceAudioMixerServer:
181 sprintf(trace_message, " AUDIO MIX/S:%5ld %5ld;", id_engine,
182 id_channel);
183 break;
184 case kTraceAudioMixerClient:
185 sprintf(trace_message, " AUDIO MIX/C:%5ld %5ld;", id_engine,
186 id_channel);
187 break;
188 case kTraceVideoCoding:
189 sprintf(trace_message, "VIDEO CODING:%5ld %5ld;", id_engine,
190 id_channel);
191 break;
192 case kTraceVideoMixer:
193 // Print sleep time and API call
194 sprintf(trace_message, " VIDEO MIX:%5ld %5ld;", id_engine,
195 id_channel);
196 break;
197 case kTraceFile:
198 sprintf(trace_message, " FILE:%5ld %5ld;", id_engine,
199 id_channel);
200 break;
201 case kTraceAudioProcessing:
202 sprintf(trace_message, " AUDIO PROC:%5ld %5ld;", id_engine,
203 id_channel);
204 break;
205 case kTraceAudioDevice:
206 sprintf(trace_message, "AUDIO DEVICE:%5ld %5ld;", id_engine,
207 id_channel);
208 break;
209 case kTraceVideoRenderer:
210 sprintf(trace_message, "VIDEO RENDER:%5ld %5ld;", id_engine,
211 id_channel);
212 break;
213 case kTraceVideoCapture:
214 sprintf(trace_message, "VIDEO CAPTUR:%5ld %5ld;", id_engine,
215 id_channel);
216 break;
217 case kTraceRemoteBitrateEstimator:
218 sprintf(trace_message, " BWE RBE:%5ld %5ld;", id_engine,
219 id_channel);
220 break;
221 }
222 } else {
223 switch (module) {
224 case kTraceUndefined:
225 // Add the appropriate amount of whitespace.
226 memset(trace_message, ' ', kMessageLength);
227 trace_message[kMessageLength] = '\0';
228 break;
229 case kTraceVoice:
230 sprintf(trace_message, " VOICE:%11ld;", idl);
231 break;
232 case kTraceVideo:
233 sprintf(trace_message, " VIDEO:%11ld;", idl);
234 break;
235 case kTraceUtility:
236 sprintf(trace_message, " UTILITY:%11ld;", idl);
237 break;
238 case kTraceRtpRtcp:
239 sprintf(trace_message, " RTP/RTCP:%11ld;", idl);
240 break;
241 case kTraceTransport:
242 sprintf(trace_message, " TRANSPORT:%11ld;", idl);
243 break;
244 case kTraceAudioCoding:
245 sprintf(trace_message, "AUDIO CODING:%11ld;", idl);
246 break;
247 case kTraceSrtp:
248 sprintf(trace_message, " SRTP:%11ld;", idl);
249 break;
250 case kTraceAudioMixerServer:
251 sprintf(trace_message, " AUDIO MIX/S:%11ld;", idl);
252 break;
253 case kTraceAudioMixerClient:
254 sprintf(trace_message, " AUDIO MIX/C:%11ld;", idl);
255 break;
256 case kTraceVideoCoding:
257 sprintf(trace_message, "VIDEO CODING:%11ld;", idl);
258 break;
259 case kTraceVideoMixer:
260 sprintf(trace_message, " VIDEO MIX:%11ld;", idl);
261 break;
262 case kTraceFile:
263 sprintf(trace_message, " FILE:%11ld;", idl);
264 break;
265 case kTraceAudioProcessing:
266 sprintf(trace_message, " AUDIO PROC:%11ld;", idl);
267 break;
268 case kTraceAudioDevice:
269 sprintf(trace_message, "AUDIO DEVICE:%11ld;", idl);
270 break;
271 case kTraceVideoRenderer:
272 sprintf(trace_message, "VIDEO RENDER:%11ld;", idl);
273 break;
274 case kTraceVideoCapture:
275 sprintf(trace_message, "VIDEO CAPTUR:%11ld;", idl);
276 break;
277 case kTraceRemoteBitrateEstimator:
278 sprintf(trace_message, " BWE RBE:%11ld;", idl);
279 break;
280 }
281 }
282 return kMessageLength;
283}
284
285int32_t TraceImpl::SetTraceFileImpl(const char* file_name_utf8,
286 const bool add_file_counter) {
287 rtc::CritScope lock(&crit_);
288
289 trace_file_->CloseFile();
290 trace_file_path_.clear();
291
292 if (file_name_utf8) {
293 if (add_file_counter) {
294 file_count_text_ = 1;
295
296 char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize];
297 CreateFileName(file_name_utf8, file_name_with_counter_utf8,
298 file_count_text_);
299 if (!trace_file_->OpenFile(file_name_with_counter_utf8, false)) {
300 return -1;
301 }
302 trace_file_path_ = file_name_with_counter_utf8;
303 } else {
304 file_count_text_ = 0;
305 if (!trace_file_->OpenFile(file_name_utf8, false)) {
306 return -1;
307 }
308 trace_file_path_ = file_name_utf8;
309 }
310 }
311 row_count_text_ = 0;
312 return 0;
313}
314
315int32_t TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) {
316 rtc::CritScope lock(&crit_);
317 callback_ = callback;
318 return 0;
319}
320
321int32_t TraceImpl::AddMessage(
322 char* trace_message,
323 const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
324 const uint16_t written_so_far) const {
325 int length = 0;
326 if (written_so_far >= WEBRTC_TRACE_MAX_MESSAGE_SIZE) {
327 return -1;
328 }
329 // - 2 to leave room for newline and NULL termination.
330#ifdef _WIN32
331 length = _snprintf(trace_message,
332 WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
333 "%s", msg);
334 if (length < 0) {
335 length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
336 trace_message[length] = 0;
337 }
338#else
339 length = snprintf(trace_message,
340 WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
341 "%s", msg);
342 if (length < 0 ||
343 length > WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2) {
344 length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
345 trace_message[length] = 0;
346 }
347#endif
348 // Length with NULL termination.
349 return length + 1;
350}
351
352void TraceImpl::AddMessageToList(
353 const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
354 const uint16_t length,
355 const TraceLevel level) {
356 rtc::CritScope lock(&crit_);
357 if (callback_)
358 callback_->Print(level, trace_message, length);
359 WriteToFile(trace_message, length);
360}
361
362void TraceImpl::WriteToFile(const char* msg, uint16_t length) {
363 if (!trace_file_->is_open())
364 return;
365
366 if (row_count_text_ > WEBRTC_TRACE_MAX_FILE_SIZE) {
367 // wrap file
368 row_count_text_ = 0;
369 trace_file_->Flush();
370
371 if (file_count_text_ == 0) {
372 trace_file_->Rewind();
373 } else {
374 char new_file_name[FileWrapper::kMaxFileNameSize];
375
376 // get current name
377 file_count_text_++;
378 UpdateFileName(new_file_name, file_count_text_);
379
380 trace_file_->CloseFile();
381 trace_file_path_.clear();
382
383 if (!trace_file_->OpenFile(new_file_name, false)) {
384 return;
385 }
386 trace_file_path_ = new_file_name;
387 }
388 }
389 if (row_count_text_ == 0) {
390 char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
391 int32_t length = AddDateTimeInfo(message);
392 if (length != -1) {
393 message[length] = 0;
394 message[length - 1] = '\n';
395 trace_file_->Write(message, length);
396 row_count_text_++;
397 }
398 }
399
400 char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
401 memcpy(trace_message, msg, length);
402 trace_message[length] = 0;
403 trace_message[length - 1] = '\n';
404 trace_file_->Write(trace_message, length);
405 row_count_text_++;
406}
407
408void TraceImpl::AddImpl(const TraceLevel level,
409 const TraceModule module,
410 const int32_t id,
411 const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE]) {
412 if (!TraceCheck(level))
413 return;
414
415 char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
416 char* message_ptr = &trace_message[0];
417 int32_t len = AddLevel(message_ptr, level);
418 if (len == -1)
419 return;
420
421 message_ptr += len;
422 int32_t ack_len = len;
423
424 len = AddTime(message_ptr, level);
425 if (len == -1)
426 return;
427
428 message_ptr += len;
429 ack_len += len;
430
431 len = AddModuleAndId(message_ptr, module, id);
432 if (len == -1)
433 return;
434
435 message_ptr += len;
436 ack_len += len;
437
438 len = AddThreadId(message_ptr);
439 if (len < 0)
440 return;
441
442 message_ptr += len;
443 ack_len += len;
444
445 len = AddMessage(message_ptr, msg, static_cast<uint16_t>(ack_len));
446 if (len == -1)
447 return;
448
449 ack_len += len;
450 AddMessageToList(trace_message, static_cast<uint16_t>(ack_len), level);
451}
452
453bool TraceImpl::TraceCheck(const TraceLevel level) const {
454 return (level & level_filter()) ? true : false;
455}
456
457bool TraceImpl::UpdateFileName(
458 char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
459 const uint32_t new_count) const {
460 int32_t length = static_cast<int32_t>(trace_file_path_.length());
461
462 int32_t length_without_file_ending = length - 1;
463 while (length_without_file_ending > 0) {
464 if (trace_file_path_[length_without_file_ending] == '.') {
465 break;
466 } else {
467 length_without_file_ending--;
468 }
469 }
470 if (length_without_file_ending == 0) {
471 length_without_file_ending = length;
472 }
473 int32_t length_to_ = length_without_file_ending - 1;
474 while (length_to_ > 0) {
475 if (trace_file_path_[length_to_] == '_') {
476 break;
477 } else {
478 length_to_--;
479 }
480 }
481
482 memcpy(file_name_with_counter_utf8, &trace_file_path_[0], length_to_);
483 sprintf(file_name_with_counter_utf8 + length_to_, "_%lu%s",
484 static_cast<long unsigned int>(new_count),
485 &trace_file_path_[length_without_file_ending]);
486 return true;
487}
488
489bool TraceImpl::CreateFileName(
490 const char file_name_utf8[FileWrapper::kMaxFileNameSize],
491 char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
492 const uint32_t new_count) const {
493 int32_t length = (int32_t)strlen(file_name_utf8);
494 if (length < 0) {
495 return false;
496 }
497
498 int32_t length_without_file_ending = length - 1;
499 while (length_without_file_ending > 0) {
500 if (file_name_utf8[length_without_file_ending] == '.') {
501 break;
502 } else {
503 length_without_file_ending--;
504 }
505 }
506 if (length_without_file_ending == 0) {
507 length_without_file_ending = length;
508 }
509 memcpy(file_name_with_counter_utf8, file_name_utf8,
510 length_without_file_ending);
511 sprintf(file_name_with_counter_utf8 + length_without_file_ending, "_%lu%s",
512 static_cast<long unsigned int>(new_count),
513 file_name_utf8 + length_without_file_ending);
514 return true;
515}
516
517// static
518void Trace::CreateTrace() {
519 TraceImpl::StaticInstance(kAddRef);
520}
521
522// static
523void Trace::ReturnTrace() {
524 TraceImpl::StaticInstance(kRelease);
525}
526
527// static
528void Trace::set_level_filter(int filter) {
529 rtc::AtomicOps::ReleaseStore(&level_filter_, filter);
530}
531
532// static
533int Trace::level_filter() {
534 return rtc::AtomicOps::AcquireLoad(&level_filter_);
535}
536
537// static
538int32_t Trace::SetTraceFile(const char* file_name,
539 const bool add_file_counter) {
540 TraceImpl* trace = TraceImpl::GetTrace();
541 if (trace) {
542 int ret_val = trace->SetTraceFileImpl(file_name, add_file_counter);
543 ReturnTrace();
544 return ret_val;
545 }
546 return -1;
547}
548
549int32_t Trace::SetTraceCallback(TraceCallback* callback) {
550 TraceImpl* trace = TraceImpl::GetTrace();
551 if (trace) {
552 int ret_val = trace->SetTraceCallbackImpl(callback);
553 ReturnTrace();
554 return ret_val;
555 }
556 return -1;
557}
558
559void Trace::Add(const TraceLevel level, const TraceModule module,
560 const int32_t id, const char* msg, ...) {
561 TraceImpl* trace = TraceImpl::GetTrace(level);
562 if (trace) {
563 if (trace->TraceCheck(level)) {
564 char temp_buff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
565 char* buff = 0;
566 if (msg) {
567 va_list args;
568 va_start(args, msg);
569#ifdef _WIN32
570 _vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
571#else
572 vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
573#endif
574 va_end(args);
575 buff = temp_buff;
576 }
577 trace->AddImpl(level, module, id, buff);
578 }
579 ReturnTrace();
580 }
581}
582
583} // namespace webrtc