mirror of
https://github.com/zeek/zeek.git
synced 2025-10-12 19:48:20 +00:00
Add gauge metric types
This commit is contained in:
parent
617e4137c6
commit
59d114005e
7 changed files with 866 additions and 2 deletions
|
@ -7,6 +7,7 @@ include_directories(BEFORE
|
||||||
|
|
||||||
set(telemetry_SRCS
|
set(telemetry_SRCS
|
||||||
Counter.cc
|
Counter.cc
|
||||||
|
Gauge.cc
|
||||||
Manager.cc
|
Manager.cc
|
||||||
MetricFamily.cc
|
MetricFamily.cc
|
||||||
)
|
)
|
||||||
|
|
189
src/telemetry/Gauge.cc
Normal file
189
src/telemetry/Gauge.cc
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "zeek/telemetry/Gauge.h"
|
||||||
|
|
||||||
|
#include "caf/telemetry/gauge.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 NativeIntGauge = ct::int_gauge;
|
||||||
|
|
||||||
|
using NativeIntGaugeFamily = ct::metric_family_impl<NativeIntGauge>;
|
||||||
|
|
||||||
|
using NativeDblGauge = ct::dbl_gauge;
|
||||||
|
|
||||||
|
using NativeDblGaugeFamily = ct::metric_family_impl<NativeDblGauge>;
|
||||||
|
|
||||||
|
auto& deref(IntGauge::Impl* ptr)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<NativeIntGauge*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& deref(IntGaugeFamily*, MetricFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto basePtr = reinterpret_cast<NativeMetricFamily*>(ptr);
|
||||||
|
return *static_cast<NativeIntGaugeFamily*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto upcast(IntGaugeFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto native = reinterpret_cast<NativeIntGaugeFamily*>(ptr);
|
||||||
|
auto basePtr = static_cast<NativeMetricFamily*>(native);
|
||||||
|
return reinterpret_cast<MetricFamily::Impl*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeIntGauge* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<IntGauge::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& deref(DblGauge::Impl* ptr)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<ct::dbl_gauge*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& deref(DblGaugeFamily*, MetricFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto basePtr = reinterpret_cast<NativeMetricFamily*>(ptr);
|
||||||
|
return *static_cast<NativeDblGaugeFamily*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto upcast(DblGaugeFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
auto native = reinterpret_cast<NativeDblGaugeFamily*>(ptr);
|
||||||
|
auto basePtr = static_cast<NativeMetricFamily*>(native);
|
||||||
|
return reinterpret_cast<MetricFamily::Impl*>(basePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeDblGauge* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<DblGauge::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
|
||||||
|
|
||||||
|
// -- IntGauge ---------------------------------------------------------------
|
||||||
|
|
||||||
|
void IntGauge::inc() noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntGauge::inc(int64_t amount) noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntGauge::dec() noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).dec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntGauge::dec(int64_t amount) noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).dec(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t IntGauge::operator++() noexcept
|
||||||
|
{
|
||||||
|
return ++deref(pimpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t IntGauge::operator--() noexcept
|
||||||
|
{
|
||||||
|
return --deref(pimpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t IntGauge::value() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
IntGaugeFamily::IntGaugeFamily(Impl* ptr) : MetricFamily(upcast(ptr))
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
IntGauge IntGaugeFamily::getOrAdd(Span<const LabelView> labels)
|
||||||
|
{
|
||||||
|
return withNativeLabels(labels, [this](auto nativeLabels)
|
||||||
|
{
|
||||||
|
auto hdl = opaque(deref(this, pimpl).get_or_add(nativeLabels));
|
||||||
|
return IntGauge{hdl};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- DblGauge ---------------------------------------------------------------
|
||||||
|
|
||||||
|
void DblGauge::inc() noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DblGauge::inc(double amount) noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).inc(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DblGauge::dec() noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).dec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DblGauge::dec(double amount) noexcept
|
||||||
|
{
|
||||||
|
deref(pimpl).dec(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
double DblGauge::value() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
DblGaugeFamily::DblGaugeFamily(Impl* ptr) : MetricFamily(upcast(ptr))
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
DblGauge DblGaugeFamily::getOrAdd(Span<const LabelView> labels)
|
||||||
|
{
|
||||||
|
return withNativeLabels(labels, [this](auto nativeLabels)
|
||||||
|
{
|
||||||
|
auto hdl = opaque(deref(this, pimpl).get_or_add(nativeLabels));
|
||||||
|
return DblGauge{hdl};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
262
src/telemetry/Gauge.h
Normal file
262
src/telemetry/Gauge.h
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
// 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 DblGaugeFamily;
|
||||||
|
class IntGaugeFamily;
|
||||||
|
class Manager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handle to a metric that represents an integer value. Gauges are less
|
||||||
|
* permissive than counters and also allow decrementing the value.
|
||||||
|
*/
|
||||||
|
class IntGauge {
|
||||||
|
public:
|
||||||
|
friend class IntGaugeFamily;
|
||||||
|
|
||||||
|
struct Impl;
|
||||||
|
|
||||||
|
IntGauge() = delete;
|
||||||
|
IntGauge(const IntGauge&) noexcept = default;
|
||||||
|
IntGauge& operator=(const IntGauge&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by 1.
|
||||||
|
*/
|
||||||
|
void inc() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by @p amount.
|
||||||
|
*/
|
||||||
|
void inc(int64_t amount) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by 1.
|
||||||
|
* @returns the new value.
|
||||||
|
*/
|
||||||
|
int64_t operator++() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the value by 1.
|
||||||
|
*/
|
||||||
|
void dec() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the value by @p amount.
|
||||||
|
*/
|
||||||
|
void dec(int64_t amount) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements 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(IntGauge other) const noexcept
|
||||||
|
{
|
||||||
|
return pimpl == other.pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit IntGauge(Impl* ptr) noexcept : pimpl(ptr)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
Impl* pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether two @ref IntGauge 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==(IntGauge lhs, IntGauge rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.isSameAs(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @relates IntGauge
|
||||||
|
constexpr bool operator!=(IntGauge lhs, IntGauge rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages a collection of IntGauge metrics.
|
||||||
|
*/
|
||||||
|
class IntGaugeFamily : public MetricFamily {
|
||||||
|
public:
|
||||||
|
friend class Manager;
|
||||||
|
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
IntGaugeFamily(const IntGaugeFamily&) noexcept = default;
|
||||||
|
IntGaugeFamily& operator=(const IntGaugeFamily&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the metrics handle for given labels, creating a new instance
|
||||||
|
* lazily if necessary.
|
||||||
|
*/
|
||||||
|
IntGauge getOrAdd(Span<const LabelView> labels);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copydoc getOrAdd
|
||||||
|
*/
|
||||||
|
IntGauge getOrAdd(std::initializer_list<LabelView> labels)
|
||||||
|
{
|
||||||
|
return getOrAdd(Span{labels.begin(), labels.size()});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit IntGaugeFamily(Impl* ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handle to a metric that represents a floating point value. Gauges are less
|
||||||
|
* permissive than counters and also allow decrementing the value.
|
||||||
|
* up.
|
||||||
|
*/
|
||||||
|
class DblGauge {
|
||||||
|
public:
|
||||||
|
friend class DblGaugeFamily;
|
||||||
|
|
||||||
|
struct Impl;
|
||||||
|
|
||||||
|
DblGauge() = delete;
|
||||||
|
DblGauge(const DblGauge&) noexcept = default;
|
||||||
|
DblGauge& operator=(const DblGauge&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by 1.
|
||||||
|
*/
|
||||||
|
void inc() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by @p amount.
|
||||||
|
*/
|
||||||
|
void inc(double amount) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by 1.
|
||||||
|
*/
|
||||||
|
void dec() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the value by @p amount.
|
||||||
|
*/
|
||||||
|
void dec(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(DblGauge other) const noexcept
|
||||||
|
{
|
||||||
|
return pimpl == other.pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit DblGauge(Impl* ptr) noexcept : pimpl(ptr)
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
Impl* pimpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether two @ref DblGauge 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==(DblGauge lhs, DblGauge rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.isSameAs(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @relates DblGauge
|
||||||
|
constexpr bool operator!=(DblGauge lhs, DblGauge rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages a collection of DblGauge metrics.
|
||||||
|
*/
|
||||||
|
class DblGaugeFamily : public MetricFamily {
|
||||||
|
public:
|
||||||
|
friend class Manager;
|
||||||
|
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
DblGaugeFamily(const DblGaugeFamily&) noexcept = default;
|
||||||
|
DblGaugeFamily& operator=(const DblGaugeFamily&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the metrics handle for given labels, creating a new instance
|
||||||
|
* lazily if necessary.
|
||||||
|
*/
|
||||||
|
DblGauge getOrAdd(Span<const LabelView> labels);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copydoc getOrAdd
|
||||||
|
*/
|
||||||
|
DblGauge getOrAdd(std::initializer_list<LabelView> labels)
|
||||||
|
{
|
||||||
|
return getOrAdd(Span{labels.begin(), labels.size()});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit DblGaugeFamily(Impl* ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct GaugeOracle {
|
||||||
|
static_assert(std::is_same<T, int64_t>::value,
|
||||||
|
"Gauge<T> only supports int64_t and double");
|
||||||
|
|
||||||
|
using type = IntGauge;
|
||||||
|
|
||||||
|
using family_type = IntGaugeFamily;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct GaugeOracle<double> {
|
||||||
|
using type = DblGauge;
|
||||||
|
|
||||||
|
using family_type = DblGaugeFamily;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using Gauge = typename detail::GaugeOracle<T>::type;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using GaugeFamily = typename detail::GaugeOracle<T>::family_type;
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
|
@ -22,6 +22,14 @@ using NativeDblCounter = ct::dbl_counter;
|
||||||
|
|
||||||
using NativeDblCounterFamily = ct::metric_family_impl<NativeDblCounter>;
|
using NativeDblCounterFamily = ct::metric_family_impl<NativeDblCounter>;
|
||||||
|
|
||||||
|
using NativeIntGauge = ct::int_gauge;
|
||||||
|
|
||||||
|
using NativeIntGaugeFamily = ct::metric_family_impl<NativeIntGauge>;
|
||||||
|
|
||||||
|
using NativeDblGauge = ct::dbl_gauge;
|
||||||
|
|
||||||
|
using NativeDblGaugeFamily = ct::metric_family_impl<NativeDblGauge>;
|
||||||
|
|
||||||
auto& deref(Manager::Impl* ptr)
|
auto& deref(Manager::Impl* ptr)
|
||||||
{
|
{
|
||||||
return *reinterpret_cast<NativeManager*>(ptr);
|
return *reinterpret_cast<NativeManager*>(ptr);
|
||||||
|
@ -42,6 +50,16 @@ auto opaque(NativeDblCounterFamily* ptr)
|
||||||
return reinterpret_cast<DblCounterFamily::Impl*>(ptr);
|
return reinterpret_cast<DblCounterFamily::Impl*>(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeIntGaugeFamily* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<IntGaugeFamily::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto opaque(NativeDblGaugeFamily* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<DblGaugeFamily::Impl*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
auto withNative(Span<const std::string_view> xs, F continuation)
|
auto withNative(Span<const std::string_view> xs, F continuation)
|
||||||
{
|
{
|
||||||
|
@ -91,13 +109,56 @@ DblCounterFamily Manager::dblCounterFam(std::string_view prefix,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntGaugeFamily Manager::intGaugeFam(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).gauge_family(prefix, name, xs,
|
||||||
|
helptext, unit, isSum);
|
||||||
|
return IntGaugeFamily{opaque(ptr)};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
DblGaugeFamily Manager::dblGaugeFam(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).gauge_family<double>(prefix, name, xs,
|
||||||
|
helptext, unit, isSum);
|
||||||
|
return DblGaugeFamily{opaque(ptr)};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace zeek::telemetry
|
} // namespace zeek::telemetry
|
||||||
|
|
||||||
// -- unit tests ---------------------------------------------------------------
|
// -- unit tests ---------------------------------------------------------------
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
using namespace zeek::telemetry;
|
using namespace zeek::telemetry;
|
||||||
|
|
||||||
SCENARIO("telemetry managers provide access to counters")
|
namespace {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
auto toVector(zeek::Span<T> xs)
|
||||||
|
{
|
||||||
|
std::vector<std::remove_const_t<T>> result;
|
||||||
|
for (auto&& x : xs)
|
||||||
|
result.emplace_back(x);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SCENARIO("telemetry managers provide access to counter singletons")
|
||||||
{
|
{
|
||||||
GIVEN("a telemetry manager")
|
GIVEN("a telemetry manager")
|
||||||
{
|
{
|
||||||
|
@ -157,3 +218,190 @@ SCENARIO("telemetry managers provide access to counters")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCENARIO("telemetry managers provide access to counter families")
|
||||||
|
{
|
||||||
|
GIVEN("a telemetry manager")
|
||||||
|
{
|
||||||
|
NativeManager nativeMgr;
|
||||||
|
Manager mgr{opaque(&nativeMgr)};
|
||||||
|
WHEN("retrieving an IntCounter family")
|
||||||
|
{
|
||||||
|
auto family = mgr.counterFamily("zeek", "requests", {"method"}, "test", "1", true);
|
||||||
|
THEN("the family object stores the parameters")
|
||||||
|
{
|
||||||
|
CHECK_EQ(family.prefix(), "zeek"sv);
|
||||||
|
CHECK_EQ(family.name(), "requests"sv);
|
||||||
|
CHECK_EQ(toVector(family.labelNames()), std::vector{"method"s});
|
||||||
|
CHECK_EQ(family.helptext(), "test"sv);
|
||||||
|
CHECK_EQ(family.unit(), "1"sv);
|
||||||
|
CHECK_EQ(family.isSum(), true);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns the same metric for the same labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"method", "get"}});
|
||||||
|
auto second = family.getOrAdd({{"method", "get"}});
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns different metric for the disjoint labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"method", "get"}});
|
||||||
|
auto second = family.getOrAdd({{"method", "put"}});
|
||||||
|
CHECK_NE(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WHEN("retrieving a DblCounter family")
|
||||||
|
{
|
||||||
|
auto family = mgr.counterFamily<double>("zeek", "runtime", {"query"}, "test", "seconds", true);
|
||||||
|
THEN("the family object stores the parameters")
|
||||||
|
{
|
||||||
|
CHECK_EQ(family.prefix(), "zeek"sv);
|
||||||
|
CHECK_EQ(family.name(), "runtime"sv);
|
||||||
|
CHECK_EQ(toVector(family.labelNames()), std::vector{"query"s});
|
||||||
|
CHECK_EQ(family.helptext(), "test"sv);
|
||||||
|
CHECK_EQ(family.unit(), "seconds"sv);
|
||||||
|
CHECK_EQ(family.isSum(), true);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns the same metric for the same labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"query", "foo"}});
|
||||||
|
auto second = family.getOrAdd({{"query", "foo"}});
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns different metric for the disjoint labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"query", "foo"}});
|
||||||
|
auto second = family.getOrAdd({{"query", "bar"}});
|
||||||
|
CHECK_NE(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("telemetry managers provide access to gauge singletons")
|
||||||
|
{
|
||||||
|
GIVEN("a telemetry manager")
|
||||||
|
{
|
||||||
|
NativeManager nativeMgr;
|
||||||
|
Manager mgr{opaque(&nativeMgr)};
|
||||||
|
WHEN("retrieving an IntGauge singleton")
|
||||||
|
{
|
||||||
|
auto first = mgr.gaugeSingleton("zeek", "int-gauge", "test");
|
||||||
|
THEN("its initial value is zero")
|
||||||
|
{
|
||||||
|
CHECK_EQ(first.value(), 0);
|
||||||
|
}
|
||||||
|
AND_THEN("calling inc(), dec(), operator++ or operator-- changes the value")
|
||||||
|
{
|
||||||
|
first.inc();
|
||||||
|
CHECK_EQ(first.value(), 1);
|
||||||
|
first.inc(2);
|
||||||
|
CHECK_EQ(first.value(), 3);
|
||||||
|
first.dec();
|
||||||
|
CHECK_EQ(first.value(), 2);
|
||||||
|
CHECK_EQ(++first, 3);
|
||||||
|
CHECK_EQ(first.value(), 3);
|
||||||
|
CHECK_EQ(--first, 2);
|
||||||
|
CHECK_EQ(first.value(), 2);
|
||||||
|
}
|
||||||
|
AND_THEN("calling gaugeSingleton again for the same name returns the same handle")
|
||||||
|
{
|
||||||
|
auto second = mgr.gaugeSingleton("zeek", "int-gauge", "test");
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("calling gaugeSingleton for a different name returns another handle")
|
||||||
|
{
|
||||||
|
auto third = mgr.gaugeSingleton("zeek", "int-gauge-2", "test");
|
||||||
|
CHECK_NE(first, third);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WHEN("retrieving a DblGauge singleton")
|
||||||
|
{
|
||||||
|
auto first = mgr.gaugeSingleton<double>("zeek", "dbl-gauge", "test");
|
||||||
|
THEN("its initial value is zero")
|
||||||
|
{
|
||||||
|
CHECK_EQ(first.value(), 0.0);
|
||||||
|
}
|
||||||
|
AND_THEN("calling inc() or dec() changes the value")
|
||||||
|
{
|
||||||
|
first.inc();
|
||||||
|
CHECK_EQ(first.value(), 1.0);
|
||||||
|
first.inc(3.0);
|
||||||
|
CHECK_EQ(first.value(), 4.0);
|
||||||
|
first.dec(2.0);
|
||||||
|
CHECK_EQ(first.value(), 2.0);
|
||||||
|
first.dec();
|
||||||
|
CHECK_EQ(first.value(), 1.0);
|
||||||
|
}
|
||||||
|
AND_THEN("calling gaugeSingleton again for the same name returns the same handle")
|
||||||
|
{
|
||||||
|
auto second = mgr.gaugeSingleton<double>("zeek", "dbl-gauge", "test");
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("calling gaugeSingleton for a different name returns another handle")
|
||||||
|
{
|
||||||
|
auto third = mgr.gaugeSingleton<double>("zeek", "dbl-gauge-2", "test");
|
||||||
|
CHECK_NE(first, third);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("telemetry managers provide access to gauge families")
|
||||||
|
{
|
||||||
|
GIVEN("a telemetry manager")
|
||||||
|
{
|
||||||
|
NativeManager nativeMgr;
|
||||||
|
Manager mgr{opaque(&nativeMgr)};
|
||||||
|
WHEN("retrieving an IntGauge family")
|
||||||
|
{
|
||||||
|
auto family = mgr.gaugeFamily("zeek", "open-connections", {"protocol"}, "test");
|
||||||
|
THEN("the family object stores the parameters")
|
||||||
|
{
|
||||||
|
CHECK_EQ(family.prefix(), "zeek"sv);
|
||||||
|
CHECK_EQ(family.name(), "open-connections"sv);
|
||||||
|
CHECK_EQ(toVector(family.labelNames()), std::vector{"protocol"s});
|
||||||
|
CHECK_EQ(family.helptext(), "test"sv);
|
||||||
|
CHECK_EQ(family.unit(), "1"sv);
|
||||||
|
CHECK_EQ(family.isSum(), false);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns the same metric for the same labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"protocol", "tcp"}});
|
||||||
|
auto second = family.getOrAdd({{"protocol", "tcp"}});
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns different metric for the disjoint labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"protocol", "tcp"}});
|
||||||
|
auto second = family.getOrAdd({{"protocol", "quic"}});
|
||||||
|
CHECK_NE(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WHEN("retrieving a DblGauge family")
|
||||||
|
{
|
||||||
|
auto family = mgr.gaugeFamily<double>("zeek", "water-level", {"river"}, "test", "meters");
|
||||||
|
THEN("the family object stores the parameters")
|
||||||
|
{
|
||||||
|
CHECK_EQ(family.prefix(), "zeek"sv);
|
||||||
|
CHECK_EQ(family.name(), "water-level"sv);
|
||||||
|
CHECK_EQ(toVector(family.labelNames()), std::vector{"river"s});
|
||||||
|
CHECK_EQ(family.helptext(), "test"sv);
|
||||||
|
CHECK_EQ(family.unit(), "meters"sv);
|
||||||
|
CHECK_EQ(family.isSum(), false);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns the same metric for the same labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"river", "Sacramento"}});
|
||||||
|
auto second = family.getOrAdd({{"river", "Sacramento"}});
|
||||||
|
CHECK_EQ(first, second);
|
||||||
|
}
|
||||||
|
AND_THEN("getOrAdd returns different metric for the disjoint labels")
|
||||||
|
{
|
||||||
|
auto first = family.getOrAdd({{"query", "Sacramento"}});
|
||||||
|
auto second = family.getOrAdd({{"query", "San Joaquin"}});
|
||||||
|
CHECK_NE(first, second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "zeek/Span.h"
|
#include "zeek/Span.h"
|
||||||
#include "zeek/telemetry/Counter.h"
|
#include "zeek/telemetry/Counter.h"
|
||||||
|
#include "zeek/telemetry/Gauge.h"
|
||||||
|
|
||||||
namespace zeek::telemetry {
|
namespace zeek::telemetry {
|
||||||
|
|
||||||
|
@ -129,6 +130,107 @@ public:
|
||||||
return fam.getOrAdd({});
|
return fam.getOrAdd({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns a gauge 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>
|
||||||
|
GaugeFamily<ValueType>
|
||||||
|
gaugeFamily(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 intGaugeFam(prefix, name, labels, helptext, unit, isSum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<ValueType, double>::value,
|
||||||
|
"metrics only support int64_t and double values");
|
||||||
|
return dblGaugeFam(prefix, name, labels, helptext, unit, isSum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc gaugeFamily
|
||||||
|
template <class ValueType = int64_t>
|
||||||
|
GaugeFamily<ValueType>
|
||||||
|
gaugeFamily(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 gaugeFamily<ValueType>(prefix, name, lblSpan, helptext,
|
||||||
|
unit, isSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accesses a gauge instance. Creates the hosting metric family as well
|
||||||
|
* as the gauge 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>
|
||||||
|
Gauge<ValueType>
|
||||||
|
gaugeInstance(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 = gaugeFamily<ValueType>(prefix, name, labelNames,
|
||||||
|
helptext, unit, isSum);
|
||||||
|
return family.getOrAdd(labels);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc gaugeInstance
|
||||||
|
template <class ValueType = int64_t>
|
||||||
|
Gauge<ValueType>
|
||||||
|
gaugeInstance(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 gaugeInstance(prefix, name, lblSpan, helptext, unit, isSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accesses a gauge singleton, i.e., a gauge that belongs to a family
|
||||||
|
* without label dimensions (which thus only has a single member). Creates
|
||||||
|
* the hosting metric family as well as the gauge 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>
|
||||||
|
Gauge<ValueType>
|
||||||
|
gaugeSingleton(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 = gaugeFamily<ValueType>(prefix, name, labels, helptext,
|
||||||
|
unit, isSum);
|
||||||
|
return fam.getOrAdd({});
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IntCounterFamily
|
IntCounterFamily
|
||||||
intCounterFam(std::string_view prefix, std::string_view name,
|
intCounterFam(std::string_view prefix, std::string_view name,
|
||||||
|
@ -140,6 +242,16 @@ private:
|
||||||
Span<const std::string_view> labels,
|
Span<const std::string_view> labels,
|
||||||
std::string_view helptext, std::string_view unit, bool isSum);
|
std::string_view helptext, std::string_view unit, bool isSum);
|
||||||
|
|
||||||
|
IntGaugeFamily
|
||||||
|
intGaugeFam(std::string_view prefix, std::string_view name,
|
||||||
|
Span<const std::string_view> labels,
|
||||||
|
std::string_view helptext, std::string_view unit, bool isSum);
|
||||||
|
|
||||||
|
DblGaugeFamily
|
||||||
|
dblGaugeFam(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>
|
template <class F>
|
||||||
static void withLabelNames(Span<const LabelView> xs, F continuation)
|
static void withLabelNames(Span<const LabelView> xs, F continuation)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "zeek/telemetry/MetricFamily.h"
|
||||||
|
|
||||||
|
#include "caf/telemetry/metric_family.hpp"
|
||||||
|
|
||||||
|
namespace zeek::telemetry {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace ct = caf::telemetry;
|
||||||
|
|
||||||
|
using NativeMetricFamily = ct::metric_family;
|
||||||
|
|
||||||
|
auto& deref(MetricFamily::Impl* ptr)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<NativeMetricFamily*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::string_view MetricFamily::prefix() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).prefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view MetricFamily::name() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).name();
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<const std::string> MetricFamily::labelNames() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).label_names();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view MetricFamily::helptext() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).helptext();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view MetricFamily::unit() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).unit();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetricFamily::isSum() const noexcept
|
||||||
|
{
|
||||||
|
return deref(pimpl).is_sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace zeek::telemetry
|
|
@ -44,7 +44,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @returns the names for all label dimensions.
|
* @returns the names for all label dimensions.
|
||||||
*/
|
*/
|
||||||
Span<const std::string> label_names() const noexcept;
|
Span<const std::string> labelNames() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns a short explanation of the metric.
|
* @returns a short explanation of the metric.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue