| #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_ |