| // 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/logger/logger.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include "src/logger/event_loggers.h" |
| #include "src/logger/event_record.h" |
| #include "src/logging.h" |
| #include "src/registry/metric_definition.pb.h" |
| #include "src/registry/report_definition.pb.h" |
| |
| namespace cobalt::logger { |
| |
| using local_aggregation::EventAggregator; |
| |
| using LoggerMethod = PerProjectLoggerCallsMadeMetricDimensionLoggerMethod; |
| |
| namespace { |
| |
| template <class EventType> |
| void CopyEventCodesAndComponent(const std::vector<uint32_t>& event_codes, |
| const std::string& component, EventType* event) { |
| for (auto event_code : event_codes) { |
| event->add_event_code(event_code); |
| } |
| event->set_component(component); |
| } |
| |
| } // namespace |
| |
| Logger::Logger(std::unique_ptr<ProjectContext> project_context, const Encoder* encoder, |
| EventAggregator* event_aggregator, ObservationWriter* observation_writer, |
| system_data::SystemDataInterface* system_data, LoggerInterface* internal_logger) |
| : Logger(std::move(project_context), encoder, event_aggregator, observation_writer, system_data, |
| nullptr, std::weak_ptr<UndatedEventManager>(), internal_logger) {} |
| |
| Logger::Logger(std::unique_ptr<ProjectContext> project_context, const Encoder* encoder, |
| EventAggregator* event_aggregator, ObservationWriter* observation_writer, |
| system_data::SystemDataInterface* system_data, |
| util::ValidatedClockInterface* validated_clock, |
| std::weak_ptr<UndatedEventManager> undated_event_manager, |
| LoggerInterface* internal_logger) |
| : project_context_(std::move(project_context)), |
| encoder_(encoder), |
| event_aggregator_(event_aggregator), |
| observation_writer_(observation_writer), |
| system_data_(system_data), |
| validated_clock_(validated_clock), |
| undated_event_manager_(std::move(undated_event_manager)) { |
| CHECK(project_context_); |
| CHECK(encoder_); |
| CHECK(event_aggregator_); |
| CHECK(observation_writer_); |
| if (!validated_clock_) { |
| local_validated_clock_ = |
| std::make_unique<util::AlwaysAccurateClock>(std::make_unique<util::SystemClock>()); |
| validated_clock_ = local_validated_clock_.get(); |
| } |
| if (internal_logger) { |
| internal_metrics_ = std::make_unique<InternalMetricsImpl>(internal_logger); |
| } else { |
| // We were not provided with a metrics logger. We must create one. |
| internal_metrics_ = std::make_unique<NoOpInternalMetrics>(); |
| } |
| if (event_aggregator_->UpdateAggregationConfigs(*project_context_) != kOK) { |
| LOG(ERROR) << "Failed to provide aggregation configurations to the " |
| "EventAggregator."; |
| } |
| } |
| |
| Status Logger::LogEvent(uint32_t metric_id, uint32_t event_code) { |
| VLOG(4) << "Logger::LogEvent(" << metric_id << ", " << event_code |
| << ") project=" << project_context_->FullyQualifiedName(); |
| auto event_record = std::make_unique<EventRecord>(project_context_, metric_id); |
| internal_metrics_->LoggerCalled(LoggerMethod::LogEvent, project_context_->project()); |
| auto* occurrence_event = event_record->event()->mutable_occurrence_event(); |
| occurrence_event->set_event_code(event_code); |
| return Log(metric_id, MetricDefinition::EVENT_OCCURRED, std::move(event_record)); |
| } |
| |
| Status Logger::LogEventCount(uint32_t metric_id, const std::vector<uint32_t>& event_codes, |
| const std::string& component, int64_t period_duration_micros, |
| uint32_t count) { |
| internal_metrics_->LoggerCalled(LoggerMethod::LogEventCount, project_context_->project()); |
| auto event_record = std::make_unique<EventRecord>(project_context_, metric_id); |
| auto* count_event = event_record->event()->mutable_count_event(); |
| CopyEventCodesAndComponent(event_codes, component, count_event); |
| count_event->set_period_duration_micros(period_duration_micros); |
| count_event->set_count(count); |
| return Log(metric_id, MetricDefinition::EVENT_COUNT, std::move(event_record)); |
| } |
| |
| Status Logger::LogElapsedTime(uint32_t metric_id, const std::vector<uint32_t>& event_codes, |
| const std::string& component, int64_t elapsed_micros) { |
| internal_metrics_->LoggerCalled(LoggerMethod::LogElapsedTime, project_context_->project()); |
| auto event_record = std::make_unique<EventRecord>(project_context_, metric_id); |
| auto* elapsed_time_event = event_record->event()->mutable_elapsed_time_event(); |
| CopyEventCodesAndComponent(event_codes, component, elapsed_time_event); |
| elapsed_time_event->set_elapsed_micros(elapsed_micros); |
| return Log(metric_id, MetricDefinition::ELAPSED_TIME, std::move(event_record)); |
| } |
| |
| Status Logger::LogFrameRate(uint32_t metric_id, const std::vector<uint32_t>& event_codes, |
| const std::string& component, float fps) { |
| internal_metrics_->LoggerCalled(LoggerMethod::LogFrameRate, project_context_->project()); |
| auto event_record = std::make_unique<EventRecord>(project_context_, metric_id); |
| auto* frame_rate_event = event_record->event()->mutable_frame_rate_event(); |
| CopyEventCodesAndComponent(event_codes, component, frame_rate_event); |
| // NOLINTNEXTLINE readability-magic-numbers |
| frame_rate_event->set_frames_per_1000_seconds(std::round(fps * 1000.0)); |
| return Log(metric_id, MetricDefinition::FRAME_RATE, std::move(event_record)); |
| } |
| |
| Status Logger::LogMemoryUsage(uint32_t metric_id, const std::vector<uint32_t>& event_codes, |
| const std::string& component, int64_t bytes) { |
| internal_metrics_->LoggerCalled(LoggerMethod::LogMemoryUsage, project_context_->project()); |
| auto event_record = std::make_unique<EventRecord>(project_context_, metric_id); |
| auto* memory_usage_event = event_record->event()->mutable_memory_usage_event(); |
| CopyEventCodesAndComponent(event_codes, component, memory_usage_event); |
| memory_usage_event->set_bytes(bytes); |
| return Log(metric_id, MetricDefinition::MEMORY_USAGE, std::move(event_record)); |
| } |
| |
| Status Logger::LogIntHistogram(uint32_t metric_id, const std::vector<uint32_t>& event_codes, |
| const std::string& component, HistogramPtr histogram) { |
| internal_metrics_->LoggerCalled(LoggerMethod::LogIntHistogram, project_context_->project()); |
| auto event_record = std::make_unique<EventRecord>(project_context_, metric_id); |
| auto* int_histogram_event = event_record->event()->mutable_int_histogram_event(); |
| CopyEventCodesAndComponent(event_codes, component, int_histogram_event); |
| int_histogram_event->mutable_buckets()->Swap(histogram.get()); |
| return Log(metric_id, MetricDefinition::INT_HISTOGRAM, std::move(event_record)); |
| } |
| |
| Status Logger::LogCustomEvent(uint32_t metric_id, EventValuesPtr event_values) { |
| internal_metrics_->LoggerCalled(LoggerMethod::LogCustomEvent, project_context_->project()); |
| auto event_record = std::make_unique<EventRecord>(project_context_, metric_id); |
| auto* custom_event = event_record->event()->mutable_custom_event(); |
| custom_event->mutable_values()->swap(*event_values); |
| return Log(metric_id, MetricDefinition::CUSTOM, std::move(event_record)); |
| } |
| |
| Status Logger::Log(uint32_t metric_id, MetricDefinition::MetricType metric_type, |
| std::unique_ptr<EventRecord> event_record) { |
| auto event_logger = internal::EventLogger::Create(metric_type, encoder_, event_aggregator_, |
| observation_writer_, system_data_); |
| Status validation_result = |
| event_logger->PrepareAndValidateEvent(metric_id, metric_type, event_record.get()); |
| if (validation_result != kOK) { |
| return validation_result; |
| } |
| |
| auto now = validated_clock_->now(); |
| if (!now) { |
| // Missing system time means that the clock is not valid, so save the event until it is. |
| auto undated_event_manager = undated_event_manager_.lock(); |
| if (undated_event_manager) { |
| return undated_event_manager->Save(std::move(event_record)); |
| } |
| // A missing UndatedEventManager is handled by retrying the clock, which should now be valid. |
| |
| // If we fall through to here, then a race condition has occurred in which the clock that we |
| // thought was not validated, has become validated. Retrying the clock should succeed. |
| now = validated_clock_->now(); |
| if (!now) { |
| // This should never happen, if it does then it's a bug. |
| LOG(ERROR) << "Clock is invalid but there is no UndatedEventManager that will save the " |
| "event, dropping event for metric: " |
| << metric_id; |
| return Status::kOther; |
| } |
| } |
| |
| return event_logger->Log(std::move(event_record), *now); |
| } |
| |
| void Logger::PauseInternalLogging() { internal_metrics_->PauseLogging(); } |
| void Logger::ResumeInternalLogging() { internal_metrics_->ResumeLogging(); } |
| |
| } // namespace cobalt::logger |