blob: e88c89c0d59a51345fac6bca2829e6a89b189880 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_PERFETTO_TRACING_EVENT_CONTEXT_H_
#define INCLUDE_PERFETTO_TRACING_EVENT_CONTEXT_H_
#include "perfetto/protozero/message_handle.h"
#include "perfetto/tracing/internal/track_event_internal.h"
#include "perfetto/tracing/traced_proto.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
namespace perfetto {
namespace protos {
namespace pbzero {
class DebugAnnotation;
} // namespace pbzero
} // namespace protos
namespace internal {
class TrackEventInternal;
}
// Allows adding custom arguments into track events. Example:
//
// TRACE_EVENT_BEGIN("category", "Title",
// [](perfetto::EventContext ctx) {
// auto* log = ctx.event()->set_log_message();
// log->set_body_iid(1234);
//
// ctx.AddDebugAnnotation("name", 1234);
// });
//
class PERFETTO_EXPORT_COMPONENT EventContext {
public:
EventContext(EventContext&&) = default;
// For Chromium during the transition phase to the client library.
// TODO(eseckler): Remove once Chromium has switched to client lib entirely.
explicit EventContext(
protos::pbzero::TrackEvent* event,
internal::TrackEventIncrementalState* incremental_state = nullptr,
bool filter_debug_annotations = false)
: event_(event),
incremental_state_(incremental_state),
filter_debug_annotations_(filter_debug_annotations) {}
~EventContext();
internal::TrackEventIncrementalState* GetIncrementalState() const {
return incremental_state_;
}
// Disclaimer: Experimental method, subject to change.
// Exposed publicly to emit some TrackEvent fields in Chromium only in local
// tracing. Long-term, we really shouldn't be (ab)using the
// filter_debug_annotation setting for this.
//
// TODO(kraskevich): Come up with a more precise name once we have more than
// one usecase.
bool ShouldFilterDebugAnnotations() const {
if (tls_state_) {
return tls_state_->filter_debug_annotations;
}
// In Chromium tls_state_ is nullptr, so we need to get this information
// from a separate field.
return filter_debug_annotations_;
}
// Get a TrackEvent message to write typed arguments to.
//
// event() is a template method to allow callers to specify a subclass of
// TrackEvent instead. Those subclasses correspond to TrackEvent message with
// application-specific extensions. More information in
// design-docs/extensions.md.
template <typename EventType = protos::pbzero::TrackEvent>
EventType* event() const {
// As the method does downcasting, we check that a target subclass does
// not add new fields.
static_assert(
sizeof(EventType) == sizeof(protos::pbzero::TrackEvent),
"Event type must be binary-compatible with protos::pbzero::TrackEvent");
return static_cast<EventType*>(event_);
}
// Convert a raw pointer to protozero message to TracedProto which captures
// the reference to this EventContext.
template <typename MessageType>
TracedProto<MessageType> Wrap(MessageType* message) {
static_assert(std::is_base_of<protozero::Message, MessageType>::value,
"TracedProto can be used only with protozero messages");
return TracedProto<MessageType>(message, this);
}
// Add a new `debug_annotation` proto message and populate it from |value|
// using perfetto::TracedValue API. Users should generally prefer passing
// values directly to TRACE_EVENT (i.e. TRACE_EVENT(..., "arg", value, ...);)
// but in rare cases (e.g. when an argument should be written conditionally)
// EventContext::AddDebugAnnotation provides an explicit equivalent.
template <typename EventNameType, typename T>
void AddDebugAnnotation(EventNameType&& name, T&& value) {
if (tls_state_ && tls_state_->filter_debug_annotations)
return;
auto annotation = AddDebugAnnotation(std::forward<EventNameType>(name));
WriteIntoTracedValue(internal::CreateTracedValueFromProto(annotation, this),
std::forward<T>(value));
}
private:
template <typename, size_t, typename, typename>
friend class TrackEventInternedDataIndex;
friend class internal::TrackEventInternal;
using TracePacketHandle =
::protozero::MessageHandle<protos::pbzero::TracePacket>;
EventContext(TracePacketHandle,
internal::TrackEventIncrementalState*,
const internal::TrackEventTlsState*);
EventContext(const EventContext&) = delete;
protos::pbzero::DebugAnnotation* AddDebugAnnotation(const char* name);
protos::pbzero::DebugAnnotation* AddDebugAnnotation(
::perfetto::DynamicString name);
TracePacketHandle trace_packet_;
protos::pbzero::TrackEvent* event_;
internal::TrackEventIncrementalState* incremental_state_;
// TODO(mohitms): Make it const-reference instead of pointer, once we
// are certain that it cannot be nullptr. Once we switch to client library in
// chrome, we can make that happen.
const internal::TrackEventTlsState* tls_state_ = nullptr;
// TODO(kraskevich): Come up with a more precise name once we have more than
// one usecase.
// TODO(kraskevich): Remove once Chromium has fully switched to client lib.
const bool filter_debug_annotations_ = false;
};
} // namespace perfetto
#endif // INCLUDE_PERFETTO_TRACING_EVENT_CONTEXT_H_