blob: f067566021c6f1903e57b0e34ab68c8b747ec94e [file] [log] [blame]
#ifndef THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_MONITORING_H_
#define THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_MONITORING_H_
#include <array>
#include <memory>
#include <tuple>
#include "absl/functional/function_ref.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include <source_location>
#include "request_response.h"
namespace milotic {
namespace metrics {
struct CreationOptions {
absl::string_view description;
};
template <typename... FieldT>
using FieldNames = std::array<absl::string_view, sizeof...(FieldT)>;
template <typename... FieldT>
using FieldValues = std::tuple<FieldT...>;
// Implementations should define the members of the following templates
template <typename... FieldT>
class Latency {
public:
explicit Latency(absl::string_view name, FieldNames<FieldT...> field_names,
const CreationOptions& options);
~Latency();
void Set(
absl::Duration latency, const FieldValues<FieldT...>& field_values,
const std::source_location& location = std::source_location::current());
private:
struct ImplData;
std::unique_ptr<ImplData> data_;
};
template <typename... FieldT>
class EventCounter {
public:
explicit EventCounter(absl::string_view name,
FieldNames<FieldT...> field_names,
const CreationOptions& options);
~EventCounter();
void Increment(
const FieldValues<FieldT...>& field_values,
const std::source_location& location = std::source_location::current());
private:
struct ImplData;
std::unique_ptr<ImplData> data_;
};
template <typename... FieldT>
class State {
public:
explicit State(absl::string_view name, FieldNames<FieldT...> field_names,
const CreationOptions& options);
~State();
void SetState(
absl::string_view state, const FieldValues<FieldT...>& field_values,
const std::source_location& location = std::source_location::current());
private:
struct ImplData;
std::unique_ptr<ImplData> data_;
};
// This exists mostly to enforce that a single implementation is linked.
extern const absl::string_view kImplementationName;
} // namespace metrics
template <typename... FieldT>
class LatencyMonitor {
public:
LatencyMonitor(
metrics::Latency<FieldT...>* request_latency,
metrics::FieldValues<FieldT...> field_values,
absl::FunctionRef<absl::Time()> now = absl::Now,
std::source_location location = std::source_location::current())
: now_(now),
request_latency_(request_latency),
field_values_(std::move(field_values)),
start_time_(now_()),
location_(location) {}
LatencyMonitor(const LatencyMonitor&) = delete;
LatencyMonitor& operator=(const LatencyMonitor&) = delete;
~LatencyMonitor() {
request_latency_->Set(now_() - start_time_, field_values_, location_);
}
private:
absl::FunctionRef<absl::Time()> now_;
metrics::Latency<FieldT...>* request_latency_;
metrics::FieldValues<FieldT...> field_values_;
absl::Time start_time_;
std::source_location location_;
};
template <typename... FieldT>
absl::StatusOr<ProxyResponse> CaptureResponseCode(
const absl::StatusOr<ProxyResponse>& http_response,
metrics::EventCounter<absl::string_view, int, FieldT...>* event_counter,
absl::string_view url, metrics::FieldValues<FieldT...> field_values,
const std::source_location& location = std::source_location::current()) {
if (http_response.ok()) {
event_counter->Increment(
std::tuple_cat(std::make_tuple(url, http_response->code),
std::move(field_values)),
location);
}
return http_response;
}
template <typename... FieldT>
LatencyMonitor(metrics::Latency<FieldT...>*,
metrics::FieldValues<FieldT...>) -> LatencyMonitor<FieldT...>;
} // namespace milotic
#endif // THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_MONITORING_H_