mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
298 lines
9.5 KiB
C++
298 lines
9.5 KiB
C++
##! Functions for accessing counter metrics from script land.
|
|
|
|
module Telemetry;
|
|
|
|
%%{
|
|
|
|
#include <span>
|
|
#include "zeek/telemetry/Counter.h"
|
|
#include "zeek/telemetry/Gauge.h"
|
|
#include "zeek/telemetry/Histogram.h"
|
|
#include "zeek/telemetry/Manager.h"
|
|
#include "zeek/telemetry/Opaques.h"
|
|
|
|
namespace {
|
|
|
|
template <class ScriptHandle, class Fun>
|
|
auto with(zeek::Val* val, const char* error_msg, Fun fun)
|
|
{
|
|
if ( auto ptr = dynamic_cast<ScriptHandle*>(val) )
|
|
{
|
|
fun(ptr->GetHandle());
|
|
return zeek::val_mgr->True();
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("%s", error_msg);
|
|
return zeek::val_mgr->False();
|
|
}
|
|
}
|
|
|
|
std::string_view sv(const zeek::String* str) noexcept
|
|
{
|
|
auto len = static_cast<size_t>(str->Len());
|
|
return {reinterpret_cast<char*>(str->Bytes()), len};
|
|
};
|
|
|
|
std::string_view sv(const zeek::StringVal* val) noexcept
|
|
{
|
|
return sv(val->AsString());
|
|
};
|
|
|
|
std::vector<std::string_view> sv_vec(zeek::VectorVal* xs)
|
|
{
|
|
std::vector<std::string_view> result;
|
|
if ( xs )
|
|
for ( unsigned index = 0; index < xs->Size(); ++index )
|
|
if ( auto ptr = xs->ValAt(index) )
|
|
if ( auto* str = ptr->AsString() )
|
|
result.emplace_back(sv(str));
|
|
return result;
|
|
}
|
|
|
|
std::vector<zeek::telemetry::LabelView> sv_tbl(zeek::TableVal* xs)
|
|
{
|
|
std::vector<zeek::telemetry::LabelView> result;
|
|
if ( xs )
|
|
{
|
|
for ( auto& val : *xs->Get() )
|
|
{
|
|
auto val_ptr = val.value->GetVal();
|
|
result.emplace_back(std::string_view{val.GetKey(), val.key_size},
|
|
sv(val_ptr->AsStringVal()));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool labels_valid(std::span<const zeek::telemetry::LabelView> labels,
|
|
std::span<const std::string> label_names)
|
|
{
|
|
auto key_in_label_names = [keys{label_names}](auto x)
|
|
{
|
|
return std::find(keys.begin(), keys.end(), x.first) != keys.end();
|
|
};
|
|
return labels.size() == label_names.size()
|
|
&& std::ranges::all_of(labels, key_in_label_names);
|
|
}
|
|
|
|
template <class IntOrDbl>
|
|
auto to_std_vec(zeek::VectorVal* xs)
|
|
{
|
|
std::vector<IntOrDbl> result;
|
|
if( xs )
|
|
for ( unsigned index = 0; index < xs->Size() ; ++index )
|
|
{
|
|
if constexpr (std::is_same_v<IntOrDbl, int64_t>)
|
|
result.emplace_back(xs->ValAt(index)->AsInt());
|
|
else
|
|
result.emplace_back(xs->ValAt(index)->AsDouble());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <class IntOrDbl>
|
|
auto to_std_vec(zeek::Val* xs)
|
|
{
|
|
return to_std_vec<IntOrDbl>(xs->AsVectorVal());
|
|
}
|
|
|
|
}
|
|
%%}
|
|
|
|
# -- Counter ----------------------------------------------------------------
|
|
|
|
function Telemetry::__counter_family%(prefix: string,
|
|
name: string,
|
|
labels: string_vec,
|
|
helptext: string &default = "Zeek Script Metric",
|
|
unit: string &default = ""%): opaque of counter_metric_family
|
|
%{
|
|
auto lbl_vec = sv_vec(labels->AsVectorVal());
|
|
auto hdl = telemetry_mgr->CounterFamily(sv(prefix), sv(name), lbl_vec,
|
|
sv(helptext), sv(unit));
|
|
return zeek::make_intrusive<CounterMetricFamilyVal>(hdl);
|
|
%}
|
|
|
|
function Telemetry::__counter_metric_get_or_add%(family: opaque of counter_metric_family,
|
|
labels: table_string_of_string%): opaque of counter_metric
|
|
%{
|
|
using ResultType = zeek::IntrusivePtr<CounterMetricFamilyVal>;
|
|
if ( auto ptr = dynamic_cast<zeek::CounterMetricFamilyVal*>(family) )
|
|
{
|
|
auto hdl = ptr->GetHandle();
|
|
auto lbl_map = sv_tbl(labels->AsTableVal());
|
|
if ( labels_valid(lbl_map, hdl->LabelNames()) )
|
|
{
|
|
auto res = hdl->GetOrAdd(lbl_map);
|
|
return zeek::make_intrusive<CounterMetricVal>(res);
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::counter_metric_get_or_add: invalid label dimensions.");
|
|
return ResultType{nullptr};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::counter_metric_get_or_add: invalid handle.");
|
|
return ResultType{nullptr};
|
|
}
|
|
%}
|
|
|
|
function Telemetry::__counter_inc%(val: opaque of counter_metric,
|
|
amount: double &default = 1.0%): bool
|
|
%{
|
|
return with<CounterMetricVal>(val, "Telemetry::counter_inc: invalid handle.", [amount](auto hdl) { hdl->Inc(amount); });
|
|
%}
|
|
|
|
function Telemetry::__counter_value%(val: opaque of counter_metric%): double
|
|
%{
|
|
if ( auto ptr = dynamic_cast<zeek::CounterMetricVal*>(val) )
|
|
{
|
|
return zeek::make_intrusive<zeek::DoubleVal>(ptr->GetHandle()->Value());
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::counter_value: invalid handle.");
|
|
return zeek::make_intrusive<zeek::DoubleVal>(0);
|
|
}
|
|
%}
|
|
|
|
# -- Gauge ------------------------------------------------------------------
|
|
|
|
function Telemetry::__gauge_family%(prefix: string,
|
|
name: string,
|
|
labels: string_vec,
|
|
helptext: string &default = "Zeek Script Metric",
|
|
unit: string &default = ""%): opaque of gauge_metric_family
|
|
%{
|
|
auto lbl_vec = sv_vec(labels->AsVectorVal());
|
|
auto hdl = telemetry_mgr->GaugeFamily(sv(prefix), sv(name), lbl_vec,
|
|
sv(helptext), sv(unit));
|
|
return zeek::make_intrusive<GaugeMetricFamilyVal>(hdl);
|
|
%}
|
|
|
|
function Telemetry::__gauge_metric_get_or_add%(family: opaque of gauge_metric_family,
|
|
labels: table_string_of_string%): opaque of gauge_metric
|
|
%{
|
|
using ResultType = zeek::IntrusivePtr<GaugeMetricFamilyVal>;
|
|
if ( auto ptr = dynamic_cast<zeek::GaugeMetricFamilyVal*>(family) )
|
|
{
|
|
auto hdl = ptr->GetHandle();
|
|
auto lbl_map = sv_tbl(labels->AsTableVal());
|
|
if ( labels_valid(lbl_map, hdl->LabelNames()) )
|
|
{
|
|
auto res = hdl->GetOrAdd(lbl_map);
|
|
return zeek::make_intrusive<GaugeMetricVal>(res);
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::gauge_metric_get_or_add: invalid label dimensions.");
|
|
return ResultType{nullptr};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::gauge_metric_get_or_add: invalid handle.");
|
|
return ResultType{nullptr};
|
|
}
|
|
%}
|
|
|
|
function Telemetry::__gauge_inc%(val: opaque of gauge_metric,
|
|
amount: double &default = 1.0%): bool
|
|
%{
|
|
return with<GaugeMetricVal>(val, "Telemetry::gauge_inc: invalid handle.", [amount](auto hdl) { hdl->Inc(amount); });
|
|
%}
|
|
|
|
function Telemetry::__gauge_dec%(val: opaque of gauge_metric,
|
|
amount: double &default = 1.0%): bool
|
|
%{
|
|
return with<GaugeMetricVal>(val, "Telemetry::gauge_dec: invalid handle.", [amount](auto hdl) { hdl->Dec(amount); });
|
|
%}
|
|
|
|
function Telemetry::__gauge_value%(val: opaque of gauge_metric%): double
|
|
%{
|
|
if ( auto ptr = dynamic_cast<zeek::GaugeMetricVal*>(val) )
|
|
{
|
|
return zeek::make_intrusive<zeek::DoubleVal>(ptr->GetHandle()->Value());
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::gauge_value: invalid handle.");
|
|
return zeek::make_intrusive<zeek::DoubleVal>(0.0);
|
|
}
|
|
%}
|
|
|
|
# -- Histogram --------------------------------------------------------------
|
|
|
|
function Telemetry::__histogram_family%(prefix: string,
|
|
name: string,
|
|
labels: string_vec,
|
|
bounds: double_vec,
|
|
helptext: string &default = "Zeek Script Metric",
|
|
unit: string &default = ""%): opaque of histogram_metric_family
|
|
%{
|
|
auto lbl_vec = sv_vec(labels->AsVectorVal());
|
|
auto std_bounds = to_std_vec<double>(bounds);
|
|
auto hdl = telemetry_mgr->HistogramFamily(sv(prefix), sv(name), lbl_vec,
|
|
std_bounds, sv(helptext),
|
|
sv(unit));
|
|
return zeek::make_intrusive<HistogramMetricFamilyVal>(hdl);
|
|
%}
|
|
|
|
function Telemetry::__histogram_metric_get_or_add%(family: opaque of histogram_metric_family,
|
|
labels: table_string_of_string%): opaque of histogram_metric
|
|
%{
|
|
using ResultType = zeek::IntrusivePtr<HistogramMetricFamilyVal>;
|
|
if ( auto ptr = dynamic_cast<zeek::HistogramMetricFamilyVal*>(family) )
|
|
{
|
|
auto hdl = ptr->GetHandle();
|
|
auto lbl_map = sv_tbl(labels->AsTableVal());
|
|
if ( labels_valid(lbl_map, hdl->LabelNames()) )
|
|
{
|
|
auto res = hdl->GetOrAdd(lbl_map);
|
|
return zeek::make_intrusive<HistogramMetricVal>(res);
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::histogram_metric_get_or_add: invalid label dimensions.");
|
|
return ResultType{nullptr};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::histogram_metric_get_or_add: invalid handle.");
|
|
return ResultType{nullptr};
|
|
}
|
|
%}
|
|
|
|
function Telemetry::__histogram_observe%(val: opaque of histogram_metric,
|
|
measurement: double%): bool
|
|
%{
|
|
return with<HistogramMetricVal>(val, "Telemetry::histogram_inc: invalid handle.",
|
|
[measurement](auto hdl) { hdl->Observe(measurement); });
|
|
%}
|
|
|
|
function Telemetry::__histogram_sum%(val: opaque of histogram_metric%): double
|
|
%{
|
|
if ( auto ptr = dynamic_cast<zeek::HistogramMetricVal*>(val) )
|
|
{
|
|
return zeek::make_intrusive<zeek::DoubleVal>(ptr->GetHandle()->Sum());
|
|
}
|
|
else
|
|
{
|
|
zeek::reporter->Error("Telemetry::histogram_sum: invalid handle.");
|
|
return make_intrusive<zeek::DoubleVal>(0.0);
|
|
}
|
|
%}
|
|
|
|
function Telemetry::__collect_metrics%(prefix: string, name: string%): any_vec
|
|
%{
|
|
return telemetry_mgr->CollectMetrics(sv(prefix), sv(name));
|
|
%}
|
|
|
|
function Telemetry::__collect_histogram_metrics%(prefix: string, name: string%): any_vec
|
|
%{
|
|
return telemetry_mgr->CollectHistogramMetrics(sv(prefix), sv(name));
|
|
%}
|