// See the file "COPYING" in the main distribution directory for copyright. #pragma once #include #include #include #include #include #include #include "zeek/IntrusivePtr.h" #include "zeek/Span.h" namespace zeek { class TableVal; using TableValPtr = zeek::IntrusivePtr; namespace telemetry { class Counter; using CounterPtr = std::shared_ptr; class CounterFamily; using CounterFamilyPtr = std::shared_ptr; class HistogramFamily; using HistogramFamilyPtr = std::shared_ptr; using LabelView = std::pair; } // namespace telemetry namespace cluster { class Backend; namespace detail { enum class TelemetryScope { Core, WebSocket, }; /** * Extra information of the serialized version of an Event. */ class SerializationInfo { public: explicit SerializationInfo(size_t size) : size(size) {} size_t Size() const { return size; } private: size_t size; }; using TopicNormalizer = std::function; using LabelList = std::vector>; using LabelViewList = std::vector>; /** * A topic normalizer using the Cluster::Telemetry::topic_normalizations table. */ class TableTopicNormalizer { public: TableTopicNormalizer(); std::string_view operator()(std::string_view topic); private: zeek::TableValPtr topic_normalizations; }; class Telemetry { public: virtual ~Telemetry() = default; virtual void OnOutgoingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) = 0; virtual void OnIncomingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) = 0; }; using TelemetryPtr = std::unique_ptr; // Reporting nothing. class NullTelemetry : public Telemetry { void OnOutgoingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override {} void OnIncomingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override {} }; // A container for telemetry instances, delegating to its children. class CompositeTelemetry : public Telemetry { public: void OnOutgoingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override { for ( const auto& c : children ) c->OnOutgoingEvent(topic, handler_name, info); } void OnIncomingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override { for ( const auto& c : children ) c->OnIncomingEvent(topic, handler_name, info); } void Add(TelemetryPtr child) { children.push_back(std::move(child)); } private: std::vector children; }; /** * Just one metric for incoming and one for outgoing metrics. */ class InfoTelemetry : public Telemetry { public: /** * * @param name The metric name without prefix. * @param static_labels Labels to add on all metrics. * @param prefix The metric prefix. */ InfoTelemetry(std::string_view name, LabelList static_labels, std::string_view prefix = "zeek"); void OnOutgoingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override; void OnIncomingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override; private: telemetry::CounterPtr in, out; }; /** * A telemetry class producing metrics labeled with handler names and topics. * * Note that randomly generated topic names will cause unbounded * metrics growth. A topic_normalizer should be injected to normalize * topic names. */ class VerboseTelemetry : public Telemetry { public: VerboseTelemetry(TopicNormalizer topic_normalizer, std::string_view name, LabelList static_labels, std::string_view prefix = "zeek"); void OnOutgoingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override; void OnIncomingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override; private: TopicNormalizer topic_normalizer; LabelList labels; LabelViewList labels_view; size_t topic_idx, handler_idx; // Index of topic and handler labels in labels_view telemetry::CounterFamilyPtr in, out; }; /** * A telemetry class producing metrics labeled with topics * and the script layer location for outgoing metrics. */ class DebugTelemetry : public Telemetry { public: DebugTelemetry(TopicNormalizer topic_normalizer, std::string_view name, LabelList static_labels, std::vector size_bounds, std::string_view prefix = "zeek"); void OnOutgoingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override; void OnIncomingEvent(std::string_view topic, std::string_view handler_name, const SerializationInfo& info) override; private: TopicNormalizer topic_normalizer; std::vector size_bounds; LabelList labels; LabelViewList labels_view; zeek::Span labels_view_no_location; size_t topic_idx, handler_idx, script_location_idx; // Index of topic, handler and script_location labels in labels_view telemetry::HistogramFamilyPtr in, out; }; /** * Reads Cluster::Telemetry consts, instantiates and appropriate Telemetry instance * set it on the given backend. * * @param backend The cluster backend to configure. * @param name The name used in the metric names. Either core or websocket at this point. * @param static_labels Static labels to attach to metrics. */ void configure_backend_telemetry(Backend& backend, std::string_view name, LabelList static_labels = {}); } // namespace detail } // namespace cluster } // namespace zeek