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