blob: 22fef1cc0ca6bea8ceeb359a813dbd4deb549fd6 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "src/cobalt/bin/app/logger_impl.h"
#include <lib/trace/event.h>
#include "src/cobalt/bin/app/utils.h"
namespace cobalt {
using fuchsia::cobalt::Status;
LoggerImpl::LoggerImpl(std::unique_ptr<logger::LoggerInterface> logger, TimerManager* timer_manager)
: logger_(std::move(logger)), timer_manager_(timer_manager) {}
void LoggerImpl::LogEvent(uint32_t metric_id, uint32_t event_code,
fuchsia::cobalt::LoggerBase::LogEventCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogEvent");
callback(ToCobaltStatus(logger_->LogEvent(metric_id, event_code)));
}
void LoggerImpl::LogEventCount(uint32_t metric_id, uint32_t event_code, std::string component,
int64_t period_duration_micros, int64_t count,
fuchsia::cobalt::LoggerBase::LogEventCountCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogEventCount");
callback(ToCobaltStatus(
logger_->LogEventCount(metric_id, event_code, component, period_duration_micros, count)));
}
void LoggerImpl::LogElapsedTime(uint32_t metric_id, uint32_t event_code, std::string component,
int64_t elapsed_micros,
fuchsia::cobalt::LoggerBase::LogElapsedTimeCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogElapsedTime");
callback(
ToCobaltStatus(logger_->LogElapsedTime(metric_id, event_code, component, elapsed_micros)));
}
void LoggerImpl::LogFrameRate(uint32_t metric_id, uint32_t event_code, std::string component,
float fps,
fuchsia::cobalt::LoggerBase::LogFrameRateCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogFrameRate");
callback(ToCobaltStatus(logger_->LogFrameRate(metric_id, event_code, component, fps)));
}
void LoggerImpl::LogMemoryUsage(uint32_t metric_id, uint32_t event_code, std::string component,
int64_t bytes,
fuchsia::cobalt::LoggerBase::LogMemoryUsageCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogMemoryUsage");
callback(ToCobaltStatus(logger_->LogMemoryUsage(metric_id, event_code, component, bytes)));
}
void LoggerImpl::LogIntHistogram(uint32_t metric_id, uint32_t event_code, std::string component,
std::vector<fuchsia::cobalt::HistogramBucket> histogram,
fuchsia::cobalt::Logger::LogIntHistogramCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogIntHistogram");
logger::HistogramPtr histogram_ptr(new google::protobuf::RepeatedPtrField<HistogramBucket>());
for (auto it = histogram.begin(); histogram.end() != it; it++) {
auto bucket = histogram_ptr->Add();
bucket->set_index((*it).index);
bucket->set_count((*it).count);
}
callback(ToCobaltStatus(
logger_->LogIntHistogram(metric_id, event_code, component, std::move(histogram_ptr))));
}
void LoggerImpl::LogIntHistogram(uint32_t metric_id, uint32_t event_code, std::string component,
std::vector<uint32_t> bucket_indices,
std::vector<uint64_t> bucket_counts,
fuchsia::cobalt::LoggerSimple::LogIntHistogramCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogIntHistogram");
if (bucket_indices.size() != bucket_counts.size()) {
FX_LOGS(ERROR) << "[" << metric_id << "]: bucket_indices.size() != bucket_counts.size().";
callback(Status::INVALID_ARGUMENTS);
return;
}
logger::HistogramPtr histogram_ptr(new google::protobuf::RepeatedPtrField<HistogramBucket>());
for (auto i = 0; i < bucket_indices.size(); i++) {
auto bucket = histogram_ptr->Add();
bucket->set_index(bucket_indices.at(i));
bucket->set_count(bucket_counts.at(i));
}
callback(ToCobaltStatus(
logger_->LogIntHistogram(metric_id, event_code, component, std::move(histogram_ptr))));
}
void LoggerImpl::LogCustomEvent(uint32_t metric_id,
std::vector<fuchsia::cobalt::CustomEventValue> event_values,
fuchsia::cobalt::Logger::LogCustomEventCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogCustomEvent");
logger::EventValuesPtr inner_event_values(
new google::protobuf::Map<std::string, CustomDimensionValue>());
for (auto it = event_values.begin(); event_values.end() != it; it++) {
CustomDimensionValue value;
if (it->value.is_string_value()) {
value.set_string_value(it->value.string_value());
} else if (it->value.is_int_value()) {
value.set_int_value(it->value.int_value());
} else if (it->value.is_double_value()) {
value.set_double_value(it->value.double_value());
} else if (it->value.is_index_value()) {
value.set_index_value(it->value.index_value());
}
auto pair = google::protobuf::MapPair(it->dimension_name, value);
inner_event_values->insert(pair);
}
callback(ToCobaltStatus(logger_->LogCustomEvent(metric_id, std::move(inner_event_values))));
}
template <class CB>
void LoggerImpl::AddTimerObservationIfReady(std::unique_ptr<TimerVal> timer_val_ptr, CB callback) {
if (!TimerManager::isReady(timer_val_ptr)) {
// TimerManager has not received both StartTimer and EndTimer calls. Return
// OK status and wait for the other call.
callback(Status::OK);
return;
}
callback(ToCobaltStatus(logger_->LogElapsedTime(
timer_val_ptr->metric_id, timer_val_ptr->event_code, timer_val_ptr->component,
timer_val_ptr->end_timestamp - timer_val_ptr->start_timestamp)));
}
void LoggerImpl::StartTimer(uint32_t metric_id, uint32_t event_code, std::string component,
std::string timer_id, uint64_t timestamp, uint32_t timeout_s,
fuchsia::cobalt::LoggerBase::StartTimerCallback callback) {
if (!timer_manager_) {
FX_LOGS(ERROR) << "Cobalt internal error: StartTimer() invoked but there is no TimerManager";
callback(Status::INTERNAL_ERROR);
return;
}
std::unique_ptr<TimerVal> timer_val_ptr;
auto status = timer_manager_->GetTimerValWithStart(metric_id, event_code, component, 0, timer_id,
timestamp, timeout_s, &timer_val_ptr);
if (status != Status::OK) {
callback(status);
return;
}
AddTimerObservationIfReady(std::move(timer_val_ptr), std::move(callback));
}
void LoggerImpl::EndTimer(std::string timer_id, uint64_t timestamp, uint32_t timeout_s,
fuchsia::cobalt::LoggerBase::EndTimerCallback callback) {
if (!timer_manager_) {
FX_LOGS(ERROR) << "Cobalt internal error: EndTimer() invoked but there is no TimerManager";
callback(Status::INTERNAL_ERROR);
return;
}
std::unique_ptr<TimerVal> timer_val_ptr;
auto status = timer_manager_->GetTimerValWithEnd(timer_id, timestamp, timeout_s, &timer_val_ptr);
if (status != Status::OK) {
callback(status);
return;
}
AddTimerObservationIfReady(std::move(timer_val_ptr), std::move(callback));
}
using fuchsia::cobalt::EventPayload;
void LoggerImpl::LogCobaltEvent(fuchsia::cobalt::CobaltEvent event,
fuchsia::cobalt::Logger::LogCobaltEventCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogCobaltEvent");
switch (event.payload.Which()) {
case EventPayload::Tag::kEvent:
if (event.event_codes.size() != 1) {
callback(Status::INVALID_ARGUMENTS);
} else {
callback(ToCobaltStatus(logger_->LogEvent(event.metric_id, event.event_codes[0])));
}
return;
case EventPayload::Tag::kEventCount:
callback(ToCobaltStatus(logger_->LogEventCount(
event.metric_id, event.event_codes, event.component.value_or(""),
event.payload.event_count().period_duration_micros, event.payload.event_count().count)));
return;
case EventPayload::Tag::kElapsedMicros:
callback(ToCobaltStatus(logger_->LogElapsedTime(event.metric_id, event.event_codes,
event.component.value_or(""),
event.payload.elapsed_micros())));
return;
case EventPayload::Tag::kFps:
callback(ToCobaltStatus(logger_->LogFrameRate(
event.metric_id, event.event_codes, event.component.value_or(""), event.payload.fps())));
return;
case EventPayload::Tag::kMemoryBytesUsed:
callback(ToCobaltStatus(logger_->LogMemoryUsage(event.metric_id, event.event_codes,
event.component.value_or(""),
event.payload.memory_bytes_used())));
return;
case EventPayload::Tag::kIntHistogram: {
auto histogram = std::move(event.payload.int_histogram());
logger::HistogramPtr histogram_ptr(new google::protobuf::RepeatedPtrField<HistogramBucket>());
for (auto it = histogram.begin(); histogram.end() != it; it++) {
auto bucket = histogram_ptr->Add();
bucket->set_index((*it).index);
bucket->set_count((*it).count);
}
callback(ToCobaltStatus(logger_->LogIntHistogram(event.metric_id, event.event_codes,
event.component.value_or(""),
std::move(histogram_ptr))));
return;
}
default:
callback(Status::INVALID_ARGUMENTS);
return;
}
}
void LoggerImpl::LogCobaltEvents(std::vector<fuchsia::cobalt::CobaltEvent> events,
fuchsia::cobalt::Logger::LogCobaltEventCallback callback) {
TRACE_DURATION("cobalt_fidl", "LoggerImpl::LogCobaltEvents");
logger_->RecordLoggerCall(logger::LoggerCallsMadeMetricDimensionLoggerMethod::LogCobaltEvents);
// tracking LoggerCalled events is expensive (~3.5ms/event). We want
// LogCobaltEvents to be a more performance concious alternative, so we pause
// this logging while we work through the batch.
logger_->PauseInternalLogging();
auto failures = 0;
auto end = std::make_move_iterator(events.end());
for (auto it = std::make_move_iterator(events.begin()); it != end; it++) {
LogCobaltEvent(std::move(*it), [failures](Status status) mutable {
if (status != Status::OK) {
failures += 1;
}
});
}
logger_->ResumeInternalLogging();
if (failures == 0) {
callback(Status::OK);
} else {
callback(Status::INTERNAL_ERROR);
}
}
} // namespace cobalt