blob: b84e7ba4ad9ff8a7f85c6567c7c656945a66bdfd [file] [log] [blame]
#ifndef THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_LOG_MONITORING_H_
#define THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_LOG_MONITORING_H_
#include <cstddef>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/log/log.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include <source_location>
#include "monitoring.h"
namespace milotic::metrics {
namespace internal {
template <typename T>
struct CopyType {
using type = T;
};
template <>
struct CopyType<absl::string_view> {
using type = std::string;
};
template <typename Array, typename Tuple, size_t... Index>
std::string PrintFields(const Array& names, const Tuple& values,
std::index_sequence<Index...> index) {
return absl::StrJoin(std::make_tuple(std::make_pair(
std::get<Index>(names), std::get<Index>(values))...),
", ", absl::PairFormatter("="));
}
template <typename... FieldT>
class GenericLogMetric {
public:
explicit GenericLogMetric(absl::string_view name,
FieldNames<FieldT...> field_names)
: name_(name), field_names_(field_names) {}
template <class Value>
void Log(Value value, const FieldValues<FieldT...>& field_values,
const std::source_location& loc) {
if constexpr (sizeof...(FieldT) == 0) {
LOG(INFO).AtLocation(loc.file_name(), static_cast<int>(loc.line())) << name_ << ": " << value;
} else {
LOG(INFO).AtLocation(loc.file_name(), static_cast<int>(loc.line()))
<< name_ << "("
<< PrintFields(field_names_, field_values,
std::index_sequence_for<FieldT...>())
<< "): " << value;
}
}
private:
std::string name_;
FieldNames<FieldT...> field_names_;
};
} // namespace internal
template <typename... FieldT>
struct Latency<FieldT...>::ImplData {
internal::GenericLogMetric<FieldT...> metric;
explicit ImplData(absl::string_view name, FieldNames<FieldT...> field_names)
: metric(name, std::move(field_names)) {}
};
template <typename... FieldT>
Latency<FieldT...>::~Latency() = default;
template <typename... FieldT>
Latency<FieldT...>::Latency(absl::string_view name,
FieldNames<FieldT...> field_names,
const CreationOptions& options)
: data_(std::make_unique<ImplData>(name, std::move(field_names))) {}
template <typename... FieldT>
void Latency<FieldT...>::Set(absl::Duration latency,
const FieldValues<FieldT...>& field_values,
const std::source_location& location) {
data_->metric.Log(latency, field_values, location);
}
template <typename... FieldT>
struct EventCounter<FieldT...>::ImplData {
internal::GenericLogMetric<FieldT...> metric;
absl::Mutex mutex;
using FieldTuple = std::tuple<typename internal::CopyType<FieldT>::type...>;
absl::flat_hash_map<FieldTuple, int> counters ABSL_GUARDED_BY(mutex);
ImplData(absl::string_view name, FieldNames<FieldT...> field_names)
: metric(name, std::move(field_names)) {}
};
template <typename... FieldT>
EventCounter<FieldT...>::EventCounter(absl::string_view name,
FieldNames<FieldT...> field_names,
const CreationOptions& options)
: data_(std::make_unique<ImplData>(name, std::move(field_names))) {}
template <typename... FieldT>
EventCounter<FieldT...>::~EventCounter() = default;
template <typename... FieldT>
void EventCounter<FieldT...>::Increment(
const FieldValues<FieldT...>& field_values,
const std::source_location& location) {
using FieldTuple = std::tuple<typename internal::CopyType<FieldT>::type...>;
int count;
{
absl::MutexLock lock(&data_->mutex);
FieldTuple field_tuple = std::make_from_tuple<FieldTuple>(field_values);
count = ++data_->counters[field_tuple];
}
data_->metric.Log(count, field_values, location);
}
template <typename... FieldT>
struct State<FieldT...>::ImplData {
internal::GenericLogMetric<FieldT...> metric;
absl::Mutex mutex;
absl::flat_hash_map<FieldValues<FieldT...>, std::string> prev_state
ABSL_GUARDED_BY(mutex);
ImplData(absl::string_view name, FieldNames<FieldT...> field_names)
: metric(name, std::move(field_names)) {}
};
template <typename... FieldT>
State<FieldT...>::State(absl::string_view name,
FieldNames<FieldT...> field_names,
const CreationOptions& options)
: data_(std::make_unique<ImplData>(name, std::move(field_names))) {}
template <typename... FieldT>
State<FieldT...>::~State() = default;
template <typename... FieldT>
void State<FieldT...>::SetState(absl::string_view state,
const FieldValues<FieldT...>& field_values,
const std::source_location& location) {
{
absl::MutexLock lock(&data_->mutex);
std::string& prev_state = data_->prev_state[field_values];
if (prev_state == state) return;
prev_state = state;
}
data_->metric.Log(state, field_values, location);
}
}; // namespace milotic::metrics
#endif // THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_LOG_MONITORING_H_