mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Add scaffold for new metrics API with counters
This commit is contained in:
parent
a5e7b2fec7
commit
617e4137c6
9 changed files with 1049 additions and 0 deletions
|
@ -159,6 +159,7 @@ set(bro_PLUGIN_DEPS CACHE INTERNAL "plugin dependencies" FORCE)
|
||||||
add_subdirectory(analyzer)
|
add_subdirectory(analyzer)
|
||||||
add_subdirectory(packet_analysis)
|
add_subdirectory(packet_analysis)
|
||||||
add_subdirectory(broker)
|
add_subdirectory(broker)
|
||||||
|
add_subdirectory(telemetry)
|
||||||
add_subdirectory(zeekygen)
|
add_subdirectory(zeekygen)
|
||||||
add_subdirectory(file_analysis)
|
add_subdirectory(file_analysis)
|
||||||
add_subdirectory(input)
|
add_subdirectory(input)
|
||||||
|
|
224
src/Span.h
Normal file
224
src/Span.h
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace zeek {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop-in replacement for C++20's @c std::span with dynamic extent only:
|
||||||
|
* https://en.cppreference.com/w/cpp/container/span. After upgrading to C++20,
|
||||||
|
* this class may get replaced with a type alias instead and/or deprecated.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
class Span {
|
||||||
|
public:
|
||||||
|
// -- member types ---------------------------------------------------------
|
||||||
|
|
||||||
|
using element_type = T;
|
||||||
|
|
||||||
|
using value_type = typename std::remove_cv<T>::type;
|
||||||
|
|
||||||
|
using index_type = size_t;
|
||||||
|
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
|
||||||
|
using pointer = T*;
|
||||||
|
|
||||||
|
using const_pointer = const T*;
|
||||||
|
|
||||||
|
using reference = T&;
|
||||||
|
|
||||||
|
using const_reference = T&;
|
||||||
|
|
||||||
|
using iterator = pointer;
|
||||||
|
|
||||||
|
using const_iterator = const_pointer;
|
||||||
|
|
||||||
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
|
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
|
// -- constructors, destructors, and assignment operators ------------------
|
||||||
|
|
||||||
|
constexpr Span() noexcept : memoryBlock(nullptr), numElements(0)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Span(pointer ptr, size_t size)
|
||||||
|
: memoryBlock(ptr), numElements(size)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Span(pointer first, pointer last)
|
||||||
|
: memoryBlock(first), numElements(static_cast<size_t>(last - first))
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t Size>
|
||||||
|
constexpr Span(element_type (&arr)[Size]) noexcept
|
||||||
|
: memoryBlock(arr), numElements(Size)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Container,
|
||||||
|
class Data = typename Container::value_type,
|
||||||
|
class = std::enable_if_t<std::is_convertible_v<Data*, T*>>>
|
||||||
|
Span(Container& xs) noexcept
|
||||||
|
: memoryBlock(xs.data()), numElements(xs.size())
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Container,
|
||||||
|
class Data = typename Container::value_type,
|
||||||
|
class = std::enable_if_t<std::is_convertible_v<const Data*, T*>>>
|
||||||
|
Span(const Container& xs) noexcept
|
||||||
|
: memoryBlock(xs.data()), numElements(xs.size())
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Span(const Span&) noexcept = default;
|
||||||
|
|
||||||
|
Span& operator=(const Span&) noexcept = default;
|
||||||
|
|
||||||
|
// -- iterators ------------------------------------------------------------
|
||||||
|
|
||||||
|
constexpr iterator begin() const noexcept
|
||||||
|
{
|
||||||
|
return memoryBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_iterator cbegin() const noexcept
|
||||||
|
{
|
||||||
|
return memoryBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator end() const noexcept
|
||||||
|
{
|
||||||
|
return begin() + numElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_iterator cend() const noexcept
|
||||||
|
{
|
||||||
|
return cbegin() + numElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reverse_iterator rbegin() const noexcept
|
||||||
|
{
|
||||||
|
return reverse_iterator{end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_reverse_iterator crbegin() const noexcept
|
||||||
|
{
|
||||||
|
return const_reverse_iterator{end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reverse_iterator rend() const noexcept
|
||||||
|
{
|
||||||
|
return reverse_iterator{begin()};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const_reverse_iterator crend() const noexcept
|
||||||
|
{
|
||||||
|
return const_reverse_iterator{begin()};
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- element access -------------------------------------------------------
|
||||||
|
|
||||||
|
constexpr reference operator[](size_t index) const noexcept
|
||||||
|
{
|
||||||
|
return memoryBlock[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reference front() const noexcept
|
||||||
|
{
|
||||||
|
return *memoryBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reference back() const noexcept
|
||||||
|
{
|
||||||
|
return (*this)[numElements - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- properties -----------------------------------------------------------
|
||||||
|
|
||||||
|
constexpr size_t size() const noexcept
|
||||||
|
{
|
||||||
|
return numElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t numElementsbytes() const noexcept
|
||||||
|
{
|
||||||
|
return numElements * sizeof(element_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return numElements == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr pointer data() const noexcept
|
||||||
|
{
|
||||||
|
return memoryBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- subviews -------------------------------------------------------------
|
||||||
|
|
||||||
|
constexpr Span subspan(size_t offset, size_t num_bytes) const
|
||||||
|
{
|
||||||
|
return {memoryBlock + offset, num_bytes};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Span subspan(size_t offset) const
|
||||||
|
{
|
||||||
|
return {memoryBlock + offset, numElements - offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Span first(size_t num_bytes) const
|
||||||
|
{
|
||||||
|
return {memoryBlock, num_bytes};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Span last(size_t num_bytes) const
|
||||||
|
{
|
||||||
|
return subspan(numElements - num_bytes, num_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// -- member variables -----------------------------------------------------
|
||||||
|
|
||||||
|
/// Points to the first element in the contiguous memory block.
|
||||||
|
pointer memoryBlock;
|
||||||
|
|
||||||
|
/// Stores the number of elements in the contiguous memory block.
|
||||||
|
size_t numElements;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- deduction guides ---------------------------------------------------------
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Span(T*, size_t) -> Span<T>;
|
||||||
|
|
||||||
|
template <class Iter>
|
||||||
|
Span(Iter, Iter) -> Span<typename std::iterator_traits<Iter>::value_type>;
|
||||||
|
|
||||||
|
template <class T, size_t N>
|
||||||
|
Span(T (&)[N]) -> Span<T>;
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
Span(Container&) -> Span<typename Container::value_type>;
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
Span(const Container&) -> Span<const typename Container::value_type>;
|
||||||
|
|
||||||
|
} // namespace zeek
|
20
src/telemetry/CMakeLists.txt
Normal file
20
src/telemetry/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
include(ZeekSubdir)
|
||||||
|
|
||||||
|
include_directories(BEFORE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(telemetry_SRCS
|
||||||
|
Counter.cc
|
||||||
|
Manager.cc
|
||||||
|
MetricFamily.cc
|
||||||
|
)
|
||||||
|
|
||||||
|
# bif_target(comm.bif)
|
||||||
|
# bif_target(data.bif)
|
||||||
|
# bif_target(messaging.bif)
|
||||||
|
# bif_target(store.bif)
|
||||||
|
|
||||||
|
bro_add_subdir_library(telemetry ${telemetry_SRCS})
|
||||||
|
|
164
src/telemetry/Counter.cc
Normal file
164
src/telemetry/Counter.cc
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "zeek/telemetry/Counter.h"
|
||||||
|
|
||||||
|
#include "caf/telemetry/counter.hpp"
|
||||||
|
#include "caf/telemetry/metric_family.hpp"
|
||||||
|
#include "caf/telemetry/metric_family_impl.hpp"
|
||||||
|
|
||||||
|
namespace zeek::telemetry {
|
||||||
|
|
||||||
|
// -- private utilities --------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace ct = caf::telemetry;
|
||||||
|
|
||||||
|
using NativeMetricFamily = ct::metric_family;
|
||||||
|
|
||||||
|
using NativeIntCounter = ct::int_counter;
|
||||||
|
|
||||||
|
using NativeIntCounterFamily = ct::metric_family_impl<NativeIntCounter>;
|
||||||
|
|
||||||
|
using NativeDblCounter = ct::dbl_counter;
|
||||||
|
|
||||||
|
using NativeDblCounterFamily = ct::metric_family_impl<NativeDblCounter>;
|
||||||
|
|
||||||
|
auto& deref(IntCounter::Impl* ptr)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<NativeIntCounter*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& deref(IntCounterFamily*, MetricFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto basePtr = reinterpret_cast<NativeMetricFamily*>(ptr);
|
||||||
|
return *static_cast<NativeIntCounterFamily*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto upcast(IntCounterFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto native = reinterpret_cast<NativeIntCounterFamily*>(ptr);
|
||||||
|
auto basePtr = static_cast<NativeMetricFamily*>(native);
|
||||||
|
return reinterpret_cast<MetricFamily::Impl*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeIntCounter* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<IntCounter::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& deref(DblCounter::Impl* ptr)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<ct::dbl_counter*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& deref(DblCounterFamily*, MetricFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto basePtr = reinterpret_cast<NativeMetricFamily*>(ptr);
|
||||||
|
return *static_cast<NativeDblCounterFamily*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto upcast(DblCounterFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto native = reinterpret_cast<NativeDblCounterFamily*>(ptr);
|
||||||
|
auto basePtr = static_cast<NativeMetricFamily*>(native);
|
||||||
|
return reinterpret_cast<MetricFamily::Impl*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeDblCounter* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<DblCounter::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
auto withNativeLabels(Span<const LabelView> xs, F continuation)
|
||||||
|
{
|
||||||
|
if (xs.size() <= 10)
|
||||||
|
{
|
||||||
|
ct::label_view buf[10]={
|
||||||
|
{{},{}}, {{},{}}, {{},{}}, {{},{}}, {{},{}},
|
||||||
|
{{},{}}, {{},{}}, {{},{}}, {{},{}}, {{},{}},
|
||||||
|
};
|
||||||
|
for (size_t index = 0; index < xs.size(); ++index)
|
||||||
|
buf[index] = ct::label_view{xs[index].first, xs[index].second};
|
||||||
|
return continuation(Span{buf, xs.size()});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<ct::label_view> buf;
|
||||||
|
for (auto x : xs)
|
||||||
|
buf.emplace_back(x.first, x.second);
|
||||||
|
return continuation(Span{buf});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// -- IntCounter ---------------------------------------------------------------
|
||||||
|
|
||||||
|
void IntCounter::inc() noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntCounter::inc(int64_t amount) noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t IntCounter::operator++() noexcept
|
||||||
|
{
|
||||||
|
return ++deref(pimpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t IntCounter::value() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
IntCounterFamily::IntCounterFamily(Impl* ptr) : MetricFamily(upcast(ptr))
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
IntCounter IntCounterFamily::getOrAdd(Span<const LabelView> labels)
|
||||||
|
{
|
||||||
|
return withNativeLabels(labels, [this](auto nativeLabels)
|
||||||
|
{
|
||||||
|
auto hdl = opaque(deref(this, pimpl).get_or_add(nativeLabels));
|
||||||
|
return IntCounter{hdl};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- DblCounter ---------------------------------------------------------------
|
||||||
|
|
||||||
|
void DblCounter::inc() noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DblCounter::inc(double amount) noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
double DblCounter::value() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
DblCounterFamily::DblCounterFamily(Impl* ptr) : MetricFamily(upcast(ptr))
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
DblCounter DblCounterFamily::getOrAdd(Span<const LabelView> labels)
|
||||||
|
{
|
||||||
|
return withNativeLabels(labels, [this](auto nativeLabels)
|
||||||
|
{
|
||||||
|
auto hdl = opaque(deref(this, pimpl).get_or_add(nativeLabels));
|
||||||
|
return DblCounter{hdl};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
236
src/telemetry/Counter.h
Normal file
236
src/telemetry/Counter.h
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "zeek/Span.h"
|
||||||
|
#include "zeek/telemetry/MetricFamily.h"
|
||||||
|
|
||||||
|
namespace zeek::telemetry {
|
||||||
|
|
||||||
|
class DblCounterFamily;
|
||||||
|
class IntCounterFamily;
|
||||||
|
class Manager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handle to a metric that represents an integer value that can only go up.
|
||||||
|
*/
|
||||||
|
class IntCounter {
|
||||||
|
public:
|
||||||
|
friend class IntCounterFamily;
|
||||||
|
|
||||||
|
struct Impl;
|
||||||
|
|
||||||
|
IntCounter() = delete;
|
||||||
|
IntCounter(const IntCounter&) noexcept = default;
|
||||||
|
IntCounter& operator=(const IntCounter&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by 1.
|
||||||
|
*/
|
||||||
|
void inc() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by @p amount.
|
||||||
|
* @pre `amount >= 0`
|
||||||
|
*/
|
||||||
|
void inc(int64_t amount) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by 1.
|
||||||
|
* @returns the new value.
|
||||||
|
*/
|
||||||
|
int64_t operator++() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the current value.
|
||||||
|
*/
|
||||||
|
int64_t value() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns whether @c this and @p other refer to the same counter.
|
||||||
|
*/
|
||||||
|
constexpr bool isSameAs(IntCounter other) const noexcept
|
||||||
|
{
|
||||||
|
return pimpl == other.pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit IntCounter(Impl* ptr) noexcept : pimpl(ptr)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
Impl* pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether two @ref IntCounter handles are identical.
|
||||||
|
* @returns whether @p lhs and @p rhs refer to the same object.
|
||||||
|
* @note compare their @c value instead to check for equality.
|
||||||
|
*/
|
||||||
|
constexpr bool operator==(IntCounter lhs, IntCounter rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.isSameAs(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @relates IntCounter
|
||||||
|
constexpr bool operator!=(IntCounter lhs, IntCounter rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages a collection of IntCounter metrics.
|
||||||
|
*/
|
||||||
|
class IntCounterFamily : public MetricFamily {
|
||||||
|
public:
|
||||||
|
friend class Manager;
|
||||||
|
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
IntCounterFamily(const IntCounterFamily&) noexcept = default;
|
||||||
|
IntCounterFamily& operator=(const IntCounterFamily&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the metrics handle for given labels, creating a new instance
|
||||||
|
* lazily if necessary.
|
||||||
|
*/
|
||||||
|
IntCounter getOrAdd(Span<const LabelView> labels);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copydoc getOrAdd
|
||||||
|
*/
|
||||||
|
IntCounter getOrAdd(std::initializer_list<LabelView> labels)
|
||||||
|
{
|
||||||
|
return getOrAdd(Span{labels.begin(), labels.size()});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit IntCounterFamily(Impl* ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handle to a metric that represents a floating point value that can only go
|
||||||
|
* up.
|
||||||
|
*/
|
||||||
|
class DblCounter {
|
||||||
|
public:
|
||||||
|
friend class DblCounterFamily;
|
||||||
|
|
||||||
|
struct Impl;
|
||||||
|
|
||||||
|
DblCounter() = delete;
|
||||||
|
DblCounter(const DblCounter&) noexcept = default;
|
||||||
|
DblCounter& operator=(const DblCounter&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by 1.
|
||||||
|
*/
|
||||||
|
void inc() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by @p amount.
|
||||||
|
* @pre `amount >= 0`
|
||||||
|
*/
|
||||||
|
void inc(double amount) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the current value.
|
||||||
|
*/
|
||||||
|
double value() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns whether @c this and @p other refer to the same counter.
|
||||||
|
*/
|
||||||
|
constexpr bool isSameAs(DblCounter other) const noexcept
|
||||||
|
{
|
||||||
|
return pimpl == other.pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit DblCounter(Impl* ptr) noexcept : pimpl(ptr)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
Impl* pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether two @ref DblCounter handles are identical.
|
||||||
|
* @returns whether @p lhs and @p rhs refer to the same object.
|
||||||
|
* @note compare their @c value instead to check for equality.
|
||||||
|
*/
|
||||||
|
constexpr bool operator==(DblCounter lhs, DblCounter rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.isSameAs(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @relates DblCounter
|
||||||
|
constexpr bool operator!=(DblCounter lhs, DblCounter rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages a collection of DblCounter metrics.
|
||||||
|
*/
|
||||||
|
class DblCounterFamily : public MetricFamily {
|
||||||
|
public:
|
||||||
|
friend class Manager;
|
||||||
|
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
DblCounterFamily(const DblCounterFamily&) noexcept = default;
|
||||||
|
DblCounterFamily& operator=(const DblCounterFamily&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the metrics handle for given labels, creating a new instance
|
||||||
|
* lazily if necessary.
|
||||||
|
*/
|
||||||
|
DblCounter getOrAdd(Span<const LabelView> labels);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copydoc getOrAdd
|
||||||
|
*/
|
||||||
|
DblCounter getOrAdd(std::initializer_list<LabelView> labels)
|
||||||
|
{
|
||||||
|
return getOrAdd(Span{labels.begin(), labels.size()});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit DblCounterFamily(Impl* ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct CounterOracle {
|
||||||
|
static_assert(std::is_same<T, int64_t>::value,
|
||||||
|
"Counter<T> only supports int64_t and double");
|
||||||
|
|
||||||
|
using type = IntCounter;
|
||||||
|
|
||||||
|
using family_type = IntCounterFamily;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct CounterOracle<double> {
|
||||||
|
using type = DblCounter;
|
||||||
|
|
||||||
|
using family_type = DblCounterFamily;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using Counter = typename detail::CounterOracle<T>::type;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using CounterFamily = typename detail::CounterOracle<T>::family_type;
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
159
src/telemetry/Manager.cc
Normal file
159
src/telemetry/Manager.cc
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "zeek/telemetry/Manager.h"
|
||||||
|
|
||||||
|
#include "caf/telemetry/metric_registry.hpp"
|
||||||
|
|
||||||
|
#include "zeek/3rdparty/doctest.h"
|
||||||
|
|
||||||
|
namespace zeek::telemetry {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace ct = caf::telemetry;
|
||||||
|
|
||||||
|
using NativeManager = ct::metric_registry;
|
||||||
|
|
||||||
|
using NativeIntCounter = ct::int_counter;
|
||||||
|
|
||||||
|
using NativeIntCounterFamily = ct::metric_family_impl<NativeIntCounter>;
|
||||||
|
|
||||||
|
using NativeDblCounter = ct::dbl_counter;
|
||||||
|
|
||||||
|
using NativeDblCounterFamily = ct::metric_family_impl<NativeDblCounter>;
|
||||||
|
|
||||||
|
auto& deref(Manager::Impl* ptr)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<NativeManager*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeManager* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Manager::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeIntCounterFamily* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<IntCounterFamily::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeDblCounterFamily* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<DblCounterFamily::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
auto withNative(Span<const std::string_view> xs, F continuation)
|
||||||
|
{
|
||||||
|
if (xs.size() <= 10)
|
||||||
|
{
|
||||||
|
caf::string_view buf[10];
|
||||||
|
for (size_t index = 0; index < xs.size(); ++index)
|
||||||
|
buf[index] = xs[index];
|
||||||
|
return continuation(Span{buf, xs.size()});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<caf::string_view> buf;
|
||||||
|
for (auto x : xs)
|
||||||
|
buf.emplace_back(x);
|
||||||
|
return continuation(Span{buf});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
IntCounterFamily Manager::intCounterFam(std::string_view prefix,
|
||||||
|
std::string_view name,
|
||||||
|
Span<const std::string_view> labels,
|
||||||
|
std::string_view helptext,
|
||||||
|
std::string_view unit, bool isSum)
|
||||||
|
{
|
||||||
|
return withNative(labels, [&, this](auto xs)
|
||||||
|
{
|
||||||
|
auto ptr = deref(pimpl).counter_family(prefix, name, xs,
|
||||||
|
helptext, unit, isSum);
|
||||||
|
return IntCounterFamily{opaque(ptr)};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
DblCounterFamily Manager::dblCounterFam(std::string_view prefix,
|
||||||
|
std::string_view name,
|
||||||
|
Span<const std::string_view> labels,
|
||||||
|
std::string_view helptext,
|
||||||
|
std::string_view unit, bool isSum)
|
||||||
|
{
|
||||||
|
return withNative(labels, [&, this](auto xs)
|
||||||
|
{
|
||||||
|
auto ptr = deref(pimpl).counter_family<double>(prefix, name, xs,
|
||||||
|
helptext, unit, isSum);
|
||||||
|
return DblCounterFamily{opaque(ptr)};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
||||||
|
|
||||||
|
// -- unit tests ---------------------------------------------------------------
|
||||||
|
|
||||||
|
using namespace zeek::telemetry;
|
||||||
|
|
||||||
|
SCENARIO("telemetry managers provide access to counters")
|
||||||
|
{
|
||||||
|
GIVEN("a telemetry manager")
|
||||||
|
{
|
||||||
|
NativeManager nativeMgr;
|
||||||
|
Manager mgr{opaque(&nativeMgr)};
|
||||||
|
WHEN("retrieving an IntCounter singleton")
|
||||||
|
{
|
||||||
|
auto first = mgr.counterSingleton("zeek", "int-count", "test");
|
||||||
|
THEN("its initial value is zero")
|
||||||
|
{
|
||||||
|
CHECK_EQ(first.value(), 0);
|
||||||
|
}
|
||||||
|
AND_THEN("calling inc() or operator++ changes the value")
|
||||||
|
{
|
||||||
|
first.inc();
|
||||||
|
CHECK_EQ(first.value(), 1);
|
||||||
|
first.inc(2);
|
||||||
|
CHECK_EQ(first.value(), 3);
|
||||||
|
CHECK_EQ(++first, 4);
|
||||||
|
CHECK_EQ(first.value(), 4);
|
||||||
|
}
|
||||||
|
AND_THEN("calling counterSingleton again for the same name returns the same handle")
|
||||||
|
{
|
||||||
|
auto second = mgr.counterSingleton("zeek", "int-count", "test");
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("calling counterSingleton for a different name returns another handle")
|
||||||
|
{
|
||||||
|
auto third = mgr.counterSingleton("zeek", "int-count-2", "test");
|
||||||
|
CHECK_NE(first, third);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WHEN("retrieving a DblCounter singleton")
|
||||||
|
{
|
||||||
|
auto first = mgr.counterSingleton<double>("zeek", "dbl-count", "test");
|
||||||
|
THEN("its initial value is zero")
|
||||||
|
{
|
||||||
|
CHECK_EQ(first.value(), 0.0);
|
||||||
|
}
|
||||||
|
AND_THEN("calling inc() changes the value")
|
||||||
|
{
|
||||||
|
first.inc();
|
||||||
|
CHECK_EQ(first.value(), 1.0);
|
||||||
|
first.inc(3.0);
|
||||||
|
CHECK_EQ(first.value(), 4.0);
|
||||||
|
}
|
||||||
|
AND_THEN("calling counterSingleton again for the same name returns the same handle")
|
||||||
|
{
|
||||||
|
auto second = mgr.counterSingleton<double>("zeek", "dbl-count", "test");
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("calling counterSingleton for a different name returns another handle")
|
||||||
|
{
|
||||||
|
auto third = mgr.counterSingleton<double>("zeek", "dbl-count-2", "test");
|
||||||
|
CHECK_NE(first, third);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
168
src/telemetry/Manager.h
Normal file
168
src/telemetry/Manager.h
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "zeek/Span.h"
|
||||||
|
#include "zeek/telemetry/Counter.h"
|
||||||
|
|
||||||
|
namespace zeek::telemetry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages a collection of metric families.
|
||||||
|
*/
|
||||||
|
class Manager {
|
||||||
|
public:
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
explicit Manager(Impl* ptr) : pimpl(ptr)
|
||||||
|
{
|
||||||
|
//nop
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager(const Manager&) = delete;
|
||||||
|
|
||||||
|
Manager& operator=(const Manager&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns a counter metric family. Creates the family lazily if necessary.
|
||||||
|
* @param prefix The prefix (namespace) this family belongs to.
|
||||||
|
* @param name The human-readable name of the metric, e.g., `requests`.
|
||||||
|
* @param labels Names for all label dimensions of the metric.
|
||||||
|
* @param helptext Short explanation of the metric.
|
||||||
|
* @param unit Unit of measurement.
|
||||||
|
* @param isSum Indicates whether this metric accumulates something, where
|
||||||
|
* only the total value is of interest.
|
||||||
|
*/
|
||||||
|
template <class ValueType = int64_t>
|
||||||
|
CounterFamily<ValueType>
|
||||||
|
counterFamily(std::string_view prefix, std::string_view name,
|
||||||
|
Span<const std::string_view> labels,
|
||||||
|
std::string_view helptext,
|
||||||
|
std::string_view unit = "1", bool isSum = false) {
|
||||||
|
if constexpr (std::is_same<ValueType, int64_t>::value)
|
||||||
|
{
|
||||||
|
return intCounterFam(prefix, name, labels, helptext, unit, isSum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<ValueType, double>::value,
|
||||||
|
"metrics only support int64_t and double values");
|
||||||
|
return dblCounterFam(prefix, name, labels, helptext, unit, isSum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc counterFamily
|
||||||
|
template <class ValueType = int64_t>
|
||||||
|
CounterFamily<ValueType>
|
||||||
|
counterFamily(std::string_view prefix, std::string_view name,
|
||||||
|
std::initializer_list<std::string_view> labels,
|
||||||
|
std::string_view helptext, std::string_view unit = "1",
|
||||||
|
bool isSum = false)
|
||||||
|
{
|
||||||
|
auto lblSpan = Span{labels.begin(), labels.size()};
|
||||||
|
return counterFamily<ValueType>(prefix, name, lblSpan, helptext,
|
||||||
|
unit, isSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accesses a counter instance. Creates the hosting metric family as well
|
||||||
|
* as the counter lazily if necessary.
|
||||||
|
* @param prefix The prefix (namespace) this family belongs to.
|
||||||
|
* @param name The human-readable name of the metric, e.g., `requests`.
|
||||||
|
* @param labels Values for all label dimensions of the metric.
|
||||||
|
* @param helptext Short explanation of the metric.
|
||||||
|
* @param unit Unit of measurement.
|
||||||
|
* @param isSum Indicates whether this metric accumulates something, where
|
||||||
|
* only the total value is of interest.
|
||||||
|
*/
|
||||||
|
template <class ValueType = int64_t>
|
||||||
|
Counter<ValueType>
|
||||||
|
counterInstance(std::string_view prefix, std::string_view name,
|
||||||
|
Span<const LabelView> labels, std::string_view helptext,
|
||||||
|
std::string_view unit = "1", bool isSum = false)
|
||||||
|
{
|
||||||
|
return withLabelNames(labels, [&, this](auto labelNames)
|
||||||
|
{
|
||||||
|
auto family = counterFamily<ValueType>(prefix, name, labelNames,
|
||||||
|
helptext, unit, isSum);
|
||||||
|
return family.getOrAdd(labels);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc counterInstance
|
||||||
|
template <class ValueType = int64_t>
|
||||||
|
Counter<ValueType>
|
||||||
|
counterInstance(std::string_view prefix, std::string_view name,
|
||||||
|
std::initializer_list<LabelView> labels,
|
||||||
|
std::string_view helptext, std::string_view unit = "1",
|
||||||
|
bool isSum = false)
|
||||||
|
{
|
||||||
|
auto lblSpan = Span{labels.begin(), labels.size()};
|
||||||
|
return counterInstance(prefix, name, lblSpan, helptext, unit, isSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accesses a counter singleton, i.e., a counter that belongs to a family
|
||||||
|
* without label dimensions (which thus only has a single member). Creates
|
||||||
|
* the hosting metric family as well as the counter lazily if necessary.
|
||||||
|
* @param prefix The prefix (namespace) this family belongs to.
|
||||||
|
* @param name The human-readable name of the metric, e.g., `requests`.
|
||||||
|
* @param helptext Short explanation of the metric.
|
||||||
|
* @param unit Unit of measurement.
|
||||||
|
* @param isSum Indicates whether this metric accumulates something, where
|
||||||
|
* only the total value is of interest.
|
||||||
|
*/
|
||||||
|
template <class ValueType = int64_t>
|
||||||
|
Counter<ValueType>
|
||||||
|
counterSingleton(std::string_view prefix, std::string_view name,
|
||||||
|
std::string_view helptext, std::string_view unit = "1",
|
||||||
|
bool isSum = false)
|
||||||
|
{
|
||||||
|
auto labels = Span<const std::string_view>{};
|
||||||
|
auto fam = counterFamily<ValueType>(prefix, name, labels, helptext,
|
||||||
|
unit, isSum);
|
||||||
|
return fam.getOrAdd({});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IntCounterFamily
|
||||||
|
intCounterFam(std::string_view prefix, std::string_view name,
|
||||||
|
Span<const std::string_view> labels,
|
||||||
|
std::string_view helptext, std::string_view unit, bool isSum);
|
||||||
|
|
||||||
|
DblCounterFamily
|
||||||
|
dblCounterFam(std::string_view prefix, std::string_view name,
|
||||||
|
Span<const std::string_view> labels,
|
||||||
|
std::string_view helptext, std::string_view unit, bool isSum);
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
static void withLabelNames(Span<const LabelView> xs, F continuation)
|
||||||
|
{
|
||||||
|
if (xs.size() <= 10) {
|
||||||
|
std::string_view buf[10];
|
||||||
|
for (size_t index = 0; index < xs.size(); ++index)
|
||||||
|
buf[index] = xs[index].first;
|
||||||
|
return continuation(Span{buf, xs.size()});
|
||||||
|
} else {
|
||||||
|
std::vector<std::string_view> buf;
|
||||||
|
for (auto x : xs)
|
||||||
|
buf.emplace_back(x.first, x.second);
|
||||||
|
return continuation(Span{buf});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Impl* pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
||||||
|
|
||||||
|
namespace zeek {
|
||||||
|
|
||||||
|
extern telemetry::Manager* telemetry_mgr;
|
||||||
|
|
||||||
|
} // namespace zeek
|
0
src/telemetry/MetricFamily.cc
Normal file
0
src/telemetry/MetricFamily.cc
Normal file
77
src/telemetry/MetricFamily.h
Normal file
77
src/telemetry/MetricFamily.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "Span.h"
|
||||||
|
|
||||||
|
namespace zeek::telemetry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A key-value pair for a single label dimension.
|
||||||
|
*/
|
||||||
|
using LabelView = std::pair<std::string_view, std::string_view>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages a collection (family) of metrics. All members of the family share
|
||||||
|
* the same prefix (namespace), name, and label dimensions.
|
||||||
|
*/
|
||||||
|
class MetricFamily {
|
||||||
|
public:
|
||||||
|
struct Impl;
|
||||||
|
|
||||||
|
MetricFamily() = delete;
|
||||||
|
MetricFamily(const MetricFamily&) noexcept = default;
|
||||||
|
MetricFamily& operator=(const MetricFamily&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the prefix (namespace) this family belongs to. Builtin metrics
|
||||||
|
* of Zeek return @c zeek. Custom metrics, e.g., created in a
|
||||||
|
* script, may use a prefix that represents the application/script
|
||||||
|
* or protocol (e.g. @c http) name.
|
||||||
|
*/
|
||||||
|
std::string_view prefix() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the human-readable name of the metric, e.g.,
|
||||||
|
* @p open-connections.
|
||||||
|
*/
|
||||||
|
std::string_view name() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the names for all label dimensions.
|
||||||
|
*/
|
||||||
|
Span<const std::string> label_names() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns a short explanation of the metric.
|
||||||
|
*/
|
||||||
|
std::string_view helptext() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the unit of measurement, preferably a base unit such as
|
||||||
|
* @c bytes or @c seconds. Dimensionless counts return the
|
||||||
|
* pseudo-unit @c 1.
|
||||||
|
*/
|
||||||
|
std::string_view unit() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns whether metrics of this family accumulate values, where only the
|
||||||
|
* total value is of interest. For example, the total number of
|
||||||
|
* HTTP requests.
|
||||||
|
*/
|
||||||
|
bool isSum() const noexcept;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit MetricFamily(Impl* ptr) : pimpl(ptr)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
Impl* pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
Loading…
Add table
Add a link
Reference in a new issue