1*14675a02SAndroid Build Coastguard Worker // Copyright 2020 Google LLC
2*14675a02SAndroid Build Coastguard Worker //
3*14675a02SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*14675a02SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*14675a02SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*14675a02SAndroid Build Coastguard Worker //
7*14675a02SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*14675a02SAndroid Build Coastguard Worker //
9*14675a02SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*14675a02SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*14675a02SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*14675a02SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*14675a02SAndroid Build Coastguard Worker // limitations under the License.
14*14675a02SAndroid Build Coastguard Worker
15*14675a02SAndroid Build Coastguard Worker #ifndef FCP_TRACING_TRACING_SPAN_H_
16*14675a02SAndroid Build Coastguard Worker #define FCP_TRACING_TRACING_SPAN_H_
17*14675a02SAndroid Build Coastguard Worker
18*14675a02SAndroid Build Coastguard Worker #include <memory>
19*14675a02SAndroid Build Coastguard Worker #include <string>
20*14675a02SAndroid Build Coastguard Worker #include <utility>
21*14675a02SAndroid Build Coastguard Worker
22*14675a02SAndroid Build Coastguard Worker #include "fcp/base/error.h"
23*14675a02SAndroid Build Coastguard Worker #include "fcp/tracing/tracing_recorder_impl.h"
24*14675a02SAndroid Build Coastguard Worker #include "fcp/tracing/tracing_span_impl.h"
25*14675a02SAndroid Build Coastguard Worker #include "fcp/tracing/tracing_span_ref.h"
26*14675a02SAndroid Build Coastguard Worker #include "fcp/tracing/tracing_traits.h"
27*14675a02SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
28*14675a02SAndroid Build Coastguard Worker
29*14675a02SAndroid Build Coastguard Worker namespace fcp {
30*14675a02SAndroid Build Coastguard Worker
31*14675a02SAndroid Build Coastguard Worker namespace tracing_internal {
32*14675a02SAndroid Build Coastguard Worker
33*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable>
AssertIsNotSpan()34*14675a02SAndroid Build Coastguard Worker void AssertIsNotSpan() {
35*14675a02SAndroid Build Coastguard Worker static_assert(TracingTraits<FlatBufferTable>::kIsSpan == false,
36*14675a02SAndroid Build Coastguard Worker "Trace can only be called on an event table, not a span. To "
37*14675a02SAndroid Build Coastguard Worker "convert the table to an event remove 'span' from the table "
38*14675a02SAndroid Build Coastguard Worker "attributes.");
39*14675a02SAndroid Build Coastguard Worker }
40*14675a02SAndroid Build Coastguard Worker
41*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable>
AssertIsError()42*14675a02SAndroid Build Coastguard Worker void AssertIsError() {
43*14675a02SAndroid Build Coastguard Worker static_assert(
44*14675a02SAndroid Build Coastguard Worker TracingTraits<FlatBufferTable>::kSeverity == TracingSeverity::kError,
45*14675a02SAndroid Build Coastguard Worker "TraceError can only be called on table of severity Error. To "
46*14675a02SAndroid Build Coastguard Worker "convert the table to error severity add 'error' to the "
47*14675a02SAndroid Build Coastguard Worker "table attributes.");
48*14675a02SAndroid Build Coastguard Worker }
49*14675a02SAndroid Build Coastguard Worker
50*14675a02SAndroid Build Coastguard Worker // Generic method to build FlatBuff tables from a set of args.
51*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable, class... Arg>
BuildFlatBuffer(Arg &&...args)52*14675a02SAndroid Build Coastguard Worker flatbuffers::DetachedBuffer BuildFlatBuffer(Arg&&... args) {
53*14675a02SAndroid Build Coastguard Worker flatbuffers::FlatBufferBuilder fbb;
54*14675a02SAndroid Build Coastguard Worker flatbuffers::Offset<FlatBufferTable> root =
55*14675a02SAndroid Build Coastguard Worker TracingTraits<FlatBufferTable>::Create(std::forward<Arg>(args)..., &fbb);
56*14675a02SAndroid Build Coastguard Worker constexpr TracingTag tag = TracingTraits<FlatBufferTable>::kTag;
57*14675a02SAndroid Build Coastguard Worker constexpr char signature[5] = {tag.data[0], tag.data[1], tag.data[2],
58*14675a02SAndroid Build Coastguard Worker tag.data[3], 0};
59*14675a02SAndroid Build Coastguard Worker fbb.Finish(root, signature);
60*14675a02SAndroid Build Coastguard Worker return fbb.Release();
61*14675a02SAndroid Build Coastguard Worker }
62*14675a02SAndroid Build Coastguard Worker
63*14675a02SAndroid Build Coastguard Worker /*
64*14675a02SAndroid Build Coastguard Worker * Un-templatized version of the tracing span which stores the raw
65*14675a02SAndroid Build Coastguard Worker * definition of the tracing span and returns a reference to it.
66*14675a02SAndroid Build Coastguard Worker *
67*14675a02SAndroid Build Coastguard Worker * This class should not/cannot be publicly initialized, instead it should be
68*14675a02SAndroid Build Coastguard Worker * used as a base class for both UnscopedTracingSpan and TracingSpan.
69*14675a02SAndroid Build Coastguard Worker *
70*14675a02SAndroid Build Coastguard Worker * For Java based tracing spans, all native spans will be cast to this common
71*14675a02SAndroid Build Coastguard Worker * structure to pass along the JNI boundary.
72*14675a02SAndroid Build Coastguard Worker */
73*14675a02SAndroid Build Coastguard Worker class TracingSpanBase {
74*14675a02SAndroid Build Coastguard Worker public:
75*14675a02SAndroid Build Coastguard Worker // Returns a reference to this span.
Ref()76*14675a02SAndroid Build Coastguard Worker inline TracingSpanRef Ref() const { return impl_->Ref(); }
77*14675a02SAndroid Build Coastguard Worker virtual ~TracingSpanBase() = default;
78*14675a02SAndroid Build Coastguard Worker
79*14675a02SAndroid Build Coastguard Worker protected:
80*14675a02SAndroid Build Coastguard Worker explicit TracingSpanBase() = default;
81*14675a02SAndroid Build Coastguard Worker // Set by the child classes after an instance of TracingSpanImpl is created
82*14675a02SAndroid Build Coastguard Worker // from the flatbuf definitions.
83*14675a02SAndroid Build Coastguard Worker std::unique_ptr<TracingSpanImpl> impl_;
84*14675a02SAndroid Build Coastguard Worker };
85*14675a02SAndroid Build Coastguard Worker
86*14675a02SAndroid Build Coastguard Worker } // namespace tracing_internal
87*14675a02SAndroid Build Coastguard Worker
88*14675a02SAndroid Build Coastguard Worker // Unscoped tracing span carries tracing context for some logical activity.
89*14675a02SAndroid Build Coastguard Worker // The primary purpose of this class is to keep the tracing context of a
90*14675a02SAndroid Build Coastguard Worker // long-running asynchronous activity, typically associated with the lifetime of
91*14675a02SAndroid Build Coastguard Worker // some long-lived object.
92*14675a02SAndroid Build Coastguard Worker //
93*14675a02SAndroid Build Coastguard Worker // This span is not scoped to a block/function and need not necessarily be
94*14675a02SAndroid Build Coastguard Worker // instantiated as a local variable on the stack. It is OK to initialise this
95*14675a02SAndroid Build Coastguard Worker // span on a heap and/or as a field member of a class. For scoped variant,
96*14675a02SAndroid Build Coastguard Worker // prefer using TracingSpan instead.
97*14675a02SAndroid Build Coastguard Worker //
98*14675a02SAndroid Build Coastguard Worker // To record a Trace within an UnscopedTracingSpan, the caller must explicitly
99*14675a02SAndroid Build Coastguard Worker // pass a reference to a span e.g Trace<FlatBuff>(span, args...).
100*14675a02SAndroid Build Coastguard Worker //
101*14675a02SAndroid Build Coastguard Worker // The class is NOT thread-safe, but OK to use from different threads if invoked
102*14675a02SAndroid Build Coastguard Worker // sequentially (i.e. with external synchronisation providing sequential
103*14675a02SAndroid Build Coastguard Worker // consistency memory ordering).
104*14675a02SAndroid Build Coastguard Worker //
105*14675a02SAndroid Build Coastguard Worker // Recommended usage is to create new child span for every sub-activity or
106*14675a02SAndroid Build Coastguard Worker // operation.
107*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable>
108*14675a02SAndroid Build Coastguard Worker class UnscopedTracingSpan : public tracing_internal::TracingSpanBase {
109*14675a02SAndroid Build Coastguard Worker public:
110*14675a02SAndroid Build Coastguard Worker // UnscopedTracingSpan is neither copyable nor movable.
111*14675a02SAndroid Build Coastguard Worker UnscopedTracingSpan(const UnscopedTracingSpan&) = delete;
112*14675a02SAndroid Build Coastguard Worker UnscopedTracingSpan& operator=(const UnscopedTracingSpan&) = delete;
113*14675a02SAndroid Build Coastguard Worker // Public constructors allow creating new tracing span.
114*14675a02SAndroid Build Coastguard Worker // A parent span reference can be optionally provided as a first argument.
115*14675a02SAndroid Build Coastguard Worker // By default current span is used as a parent.
116*14675a02SAndroid Build Coastguard Worker template <class... Arg>
117*14675a02SAndroid Build Coastguard Worker explicit UnscopedTracingSpan(Arg&&... args);
118*14675a02SAndroid Build Coastguard Worker template <class... Arg>
119*14675a02SAndroid Build Coastguard Worker explicit UnscopedTracingSpan(TracingSpanRef parent, Arg&&... args);
120*14675a02SAndroid Build Coastguard Worker
121*14675a02SAndroid Build Coastguard Worker private:
122*14675a02SAndroid Build Coastguard Worker template <class... Arg>
123*14675a02SAndroid Build Coastguard Worker void Create(TracingSpanRef parent, Arg&&... args);
124*14675a02SAndroid Build Coastguard Worker };
125*14675a02SAndroid Build Coastguard Worker
126*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable>
127*14675a02SAndroid Build Coastguard Worker template <class... Arg>
UnscopedTracingSpan(Arg &&...args)128*14675a02SAndroid Build Coastguard Worker UnscopedTracingSpan<FlatBufferTable>::UnscopedTracingSpan(Arg&&... args) {
129*14675a02SAndroid Build Coastguard Worker Create(TracingSpanRef::Top(), std::forward<Arg>(args)...);
130*14675a02SAndroid Build Coastguard Worker }
131*14675a02SAndroid Build Coastguard Worker
132*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable>
133*14675a02SAndroid Build Coastguard Worker template <class... Arg>
UnscopedTracingSpan(TracingSpanRef parent,Arg &&...args)134*14675a02SAndroid Build Coastguard Worker UnscopedTracingSpan<FlatBufferTable>::UnscopedTracingSpan(TracingSpanRef parent,
135*14675a02SAndroid Build Coastguard Worker Arg&&... args) {
136*14675a02SAndroid Build Coastguard Worker Create(parent, std::forward<Arg>(args)...);
137*14675a02SAndroid Build Coastguard Worker }
138*14675a02SAndroid Build Coastguard Worker
139*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable>
140*14675a02SAndroid Build Coastguard Worker template <class... Arg>
Create(TracingSpanRef parent,Arg &&...args)141*14675a02SAndroid Build Coastguard Worker void UnscopedTracingSpan<FlatBufferTable>::Create(TracingSpanRef parent,
142*14675a02SAndroid Build Coastguard Worker Arg&&... args) {
143*14675a02SAndroid Build Coastguard Worker static_assert(
144*14675a02SAndroid Build Coastguard Worker TracingTraits<FlatBufferTable>::kIsSpan == true,
145*14675a02SAndroid Build Coastguard Worker "UnscopedTracingSpan can only be created from a span table, not "
146*14675a02SAndroid Build Coastguard Worker "an event. To convert the table to an span add 'span' "
147*14675a02SAndroid Build Coastguard Worker "to the table attributes.");
148*14675a02SAndroid Build Coastguard Worker flatbuffers::DetachedBuffer trace_data =
149*14675a02SAndroid Build Coastguard Worker tracing_internal::BuildFlatBuffer<FlatBufferTable>(
150*14675a02SAndroid Build Coastguard Worker std::forward<Arg>(args)...);
151*14675a02SAndroid Build Coastguard Worker impl_ = parent.recorder()->CreateChildSpan(parent.span_id(),
152*14675a02SAndroid Build Coastguard Worker std::move(trace_data),
153*14675a02SAndroid Build Coastguard Worker TracingTraits<FlatBufferTable>());
154*14675a02SAndroid Build Coastguard Worker }
155*14675a02SAndroid Build Coastguard Worker
156*14675a02SAndroid Build Coastguard Worker // Tracing span, carrying abstract tracing context for some logical activity
157*14675a02SAndroid Build Coastguard Worker // performed by the application. Provides ability to log various events
158*14675a02SAndroid Build Coastguard Worker // which are automatically associated with such a context, thus allowing logging
159*14675a02SAndroid Build Coastguard Worker // essential information only.
160*14675a02SAndroid Build Coastguard Worker //
161*14675a02SAndroid Build Coastguard Worker // This class uses RAII-style mechanism of entering/existing the tracing span
162*14675a02SAndroid Build Coastguard Worker // for the duration of a scoped block or a function, this class must be
163*14675a02SAndroid Build Coastguard Worker // instantiated as a local variable on the stack, in a similar manner as
164*14675a02SAndroid Build Coastguard Worker // std::lock_guard.
165*14675a02SAndroid Build Coastguard Worker //
166*14675a02SAndroid Build Coastguard Worker // The class is NOT thread-safe, but OK to use from different threads if invoked
167*14675a02SAndroid Build Coastguard Worker // sequentially (i.e. with external synchronisation providing sequential
168*14675a02SAndroid Build Coastguard Worker // consistency memory ordering).
169*14675a02SAndroid Build Coastguard Worker //
170*14675a02SAndroid Build Coastguard Worker // Recommended usage is to create new child span for every sub-activity or
171*14675a02SAndroid Build Coastguard Worker // operation.
172*14675a02SAndroid Build Coastguard Worker //
173*14675a02SAndroid Build Coastguard Worker // For a more general variant that is not necessarily tied to a scoped block,
174*14675a02SAndroid Build Coastguard Worker // prefer using UnscopedTracingSpan directly.
175*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable>
176*14675a02SAndroid Build Coastguard Worker class TracingSpan final : public UnscopedTracingSpan<FlatBufferTable> {
177*14675a02SAndroid Build Coastguard Worker public:
178*14675a02SAndroid Build Coastguard Worker // Since this manipulates TLS/FLS in RAII fashion, this is intended to be
179*14675a02SAndroid Build Coastguard Worker // used as a stack local (no heap alloc allowed):
180*14675a02SAndroid Build Coastguard Worker void* operator new(std::size_t) = delete;
181*14675a02SAndroid Build Coastguard Worker void* operator new[](std::size_t) = delete;
182*14675a02SAndroid Build Coastguard Worker // Public constructors allow creating new tracing span.
183*14675a02SAndroid Build Coastguard Worker template <class... Arg>
TracingSpan(Arg &&...args)184*14675a02SAndroid Build Coastguard Worker explicit TracingSpan(Arg&&... args)
185*14675a02SAndroid Build Coastguard Worker : UnscopedTracingSpan<FlatBufferTable>(std::forward<Arg>(args)...) {
186*14675a02SAndroid Build Coastguard Worker UnscopedTracingSpan<FlatBufferTable>::impl_->Push();
187*14675a02SAndroid Build Coastguard Worker }
188*14675a02SAndroid Build Coastguard Worker template <class... Arg>
TracingSpan(TracingSpanRef parent,Arg &&...args)189*14675a02SAndroid Build Coastguard Worker explicit TracingSpan(TracingSpanRef parent, Arg&&... args)
190*14675a02SAndroid Build Coastguard Worker : UnscopedTracingSpan<FlatBufferTable>(parent,
191*14675a02SAndroid Build Coastguard Worker std::forward<Arg>(args)...) {
192*14675a02SAndroid Build Coastguard Worker UnscopedTracingSpan<FlatBufferTable>::impl_->Push();
193*14675a02SAndroid Build Coastguard Worker }
194*14675a02SAndroid Build Coastguard Worker
195*14675a02SAndroid Build Coastguard Worker // Destructor closes the span
~TracingSpan()196*14675a02SAndroid Build Coastguard Worker ~TracingSpan() override {
197*14675a02SAndroid Build Coastguard Worker UnscopedTracingSpan<FlatBufferTable>::impl_->Pop();
198*14675a02SAndroid Build Coastguard Worker }
199*14675a02SAndroid Build Coastguard Worker };
200*14675a02SAndroid Build Coastguard Worker
201*14675a02SAndroid Build Coastguard Worker // Writes a trace with the specified args under the topmost span located on
202*14675a02SAndroid Build Coastguard Worker // TLS. If no span exists on TLS, then root span is fetched from the global
203*14675a02SAndroid Build Coastguard Worker // recorder.
204*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable, class... Arg>
Trace(Arg &&...args)205*14675a02SAndroid Build Coastguard Worker void Trace(Arg&&... args) {
206*14675a02SAndroid Build Coastguard Worker tracing_internal::AssertIsNotSpan<FlatBufferTable>();
207*14675a02SAndroid Build Coastguard Worker flatbuffers::DetachedBuffer trace_data =
208*14675a02SAndroid Build Coastguard Worker tracing_internal::BuildFlatBuffer<FlatBufferTable>(
209*14675a02SAndroid Build Coastguard Worker std::forward<Arg>(args)...);
210*14675a02SAndroid Build Coastguard Worker // Now discover what tracing span to log that with:
211*14675a02SAndroid Build Coastguard Worker tracing_internal::TracingSpanImpl* top =
212*14675a02SAndroid Build Coastguard Worker tracing_internal::TracingSpanImpl::Top();
213*14675a02SAndroid Build Coastguard Worker if (top != nullptr) {
214*14675a02SAndroid Build Coastguard Worker // Fast path: getting top tracing span from TLS/FCB:
215*14675a02SAndroid Build Coastguard Worker top->TraceImpl(std::move(trace_data), TracingTraits<FlatBufferTable>());
216*14675a02SAndroid Build Coastguard Worker } else {
217*14675a02SAndroid Build Coastguard Worker // Slow path, finding root span from global recorder. This
218*14675a02SAndroid Build Coastguard Worker // involves increasing its reference counter:
219*14675a02SAndroid Build Coastguard Worker std::shared_ptr<tracing_internal::TracingRecorderImpl> recorder =
220*14675a02SAndroid Build Coastguard Worker tracing_internal::TracingRecorderImpl::GetCurrent();
221*14675a02SAndroid Build Coastguard Worker recorder->GetRootSpan()->TraceImpl(std::move(trace_data),
222*14675a02SAndroid Build Coastguard Worker TracingTraits<FlatBufferTable>());
223*14675a02SAndroid Build Coastguard Worker // now, since we done with using root span, it is safe to release shared_ptr
224*14675a02SAndroid Build Coastguard Worker }
225*14675a02SAndroid Build Coastguard Worker }
226*14675a02SAndroid Build Coastguard Worker
227*14675a02SAndroid Build Coastguard Worker // Writes a trace under the specified span with the given args.
228*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable, class... Arg>
Trace(TracingSpanRef span,Arg &&...args)229*14675a02SAndroid Build Coastguard Worker void Trace(TracingSpanRef span, Arg&&... args) {
230*14675a02SAndroid Build Coastguard Worker tracing_internal::AssertIsNotSpan<FlatBufferTable>();
231*14675a02SAndroid Build Coastguard Worker flatbuffers::DetachedBuffer trace_data =
232*14675a02SAndroid Build Coastguard Worker tracing_internal::BuildFlatBuffer<FlatBufferTable>(
233*14675a02SAndroid Build Coastguard Worker std::forward<Arg>(args)...);
234*14675a02SAndroid Build Coastguard Worker span.recorder()->TraceImpl(span.span_id(), std::move(trace_data),
235*14675a02SAndroid Build Coastguard Worker TracingTraits<FlatBufferTable>());
236*14675a02SAndroid Build Coastguard Worker }
237*14675a02SAndroid Build Coastguard Worker
238*14675a02SAndroid Build Coastguard Worker // Writes an error trace with the specified args under the topmost span located
239*14675a02SAndroid Build Coastguard Worker // on TLS. If no span exists on TLS, then root span is fetched from the global
240*14675a02SAndroid Build Coastguard Worker // recorder.
241*14675a02SAndroid Build Coastguard Worker template <class FlatBufferTable, class... Arg>
TraceError(Arg &&...args)242*14675a02SAndroid Build Coastguard Worker ABSL_MUST_USE_RESULT Error TraceError(Arg&&... args) {
243*14675a02SAndroid Build Coastguard Worker tracing_internal::AssertIsError<FlatBufferTable>();
244*14675a02SAndroid Build Coastguard Worker Trace<FlatBufferTable>(args...);
245*14675a02SAndroid Build Coastguard Worker return Error(Error::ConstructorAccess{});
246*14675a02SAndroid Build Coastguard Worker }
247*14675a02SAndroid Build Coastguard Worker
248*14675a02SAndroid Build Coastguard Worker } // namespace fcp
249*14675a02SAndroid Build Coastguard Worker
250*14675a02SAndroid Build Coastguard Worker #endif // FCP_TRACING_TRACING_SPAN_H_
251