1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/trace_event_impl.h" 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 70d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stddef.h> 8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/format_macros.h" 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/json/string_escape.h" 110d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/process/process_handle.h" 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/stl_util.h" 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/string_number_conversions.h" 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/string_util.h" 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/stringprintf.h" 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/utf_string_conversions.h" 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/trace_event.h" 180d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/trace_event/trace_log.h" 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace trace_event { 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratsize_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; } 26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copies |*member| into |*buffer|, sets |*member| to point to this new 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// location, and then advances |*buffer| by the amount written. 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid CopyTraceEventParameter(char** buffer, 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const char** member, 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const char* end) { 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (*member) { 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat size_t written = strlcpy(*buffer, *member, end - *buffer) + 1; 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_LE(static_cast<int>(written), end - *buffer); 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *member = *buffer; 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *buffer += written; 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTraceEvent::TraceEvent() 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat : duration_(TimeDelta::FromInternalValue(-1)), 4445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko scope_(trace_event_internal::kGlobalScope), 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat id_(0u), 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat category_group_enabled_(NULL), 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat name_(NULL), 48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread_id_(0), 490d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko flags_(0), 500d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko phase_(TRACE_EVENT_PHASE_BEGIN) { 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (int i = 0; i < kTraceMaxNumArgs; ++i) 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_names_[i] = NULL; 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat memset(arg_values_, 0, sizeof(arg_values_)); 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTraceEvent::~TraceEvent() { 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid TraceEvent::MoveFrom(std::unique_ptr<TraceEvent> other) { 6045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko timestamp_ = other->timestamp_; 6145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko thread_timestamp_ = other->thread_timestamp_; 6245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko duration_ = other->duration_; 6345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko scope_ = other->scope_; 6445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko id_ = other->id_; 6545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko category_group_enabled_ = other->category_group_enabled_; 6645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko name_ = other->name_; 6745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (other->flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID) 6845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko process_id_ = other->process_id_; 690d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko else 7045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko thread_id_ = other->thread_id_; 7145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko phase_ = other->phase_; 7245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko flags_ = other->flags_; 7345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko parameter_copy_storage_ = std::move(other->parameter_copy_storage_); 74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (int i = 0; i < kTraceMaxNumArgs; ++i) { 7645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko arg_names_[i] = other->arg_names_[i]; 7745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko arg_types_[i] = other->arg_types_[i]; 7845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko arg_values_[i] = other->arg_values_[i]; 7945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko convertable_values_[i] = std::move(other->convertable_values_[i]); 80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEvent::Initialize( 84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int thread_id, 850d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko TimeTicks timestamp, 86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ThreadTicks thread_timestamp, 87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat char phase, 88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const unsigned char* category_group_enabled, 89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const char* name, 9045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko const char* scope, 91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat unsigned long long id, 920d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko unsigned long long bind_id, 93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int num_args, 94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const char** arg_names, 95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const unsigned char* arg_types, 96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const unsigned long long* arg_values, 9794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez std::unique_ptr<ConvertableToTraceFormat>* convertable_values, 980d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko unsigned int flags) { 99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat timestamp_ = timestamp; 100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread_timestamp_ = thread_timestamp; 101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat duration_ = TimeDelta::FromInternalValue(-1); 10245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko scope_ = scope; 103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat id_ = id; 104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat category_group_enabled_ = category_group_enabled; 105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat name_ = name; 106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread_id_ = thread_id; 107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat phase_ = phase; 108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat flags_ = flags; 1090d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko bind_id_ = bind_id; 110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Clamp num_args since it may have been set by a third_party library. 112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args; 113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int i = 0; 114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (; i < num_args; ++i) { 115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_names_[i] = arg_names[i]; 116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_types_[i] = arg_types[i]; 117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 11845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) { 11945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko convertable_values_[i] = std::move(convertable_values[i]); 12045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko } else { 121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_values_[i].as_uint = arg_values[i]; 12245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko convertable_values_[i].reset(); 12345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko } 124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (; i < kTraceMaxNumArgs; ++i) { 126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_names_[i] = NULL; 127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_values_[i].as_uint = 0u; 12845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko convertable_values_[i].reset(); 129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_types_[i] = TRACE_VALUE_TYPE_UINT; 130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool copy = !!(flags & TRACE_EVENT_FLAG_COPY); 133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat size_t alloc_size = 0; 134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (copy) { 13545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko alloc_size += GetAllocLength(name) + GetAllocLength(scope); 136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (i = 0; i < num_args; ++i) { 137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat alloc_size += GetAllocLength(arg_names_[i]); 138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (arg_types_[i] == TRACE_VALUE_TYPE_STRING) 139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING; 140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool arg_is_copy[kTraceMaxNumArgs]; 144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (i = 0; i < num_args; ++i) { 145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // No copying of convertable types, we retain ownership. 146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) 147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat continue; 148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We only take a copy of arg_vals if they are of type COPY_STRING. 150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING); 151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (arg_is_copy[i]) 152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat alloc_size += GetAllocLength(arg_values_[i].as_string); 153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (alloc_size) { 15645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko parameter_copy_storage_.reset(new std::string); 15745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko parameter_copy_storage_->resize(alloc_size); 15845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko char* ptr = string_as_array(parameter_copy_storage_.get()); 159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const char* end = ptr + alloc_size; 160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (copy) { 161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CopyTraceEventParameter(&ptr, &name_, end); 16245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko CopyTraceEventParameter(&ptr, &scope_, end); 163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (i = 0; i < num_args; ++i) { 164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CopyTraceEventParameter(&ptr, &arg_names_[i], end); 165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (i = 0; i < num_args; ++i) { 168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) 169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat continue; 170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (arg_is_copy[i]) 171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end); 172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; 174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEvent::Reset() { 178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Only reset fields that won't be initialized in Initialize(), or that may 179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // hold references to other objects. 180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat duration_ = TimeDelta::FromInternalValue(-1); 18145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko parameter_copy_storage_.reset(); 182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (int i = 0; i < kTraceMaxNumArgs; ++i) 18345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko convertable_values_[i].reset(); 184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 1860d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkovoid TraceEvent::UpdateDuration(const TimeTicks& now, 187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const ThreadTicks& thread_now) { 188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK_EQ(duration_.ToInternalValue(), -1); 189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat duration_ = now - timestamp_; 1900d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1910d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // |thread_timestamp_| can be empty if the thread ticks clock wasn't 1920d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // initialized when it was recorded. 1930d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (thread_timestamp_ != ThreadTicks()) 1940d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko thread_duration_ = thread_now - thread_timestamp_; 195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEvent::EstimateTraceMemoryOverhead( 198b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TraceEventMemoryOverhead* overhead) { 1990d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko overhead->Add("TraceEvent", sizeof(*this)); 2000d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 2010d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (parameter_copy_storage_) 20245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko overhead->AddString(*parameter_copy_storage_); 2030d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 2040d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko for (size_t i = 0; i < kTraceMaxNumArgs; ++i) { 2050d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) 2060d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko convertable_values_[i]->EstimateTraceMemoryOverhead(overhead); 207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 208b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 209b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static 211b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEvent::AppendValueAsJSON(unsigned char type, 212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TraceEvent::TraceValue value, 213b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat std::string* out) { 214b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat switch (type) { 215b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_VALUE_TYPE_BOOL: 216b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += value.as_bool ? "true" : "false"; 217b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 218b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_VALUE_TYPE_UINT: 2190d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko StringAppendF(out, "%" PRIu64, static_cast<uint64_t>(value.as_uint)); 220b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 221b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_VALUE_TYPE_INT: 2220d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko StringAppendF(out, "%" PRId64, static_cast<int64_t>(value.as_int)); 223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_VALUE_TYPE_DOUBLE: { 225b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // FIXME: base/json/json_writer.cc is using the same code, 226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // should be made into a common method. 227b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat std::string real; 228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat double val = value.as_double; 229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (std::isfinite(val)) { 230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real = DoubleToString(val); 231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Ensure that the number has a .0 if there's no decimal or 'e'. This 232b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // makes sure that when we read the JSON back, it's interpreted as a 233b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // real rather than an int. 234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (real.find('.') == std::string::npos && 235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real.find('e') == std::string::npos && 236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real.find('E') == std::string::npos) { 237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real.append(".0"); 238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // The JSON spec requires that non-integer values in the range (-1,1) 240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // have a zero before the decimal point - ".52" is not valid, "0.52" is. 241b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (real[0] == '.') { 242b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real.insert(0, "0"); 243b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { 244b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // "-.1" bad "-0.1" good 245b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real.insert(1, "0"); 246b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 247b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } else if (std::isnan(val)){ 248b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // The JSON spec doesn't allow NaN and Infinity (since these are 249b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // objects in EcmaScript). Use strings instead. 250b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real = "\"NaN\""; 251b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } else if (val < 0) { 252b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real = "\"-Infinity\""; 253b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } else { 254b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat real = "\"Infinity\""; 255b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 256b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, "%s", real.c_str()); 257b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 258b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 259b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_VALUE_TYPE_POINTER: 260b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // JSON only supports double and int numbers. 261b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // So as not to lose bits from a 64-bit pointer, output as a hex string. 2620d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko StringAppendF( 2630d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko out, "\"0x%" PRIx64 "\"", 2640c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value.as_pointer))); 265b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 266b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_VALUE_TYPE_STRING: 267b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_VALUE_TYPE_COPY_STRING: 268b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out); 269b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 270b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat default: 271b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat NOTREACHED() << "Don't know how to print this value"; 272b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 273b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 274b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 275b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 276b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEvent::AppendAsJSON( 277b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat std::string* out, 278b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const ArgumentFilterPredicate& argument_filter_predicate) const { 2790d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko int64_t time_int64 = timestamp_.ToInternalValue(); 2800d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko int process_id; 2810d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko int thread_id; 2820d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if ((flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID) && 2830d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko process_id_ != kNullProcessId) { 2840d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko process_id = process_id_; 2850d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko thread_id = -1; 2860d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } else { 2870d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko process_id = TraceLog::GetInstance()->process_id(); 2880d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko thread_id = thread_id_; 2890d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 290b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const char* category_group_name = 291b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TraceLog::GetCategoryGroupName(category_group_enabled_); 292b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 293b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Category group checked at category creation time. 294b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK(!strchr(name_, '"')); 295b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 29694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez ",\"ph\":\"%c\",\"cat\":\"%s\",\"name\":", 29794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez process_id, thread_id, time_int64, phase_, category_group_name); 29894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez EscapeJSONString(name_, true, out); 29994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez *out += ",\"args\":"; 300b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 301b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Output argument names and values, stop at first NULL argument name. 3020d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // TODO(oysteine): The dual predicates here is a bit ugly; if the filtering 3030d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // capabilities need to grow even more precise we should rethink this 3040d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // approach 3050d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko ArgumentNameFilterPredicate argument_name_filter_predicate; 3060d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko bool strip_args = 3070d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko arg_names_[0] && !argument_filter_predicate.is_null() && 3080d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko !argument_filter_predicate.Run(category_group_name, name_, 3090d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko &argument_name_filter_predicate); 310b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 311b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (strip_args) { 312b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += "\"__stripped__\""; 313b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } else { 314b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += "{"; 315b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 316b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { 317b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (i > 0) 318b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += ","; 319b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += "\""; 320b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += arg_names_[i]; 321b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += "\":"; 322b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 3230d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (argument_name_filter_predicate.is_null() || 3240d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko argument_name_filter_predicate.Run(arg_names_[i])) { 3250d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) 3260d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko convertable_values_[i]->AppendAsTraceFormat(out); 3270d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko else 3280d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko AppendValueAsJSON(arg_types_[i], arg_values_[i], out); 3290d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } else { 3300d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko *out += "\"__stripped__\""; 3310d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 332b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 333b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 334b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += "}"; 335b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 336b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 337b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (phase_ == TRACE_EVENT_PHASE_COMPLETE) { 3380d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko int64_t duration = duration_.ToInternalValue(); 339b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (duration != -1) 340b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, ",\"dur\":%" PRId64, duration); 341b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!thread_timestamp_.is_null()) { 3420d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko int64_t thread_duration = thread_duration_.ToInternalValue(); 343b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (thread_duration != -1) 344b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration); 345b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 346b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 347b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 348b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Output tts if thread_timestamp is valid. 349b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (!thread_timestamp_.is_null()) { 3500d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko int64_t thread_time_int64 = thread_timestamp_.ToInternalValue(); 351b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64); 352b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 353b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 354b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Output async tts marker field if flag is set. 355b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) { 356b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, ", \"use_async_tts\":1"); 357b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 358b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 359b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // If id_ is set, print it out as a hex string so we don't loose any 360b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // bits (it might be a 64-bit pointer). 36145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (flags_ & TRACE_EVENT_FLAG_HAS_ID) { 36245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko if (scope_ != trace_event_internal::kGlobalScope) 36345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko StringAppendF(out, ",\"scope\":\"%s\"", scope_); 3640d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64_t>(id_)); 36545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko } 366b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 367b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING) 368b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, ",\"bp\":\"e\""); 369b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 3700d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if ((flags_ & TRACE_EVENT_FLAG_FLOW_OUT) || 3710d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko (flags_ & TRACE_EVENT_FLAG_FLOW_IN)) { 3720d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko StringAppendF(out, ",\"bind_id\":\"0x%" PRIx64 "\"", 3730d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko static_cast<uint64_t>(bind_id_)); 3740d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 3750d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (flags_ & TRACE_EVENT_FLAG_FLOW_IN) 3760d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko StringAppendF(out, ",\"flow_in\":true"); 3770d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (flags_ & TRACE_EVENT_FLAG_FLOW_OUT) 3780d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko StringAppendF(out, ",\"flow_out\":true"); 3790d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 380b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Instant events also output their scope. 381b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (phase_ == TRACE_EVENT_PHASE_INSTANT) { 382b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat char scope = '?'; 383b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat switch (flags_ & TRACE_EVENT_FLAG_SCOPE_MASK) { 384b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_EVENT_SCOPE_GLOBAL: 385b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat scope = TRACE_EVENT_SCOPE_NAME_GLOBAL; 386b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 387b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 388b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_EVENT_SCOPE_PROCESS: 389b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat scope = TRACE_EVENT_SCOPE_NAME_PROCESS; 390b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 391b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 392b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat case TRACE_EVENT_SCOPE_THREAD: 393b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat scope = TRACE_EVENT_SCOPE_NAME_THREAD; 394b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 395b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 396b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat StringAppendF(out, ",\"s\":\"%c\"", scope); 397b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 398b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 399b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out += "}"; 400b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 401b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 402b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid TraceEvent::AppendPrettyPrinted(std::ostringstream* out) const { 403b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << name_ << "["; 404b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << TraceLog::GetCategoryGroupName(category_group_enabled_); 405b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << "]"; 406b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (arg_names_[0]) { 407b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << ", {"; 408b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { 409b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (i > 0) 410b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << ", "; 411b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << arg_names_[i] << ":"; 412b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat std::string value_as_text; 413b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 414b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) 415b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat convertable_values_[i]->AppendAsTraceFormat(&value_as_text); 416b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat else 417b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AppendValueAsJSON(arg_types_[i], arg_values_[i], &value_as_text); 418b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 419b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << value_as_text; 420b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 421b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat *out << "}"; 422b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 423b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 424b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 425b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace trace_event 426b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 427