blob: 5aea1c1faca86215e758db35cc55ee0de95545e0 [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.
// This file contains a library to be used by users of Cobalt in order to
// collect metrics at a high frequency. The main building blocks are the
// ObservationsCollector and Counter classes.
//
// Example: counting function calls
//
// ObservationsCollector collector(send_to_cobalt_function_pointer,
// kDefaultEncodingId);
//
// auto foo_calls = collector.MakeCounter("foo_calls");
// auto foo_calls = collector.MakeCounter("bar_calls");
//
// // Perform aggregation and send to Cobalt FIDL service every 1 second.
// collector.Start(std::chrono::seconds(1));
//
// void Foo() {
// foo_calls.Increment();
// DoSomeFooWork
// ...
// }
//
// void Bar() {
// bar_calls.Increment();
// DoSomeBarWork
// ...
// }
#ifndef COBALT_CLIENT_COLLECTION_OBSERVATIONS_COLLECTOR_H_
#define COBALT_CLIENT_COLLECTION_OBSERVATIONS_COLLECTOR_H_
#include <atomic>
#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include "client/collection/observation.h"
namespace cobalt {
namespace client {
// An SendObservationsFn is a callable object that takes a pointer to a vector
// of observations and returns a list of the observation indices for
// observations that failed to be sent.
typedef std::function<std::vector<size_t>(std::vector<Observation>*)>
SendObservationsFn;
// A Counter allows you to keep track of the number of times an event has
// occured. Every counter has an associated metric part.
// A Counter can be incremented from an arbitrary number of threads.
class Counter {
public:
// Increments the counter by 1.
inline void Increment() { counter_++; }
private:
friend class MetricObservers;
// Make a counter with the specified part name.
static std::shared_ptr<Counter> Make(const std::string& part_name,
uint32_t encoding_id) {
return std::shared_ptr<Counter>(new Counter(part_name, encoding_id));
}
explicit Counter(const std::string& part_name, uint32_t encoding_id)
: counter_(0), part_name_(part_name), encoding_id_(encoding_id) {}
// Returns an integer ObservationPart and sets the counter's value to 0.
// If the ObservationPart undo function is called, the counter's value is
// added back on top of the counter.
ObservationPart GetObservationPart();
std::atomic<int64_t> counter_;
std::string part_name_;
uint32_t encoding_id_;
};
// A MetricObservers allows you to group together several observers that
// correspond to metric parts.
class MetricObservers {
public:
// Makes a Counter associated with this metric.
// The part_name specified must correspond to an integer part name.
// The encoding_id specified must be the id of an encoding in the cobalt
// config.
std::shared_ptr<Counter> MakeCounter(const std::string& part_name,
uint32_t encoding_id);
private:
friend class ObservationsCollector;
static std::shared_ptr<MetricObservers> Make(uint32_t id);
explicit MetricObservers(uint32_t id) : id_(id) {}
// Gets the Observation.
Observation GetObservation();
// MetricObservers id.
uint32_t id_;
// Map of counters part_name -> Counter.
std::map<std::string, std::shared_ptr<Counter>> counters_;
};
// A ObservationsCollector tracks various metrics, collects their values into
// observations and sends them.
class ObservationsCollector {
public:
// send_observations will be used to send the collected observations.
// default_encoding_id is the encoding id used unless another one is
// specified.
explicit ObservationsCollector(SendObservationsFn send_observations,
uint32_t default_encoding_id)
: send_observations_(send_observations),
default_encoding_id_(default_encoding_id) {}
// Makes a Counter object for the specified metric id, part name and to be
// encoded using the default encoding id.
std::shared_ptr<Counter> MakeCounter(uint32_t metric_id,
const std::string& part_name);
// Makes a Counter object for the specified metric id, part name and to be
// encoded using the specified encoding id.
std::shared_ptr<Counter> MakeCounter(uint32_t metric_id,
const std::string& part_name,
uint32_t encoding_id);
// Starts a new thread that collects and attempts to send metrics every
// |collection_interval|.
// Calling Start more than once without first calling Stop has undefined
// behavior.
void Start(std::chrono::nanoseconds collection_interval);
// Instructs the collection thread started by Start to stop and joins that
// thread.
void Stop();
// CollectAll attempts to collect observations for all MetricObservers
// created with this collector and send them using |send_observations|.
void CollectAll();
private:
std::shared_ptr<MetricObservers> GetMetricObservers(uint32_t id);
void CollectLoop(std::chrono::nanoseconds collection_interval);
// Map of metric id -> MetricObservers.
std::map<uint32_t, std::shared_ptr<MetricObservers>> metrics_;
// Thread on which the collection loop is run.
std::thread collection_loop_;
// Set to false to stop collection.
bool collection_loop_continue_;
// Call this function to send observations.
SendObservationsFn send_observations_;
// The encoding id to be used when none is specified.
uint32_t default_encoding_id_;
};
} // namespace client
} // namespace cobalt
#endif // COBALT_CLIENT_COLLECTION_OBSERVATIONS_COLLECTOR_H_