Index: remoting/base/tracer.cc |
diff --git a/remoting/base/tracer.cc b/remoting/base/tracer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c9df2f0d30fa6a651f4ad2fcf4e62e320a57d681 |
--- /dev/null |
+++ b/remoting/base/tracer.cc |
@@ -0,0 +1,144 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "remoting/base/tracer.h" |
+ |
+#include <list> |
+ |
+#include "base/basictypes.h" |
+#include "base/condition_variable.h" |
+#include "base/message_loop.h" |
+#include "base/rand_util.h" |
+#include "base/ref_counted.h" |
+#include "base/stl_util-inl.h" |
+#include "base/thread.h" |
+#include "base/time.h" |
+ |
+namespace remoting { |
+ |
+namespace { |
+ |
+class OutputLogger { |
+ public: |
+ OutputLogger() |
+ : thread_("logging_thread"), |
+ stopped_(false), |
+ wake_(&lock_) { |
+ thread_.Start(); |
+ thread_.message_loop()->PostTask( |
+ FROM_HERE, |
+ NewRunnableMethod(this, &OutputLogger::PrintLogs)); |
+ } |
+ |
+ void OutputTrace(TraceBuffer* buffer) { |
+ scoped_ptr<TraceBuffer> buffer_ref_(buffer); |
+ AutoLock l(lock_); |
+ |
+ // Drop messages if we're overwhelming the logger. |
+ if (buffers_.size() < 10) { |
+ buffers_.push_front(buffer_ref_.release()); |
+ wake_.Signal(); |
+ } else { |
+ // TODO(ajwong): Remove this cause it just overwhelms the logging more. |
+ LOG(WARNING) << "Message dropped."; |
+ } |
+ } |
+ |
+ void LogOneTrace(TraceBuffer* buffer) { |
+ LOG(INFO) << "Trace: " << buffer->name(); |
+ base::Time last_timestamp; |
+ for (int i = 0; i < buffer->record_size(); ++i) { |
+ const TraceRecord& record = buffer->record(i); |
+ base::Time timestamp = base::Time::FromInternalValue(record.timestamp()); |
+ if (i == 0) { |
+ LOG(INFO) << " TS: " << record.timestamp() |
+ << " msg: " << record.annotation(); |
+ } else { |
+ base::TimeDelta delta = timestamp - last_timestamp; |
+ LOG(INFO) << " TS: " << record.timestamp() |
+ << " msg: " << record.annotation() |
+ << " [ " << delta.InMilliseconds() << "ms ]"; |
+ } |
+ last_timestamp = timestamp; |
+ } |
+ } |
+ |
+ void PrintLogs() { |
+ while(!stopped_) { |
+ TraceBuffer* buffer = NULL; |
+ { |
+ AutoLock l(lock_); |
+ if (buffers_.size() == 0) { |
+ wake_.Wait(); |
+ } |
+ // Check again since we might have woken for a stop signal. |
+ if (buffers_.size() != 0) { |
+ buffer = buffers_.back(); |
+ buffers_.pop_back(); |
+ } |
+ } |
+ |
+ if (buffer) { |
+ LogOneTrace(buffer); |
+ delete buffer; |
+ } |
+ } |
+ } |
+ |
+ private: |
+ friend struct DefaultSingletonTraits<OutputLogger>; |
+ |
+ ~OutputLogger() { |
+ { |
+ AutoLock l(lock_); |
+ stopped_ = true; |
+ wake_.Signal(); |
+ } |
+ |
+ thread_.Stop(); |
+ STLDeleteElements(&buffers_); |
+ } |
+ |
+ Lock lock_; |
+ base::Thread thread_; |
+ bool stopped_; |
+ ConditionVariable wake_; |
+ std::list<TraceBuffer*> buffers_; |
+}; |
+ |
+} // namespace |
+ |
+Tracer::Tracer(const std::string& name, double sample_percent) { |
+ if (sample_percent > base::RandDouble()) { |
+ buffer_.reset(new TraceBuffer()); |
+ buffer_->set_name(name); |
+ } |
+} |
+ |
+void Tracer::PrintString(const std::string& s) { |
+ AutoLock l(lock_); |
+ if (!buffer_.get()) { |
+ return; |
+ } |
+ |
+ TraceRecord* record = buffer_->add_record(); |
+ record->set_annotation(s); |
+ record->set_timestamp(base::Time::Now().ToInternalValue()); |
+ |
+ // Take the pointer for the current messageloop as identifying for the |
+ // current thread. |
+ record->set_thread_id(static_cast<uint64>(PlatformThread::CurrentId())); |
+} |
+ |
+Tracer::~Tracer() { |
+ AutoLock l(lock_); |
+ |
+ if (buffer_.get()) { |
+ Singleton<OutputLogger>::get()->OutputTrace(buffer_.release()); |
+ } |
+} |
+ |
+} // namespace remoting |
+ |
+DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::OutputLogger); |