blob: b79b0aca3180aa1c2dbd1fc9c14125a883d494b8 [file] [log] [blame]
// Copyright 2019 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.
#ifndef COBALT_SRC_PUBLIC_COBALT_CONFIG_H_
#define COBALT_SRC_PUBLIC_COBALT_CONFIG_H_
#include <memory>
#include "src/lib/clearcut/uploader.h"
#include "src/lib/util/clock.h"
#include "src/lib/util/file_system.h"
#include "src/local_aggregation_1_1/local_aggregate_storage/local_aggregate_storage.h"
#include "src/logger/project_context.h"
#include "src/pb/common.pb.h"
#include "src/public/activity_listener_interface.h"
#include "src/public/diagnostics_interface.h"
#include "src/public/lib/http_client.h"
#include "src/registry/metric_definition.pb.h"
#include "src/system_data/client_secret.h"
#include "src/system_data/configuration_data.h"
namespace cobalt {
constexpr char kDefaultClearcutEndpoint[] = "https://play.googleapis.com/staging/log";
constexpr char kProductionClearcutEndpoint[] = "https://play.googleapis.com/log";
constexpr size_t kDefaultClearcutMaxRetries = 5;
using StorageStrategy = local_aggregation::LocalAggregateStorage::StorageStrategy;
class TargetPipelineInterface {
public:
explicit TargetPipelineInterface(system_data::Environment environment)
: environment_(environment) {}
virtual ~TargetPipelineInterface() = default;
// The target environment for the pipeline. Used to determine where to send the data.
[[nodiscard]] system_data::Environment environment() const { return environment_; }
// An encoded CobaltEncryptionKey proto representing the encryption key to be used for envelopes
// sent to the shuffler. (Or nullopt for no encryption)
[[nodiscard]] virtual std::optional<std::string> shuffler_encryption_key() const {
return std::nullopt;
}
// An encoded CobaltEncryptionKey proto representing the encryption key to be used for
// observations sent to the analyzer. (Or nullopt for no encryption)
[[nodiscard]] virtual std::optional<std::string> analyzer_encryption_key() const {
return std::nullopt;
}
// The URL for the desired clearcut endpoint.
[[nodiscard]] virtual std::string clearcut_endpoint() const { return ""; }
// Returns an implementation of lib::HTTPClient. Will be used for uploading data in the
// ShippingManager.
//
// Note, that it is used to create cobalt::lib::ClearcutUploader that uses HTTP
// requests for uploading to clearcut.
// If TakeClearcutUploader is overridden then there is no need to override this method.
[[nodiscard]] virtual std::unique_ptr<lib::HTTPClient> TakeHttpClient() { return nullptr; }
// Returns an implementation of lib::clearcut::ClearcutUploaderInterface. Will be used for
// uploading data in the ShippingManager. If it is not set uploader will be created using
// parameters in the config.
[[nodiscard]] virtual std::unique_ptr<lib::clearcut::ClearcutUploaderInterface>
TakeClearcutUploader() {
return nullptr;
}
// How many times should the clearcut upload be reattempted, before returning the observations to
// the ObservationStore.
[[nodiscard]] virtual size_t clearcut_max_retries() const { return 0; }
private:
system_data::Environment environment_;
};
class LocalPipeline : public TargetPipelineInterface {
public:
LocalPipeline() : TargetPipelineInterface(system_data::Environment::LOCAL) {}
~LocalPipeline() override = default;
};
class TargetPipeline : public TargetPipelineInterface {
public:
TargetPipeline(system_data::Environment environment, std::string shuffler_encryption_key,
std::string analyzer_encryption_key, std::unique_ptr<lib::HTTPClient> http_client,
size_t clearcut_max_retries = kDefaultClearcutMaxRetries)
: TargetPipelineInterface(environment),
shuffler_encryption_key_(std::move(shuffler_encryption_key)),
analyzer_encryption_key_(std::move(analyzer_encryption_key)),
http_client_(std::move(http_client)),
clearcut_max_retries_(clearcut_max_retries) {}
~TargetPipeline() override = default;
[[nodiscard]] std::optional<std::string> shuffler_encryption_key() const override {
if (shuffler_encryption_key_.empty()) {
return std::optional<std::string>();
}
return shuffler_encryption_key_;
}
[[nodiscard]] std::optional<std::string> analyzer_encryption_key() const override {
if (analyzer_encryption_key_.empty()) {
return std::optional<std::string>();
}
return analyzer_encryption_key_;
}
[[nodiscard]] std::string clearcut_endpoint() const override {
if (environment() == system_data::Environment::PROD) {
return kProductionClearcutEndpoint;
}
return kDefaultClearcutEndpoint;
}
[[nodiscard]] std::unique_ptr<lib::HTTPClient> TakeHttpClient() override {
return std::move(http_client_);
}
[[nodiscard]] size_t clearcut_max_retries() const override { return clearcut_max_retries_; }
private:
std::string shuffler_encryption_key_;
std::string analyzer_encryption_key_;
std::unique_ptr<lib::HTTPClient> http_client_;
size_t clearcut_max_retries_;
};
struct StorageQuotas {
int64_t per_project_reserved_bytes;
int64_t total_capacity_bytes;
};
const StorageQuotas kDefaultStorageQuotas = {
.per_project_reserved_bytes = size_t{1024}, // Default to 1KiB
.total_capacity_bytes = size_t{1024} * 1024, // Default to 1MiB
};
// These four values are provided to the UploadScheduler of the shipping manager.
// REQUIRED:
// 0 <= min_interval <= target_interval <= kMaxSeconds
// 0 <= upload_jitter < 1
struct UploadScheduleConfig {
// |target_interval|: How frequently should ShippingManager perform regular periodic sends to the
// Shuffler? Set to kMaxSeconds to effectively disable periodic sends.
std::chrono::seconds target_interval;
// |min_interval|: Used as the basis for exponentially increasing the upload interval. The
// resulting interval starts at this value, and then is multiplied by 2 each time until the value
// is greater than or equal to |target_interval|.
std::chrono::seconds min_interval;
//
// |initial_interval| The upload scheduler thread will initially perform more frequent uploads at
// this interval and then exponentially back off until it reaches a periodic
// rhythm of |target_interval|.
std::chrono::seconds initial_interval;
// |jitter|: Used to mitigate risk of synchronized uploads between devices
// and hide information about reboot time. Each interval is increased
// or decreased by a random value n distributed between 0 and
// |jitter| * current_interval.
float jitter;
};
struct CobaltConfig {
// |product_name|: The value to use for the |product_name| field of the SystemProfile.
std::string product_name;
// |board_name_suggestion|: A suggestion for the value to use for the |board_name| field of the
// SystemProfile. This may be ignored if SystemData is able to determine the board name directly.
// A value of "" indicates that the caller has no information about board name, so one should be
// guessed.
std::string board_name_suggestion;
// |version|: The version of the running system. The use of this field is system-specific. For
// example on Fuchsia a possible value for |version| is "20190220_01_RC00".
std::string version;
// |build_type|: The build type of the running system. The use of this field
// is system-specific. Fuchsia can have possible values of "eng", "user", and
// "user_debug".
SystemProfile::BuildType build_type = SystemProfile::UNKNOWN_TYPE;
// |release_stage|: The ReleaseStage of the running system.
ReleaseStage release_stage = ReleaseStage::GA;
// |file_system|: The FileSystem implementation to be used for all file system operations in
// Cobalt.
std::unique_ptr<util::FileSystem> file_system;
// |use_memory_observation_store|: If true, the ObservaitonStore used will be memory backed intead
// of file backed.
bool use_memory_observation_store = false;
// These three values are provided to the ObservationStore.
//
// |max_bytes_per_event|: Attempting to log an event that is larger than this value will result in
// an error code kObservationTooBig. (See observation_store.h)
//
// |max_bytes_per_envelope|: When pooling together Observaitons into an Envelope, the
// ObservationStore will try not to form envelopes larger than this size. This value is used to
// avoid sending messages over HTTP that are too large. (see observation_store.h)
//
// |max_bytes_total|: This is the maximum size of the Observations in the ObservationStore. If the
// size of the accumulated Observation data reaches this value, then ObservationStore will not
// accept any more Observations, resulting in an error code of kStoreFull. (See
// observaiton_store.h)
//
// REQUIRED:
// 0 <= max_bytes_per_event <= max_bytes_per_envelope <= max_bytes_total
// 0 <= max_bytes_per_envelope
size_t max_bytes_per_event;
size_t max_bytes_per_envelope;
size_t max_bytes_total;
// |storage_quota|: provided to local aggregation to cap the amount of disk usage used by the
// local aggregate storage.
StorageQuotas storage_quotas = kDefaultStorageQuotas;
// |observation_store_directory|: If |use_memory_observation_store| is false, this is the absolute
// path to the directory the observation_store will use to store observations. This directory
// doesn't need to exist yet, but its parent directory must already exist.
std::string observation_store_directory;
// |local_aggregate_proto_store_path|: The absolute path to a file where the local aggregate proto
// should be stored. The directory this file is in must already exist.
std::string local_aggregate_proto_store_path;
// |obs_history_proto_store_path|: The absolute path to a file where the observation history proto
// should be stored. The directory this file is in must already exist.
std::string obs_history_proto_store_path;
// |local_aggregate_store_dir|: The absolute path to the directory where the local aggregate store
// for Cobalt 1.1 should be stored. This directory doesn't need to exist yet, but its parent
// directory must already exist.
std::string local_aggregate_store_dir;
// |local_aggregate_store_strategy|: The strategy to use for LocalAggregateStorage.
//
// Immediate: Always write to disk immediately after every modification. (The default)
// Delayed: Writes to disk every 5 seconds if there have been any modifications. (Note: This
// implementation has more potential to lose data. Only use this on systems where
// Immediate performs poorly)
StorageStrategy local_aggregate_store_strategy = StorageStrategy::Immediate;
// Any missing system profile fields at observation generation time should be taken from the
// current system profile. This should be set on systems where some of the system profile
// information is not available at logging time.
bool generate_observations_with_current_system_profile = false;
// |system_data_cache_path|: The absolute path where the MetadataBuilder will cache its
// previously seen SystemData.
std::string system_data_cache_path;
// |upload_schedule|: config values provided to the UploadScheduler.
UploadScheduleConfig upload_schedule_cfg;
// |target_pipeline|: Used to determine where to send observations, and how to encrypt them.
std::unique_ptr<TargetPipelineInterface> target_pipeline;
// |local_shipping_manager_path|: If |environments| is equal to {LOCAL}, the observations will be
// written to this path, instead of being shipped to clearcut.
std::string local_shipping_manager_path;
// |api_key|: An API key included in each request to the Shuffler. If the API key is unrecognized
// on the server, the observations may be discarded.
std::string api_key;
// |client_secret|: The ClientSecret for this device.
system_data::ClientSecret client_secret;
// |global_registry|: The complete registry of all customers, projects, metrics, and reports.
std::unique_ptr<CobaltRegistry> global_registry = nullptr;
// |local_aggregation_backfill_days|: The number of past days for which the AggregateStore
// generates and sends Observations, in addition to a requested day index.
size_t local_aggregation_backfill_days;
// |validated_clock|: A reference to a ValidatedClockInterface, used to determine when the system
// has a clock that we can rely on.
util::ValidatedClockInterface* validated_clock;
// |civil_time_converter|: Converts an absolute time to a civil time for a given time zone.
// For now, if null, Cobalt defaults to UTC for all metrics with the {OTHER_TIME_ZONE}
// TimeZonePolicy. In the future, `civil_time_converter` will be required to create a
// CobaltService.
//
// TODO(fxbug.dev/92131): Update this comment and CHECK in the CobaltService constructor
// when all client implementations provide a civil time converter.
std::unique_ptr<util::CivilTimeConverterInterface> civil_time_converter;
// |activity_listener|: The interface to receive information on the current device state.
std::unique_ptr<ActivityListenerInterface> activity_listener;
// |diagnostics|: The implementation to send diagnostic information about the functioning of the
// Cobalt Core library.
std::unique_ptr<DiagnosticsInterface> diagnostics;
// |enable_replacement_metrics|: Determines whether or not replacement_metric_id should be honored
bool enable_replacement_metrics = false;
// |start_worker_threads|: Determines whether or not to start the worker threads.
bool start_worker_threads = true;
// |experiment_tokens|: A list of experiment tokens which the shuffler can convert to experiment
// ids.
std::vector<cobalt::ExperimentToken> experiment_tokens;
// |experiment_ids|: A list of experiments that are active on the device.
std::vector<int64_t> experiment_ids;
};
} // namespace cobalt
#endif // COBALT_SRC_PUBLIC_COBALT_CONFIG_H_