1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "util/trace_logging/scoped_trace_operations.h"
6
7 #include "absl/types/optional.h"
8 #include "platform/api/trace_logging_platform.h"
9 #include "platform/base/trace_logging_activation.h"
10 #include "util/osp_logging.h"
11
12 #if defined(ENABLE_TRACE_LOGGING)
13
14 namespace openscreen {
15 namespace internal {
16
17 // static
TraceAsyncEnd(const uint32_t line,const char * file,TraceId id,Error::Code e)18 bool ScopedTraceOperation::TraceAsyncEnd(const uint32_t line,
19 const char* file,
20 TraceId id,
21 Error::Code e) {
22 auto end_time = Clock::now();
23 const CurrentTracingDestination destination;
24 if (destination) {
25 destination->LogAsyncEnd(line, file, end_time, id, e);
26 return true;
27 }
28 return false;
29 }
30
ScopedTraceOperation(TraceId trace_id,TraceId parent_id,TraceId root_id)31 ScopedTraceOperation::ScopedTraceOperation(TraceId trace_id,
32 TraceId parent_id,
33 TraceId root_id) {
34 if (traces_ == nullptr) {
35 // Create the stack if it doesnt' exist.
36 traces_ = new TraceStack();
37
38 // Create a new root node. This will re-call this constructor and add the
39 // root node to the stack before proceeding with the original node.
40 root_node_ = new TraceIdSetter(TraceIdHierarchy::Empty());
41 OSP_DCHECK(!traces_->empty());
42 }
43
44 // Setting trace id fields.
45 root_id_ = root_id != kUnsetTraceId ? root_id : traces_->top()->root_id_;
46 parent_id_ =
47 parent_id != kUnsetTraceId ? parent_id : traces_->top()->trace_id_;
48 trace_id_ =
49 trace_id != kUnsetTraceId ? trace_id : trace_id_counter_.fetch_add(1);
50
51 // Add this item to the stack.
52 traces_->push(this);
53 OSP_DCHECK(traces_->size() < 1024);
54 }
55
~ScopedTraceOperation()56 ScopedTraceOperation::~ScopedTraceOperation() {
57 OSP_CHECK(traces_ != nullptr && !traces_->empty());
58 OSP_CHECK_EQ(traces_->top(), this);
59 traces_->pop();
60
61 // If there's only one item left, it must be the root node. Deleting the root
62 // node will re-call this destructor and delete the traces_ stack.
63 if (traces_->size() == 1) {
64 OSP_CHECK_EQ(traces_->top(), root_node_);
65 delete root_node_;
66 root_node_ = nullptr;
67 } else if (traces_->empty()) {
68 delete traces_;
69 traces_ = nullptr;
70 }
71 }
72
73 // static
74 thread_local ScopedTraceOperation::TraceStack* ScopedTraceOperation::traces_ =
75 nullptr;
76
77 // static
78 thread_local ScopedTraceOperation* ScopedTraceOperation::root_node_ = nullptr;
79
80 // static
81 std::atomic<std::uint64_t> ScopedTraceOperation::trace_id_counter_{
82 uint64_t{0x01} << (sizeof(TraceId) * 8 - 1)};
83
TraceLoggerBase(TraceCategory::Value category,const char * name,const char * file,uint32_t line,TraceId current,TraceId parent,TraceId root)84 TraceLoggerBase::TraceLoggerBase(TraceCategory::Value category,
85 const char* name,
86 const char* file,
87 uint32_t line,
88 TraceId current,
89 TraceId parent,
90 TraceId root)
91 : ScopedTraceOperation(current, parent, root),
92 start_time_(Clock::now()),
93 result_(Error::Code::kNone),
94 name_(name),
95 file_name_(file),
96 line_number_(line),
97 category_(category) {}
98
TraceLoggerBase(TraceCategory::Value category,const char * name,const char * file,uint32_t line,TraceIdHierarchy ids)99 TraceLoggerBase::TraceLoggerBase(TraceCategory::Value category,
100 const char* name,
101 const char* file,
102 uint32_t line,
103 TraceIdHierarchy ids)
104 : TraceLoggerBase(category,
105 name,
106 file,
107 line,
108 ids.current,
109 ids.parent,
110 ids.root) {}
111
~SynchronousTraceLogger()112 SynchronousTraceLogger::~SynchronousTraceLogger() {
113 const CurrentTracingDestination destination;
114 if (destination) {
115 auto end_time = Clock::now();
116 destination->LogTrace(this->name_, this->line_number_, this->file_name_,
117 this->start_time_, end_time, this->to_hierarchy(),
118 this->result_);
119 }
120 }
121
~AsynchronousTraceLogger()122 AsynchronousTraceLogger::~AsynchronousTraceLogger() {
123 const CurrentTracingDestination destination;
124 if (destination) {
125 destination->LogAsyncStart(this->name_, this->line_number_,
126 this->file_name_, this->start_time_,
127 this->to_hierarchy());
128 }
129 }
130
131 TraceIdSetter::~TraceIdSetter() = default;
132
133 } // namespace internal
134 } // namespace openscreen
135
136 #endif // defined(ENABLE_TRACE_LOGGING)
137