| // 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 FuchsiaStatus = 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(FuchsiaStatus::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(FuchsiaStatus::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(FuchsiaStatus::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 != FuchsiaStatus::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(FuchsiaStatus::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 != FuchsiaStatus::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(FuchsiaStatus::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(FuchsiaStatus::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::LoggerCallsMadeMigratedMetricDimensionLoggerMethod::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](FuchsiaStatus status) mutable { |
| if (status != FuchsiaStatus::OK) { |
| failures += 1; |
| } |
| }); |
| } |
| |
| logger_->ResumeInternalLogging(); |
| |
| if (failures == 0) { |
| callback(FuchsiaStatus::OK); |
| } else { |
| callback(FuchsiaStatus::INTERNAL_ERROR); |
| } |
| } |
| |
| } // namespace cobalt |