Skip to content

Commit

Permalink
appsec helper: remote config telemetry metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
cataphract committed Jul 11, 2024
1 parent dbeb811 commit 15c89e7
Show file tree
Hide file tree
Showing 18 changed files with 726 additions and 31 deletions.
1 change: 1 addition & 0 deletions appsec/src/extension/commands_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ void _handle_telemetry_metric(const char *nonnull key_str, size_t key_len,
HANDLE_METRIC("waf.init", DDTRACE_METRIC_TYPE_COUNT);
HANDLE_METRIC("waf.input_truncated", DDTRACE_METRIC_TYPE_COUNT);

HANDLE_METRIC("remote_config.first_pull", DDTRACE_METRIC_TYPE_GAUGE);
HANDLE_METRIC("remote_config.first_pull", DDTRACE_METRIC_TYPE_GAUGE);
HANDLE_METRIC("remote_config.first_pull", DDTRACE_METRIC_TYPE_GAUGE);
HANDLE_METRIC(
Expand Down
13 changes: 10 additions & 3 deletions appsec/src/helper/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ std::shared_ptr<typename T::response> client::publish(

auto response = std::make_shared<typename T::response>();
try {
service_->before_first_publish();

// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
auto res = context_->publish(std::move(command.data));
if (res) {
Expand Down Expand Up @@ -502,19 +504,27 @@ struct RequestMetricsSubmitter : public metrics::TelemetrySubmitter {
void submit_metric(
std::string_view name, double value, std::string tags) override
{
SPDLOG_TRACE("submit_metric [req]: name={}, value={}, tags={}", name,
value, tags);
tel_metrics[name].emplace_back(value, tags);
};
void submit_legacy_metric(std::string_view name, double value) override
{
SPDLOG_TRACE(
"submit_legacy_metric [req]: name={}, value={}", name, value);
metrics[name] = value;
};
void submit_legacy_meta(std::string_view name, std::string value) override
{
SPDLOG_TRACE(
"submit_legacy_meta [req]: name={}, value={}", name, value);
meta[std::string{name}] = value;
};
void submit_legacy_meta_copy_key(
std::string name, std::string value) override
{
SPDLOG_TRACE("submit_legacy_meta_copy_key [req]: name={}, value={}",
name, value);
meta[name] = value;
}

Expand All @@ -528,15 +538,12 @@ template <typename Response>
void collect_metrics_impl(Response &response, service &service,
std::optional<engine::context> &context)
{

RequestMetricsSubmitter msubmitter{};
if (context) {
context->get_metrics(msubmitter);
}
service.drain_metrics(
[&msubmitter](std::string_view name, double value, std::string tags) {
spdlog::debug(
"submit_metric: name={}, value={}, tags={}", name, value, tags);
msubmitter.submit_metric(name, value, std::move(tags));
});
msubmitter.metrics.merge(service.drain_legacy_metrics());
Expand Down
37 changes: 31 additions & 6 deletions appsec/src/helper/remote_config/client_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@
#include "listeners/engine_listener.hpp"
#include "listeners/listener.hpp"
#include "metrics.hpp"
#include <atomic>
#include <chrono>

namespace dds::remote_config {

static constexpr std::chrono::milliseconds default_max_interval = 5min;

client_handler::client_handler(remote_config::client::ptr &&rc_client,
std::shared_ptr<service_config> service_config,
std::shared_ptr<metrics::TelemetrySubmitter> msubmitter,
const std::chrono::milliseconds &poll_interval)
: service_config_(std::move(service_config)),
rc_client_(std::move(rc_client)), poll_interval_(poll_interval),
interval_(poll_interval), max_interval(default_max_interval)
msubmitter_(std::move(msubmitter)), interval_(poll_interval),
max_interval(default_max_interval)
{
// It starts checking if rc is available
rc_action_ = [this] { discover(); };
Expand Down Expand Up @@ -56,9 +60,8 @@ client_handler::ptr client_handler::from_settings(service_identifier &&id,
}

if (eng_settings.rules_file.empty()) {
listeners.emplace_back(
std::make_shared<remote_config::engine_listener>(engine_ptr,
std::move(msubmitter), eng_settings.rules_file_or_default()));
listeners.emplace_back(std::make_shared<remote_config::engine_listener>(
engine_ptr, msubmitter, eng_settings.rules_file_or_default()));
}

if (listeners.empty()) {
Expand All @@ -69,7 +72,7 @@ client_handler::ptr client_handler::from_settings(service_identifier &&id,
remote_config::settings(rc_settings), std::move(listeners));

return std::make_shared<client_handler>(std::move(rc_client),
std::move(service_config),
std::move(service_config), std::move(msubmitter),
std::chrono::milliseconds{rc_settings.poll_interval});
}

Expand Down Expand Up @@ -102,7 +105,29 @@ void client_handler::handle_error()
void client_handler::poll()
{
try {
rc_client_->poll();
if (last_success_ != empty_time) {
auto now = std::chrono::steady_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(
now - last_success_);
msubmitter_->submit_metric("remote_config.last_success"sv,
static_cast<double>(elapsed.count()), {});
}

const bool result = rc_client_->poll();

auto now = std::chrono::steady_clock::now();
last_success_ = now;

auto creation_time = creation_time_.load(std::memory_order_acquire);
if (result && creation_time != empty_time) {
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(
now - creation_time);
msubmitter_->submit_metric("remote_config.first_pull"sv,
static_cast<double>(elapsed.count()), {});
creation_time_.store(empty_time, std::memory_order_release);
}
} catch (dds::remote_config::network_exception & /** e */) {
handle_error();
}
Expand Down
14 changes: 14 additions & 0 deletions appsec/src/helper/remote_config/client_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "service_identifier.hpp"
#include "std_logging.hpp"
#include "utils.hpp"
#include <atomic>
#include <future>
#include <memory>
#include <spdlog/spdlog.h>
Expand All @@ -28,6 +29,7 @@ class client_handler {

client_handler(remote_config::client::ptr &&rc_client,
std::shared_ptr<service_config> service_config,
std::shared_ptr<metrics::TelemetrySubmitter> msubmitter,
const std::chrono::milliseconds &poll_interval = 1s);
~client_handler();

Expand Down Expand Up @@ -62,6 +64,11 @@ class client_handler {
}
}

bool has_applied_rc()
{
return creation_time_.load(std::memory_order_acquire) == empty_time;
}

protected:
void run(std::future<bool> &&exit_signal);
void handle_error();
Expand All @@ -81,6 +88,13 @@ class client_handler {

std::promise<bool> exit_;
std::thread handler_;

static constexpr auto empty_time = std::chrono::steady_clock::time_point{};

std::shared_ptr<metrics::TelemetrySubmitter> msubmitter_;
std::atomic<std::chrono::steady_clock::time_point> creation_time_{
std::chrono::steady_clock::now()}; // def value if first poll() done
std::chrono::steady_clock::time_point last_success_{};
};

} // namespace dds::remote_config
14 changes: 14 additions & 0 deletions appsec/src/helper/service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "service_identifier.hpp"
#include "std_logging.hpp"
#include "utils.hpp"
#include <chrono>
#include <memory>
#include <mutex>
#include <spdlog/spdlog.h>
Expand Down Expand Up @@ -47,18 +48,21 @@ class service {
void submit_metric(std::string_view metric_name, double value,
std::string tags) override
{
SPDLOG_TRACE("submit_metric: {} {} {}", metric_name, value, tags);
const std::lock_guard<std::mutex> lock{pending_metrics_mutex_};
pending_metrics_.emplace_back(metric_name, value, std::move(tags));
}

void submit_legacy_metric(std::string_view name, double value) override
{
SPDLOG_TRACE("submit_legacy_metric: {} {}", name, value);
const std::lock_guard<std::mutex> lock{legacy_metrics_mutex_};
legacy_metrics_[name] = value;
}
void submit_legacy_meta(
std::string_view name, std::string value) override
{
SPDLOG_TRACE("submit_legacy_meta: {} {}", name, value);
const std::lock_guard<std::mutex> lock{meta_mutex_};
meta_[std::string{name}] = std::move(value);
}
Expand Down Expand Up @@ -184,6 +188,16 @@ class service {
return msubmitter_->drain_legacy_meta();
}

// to be called just before the submitting data to the engine for the first
// time in the request
void before_first_publish() const
{
if (client_handler_ && !client_handler_->has_applied_rc()) {
msubmitter_->submit_metric(
"remote_config.requests_before_running"sv, 1, "");
}
}

protected:
std::shared_ptr<engine> engine_{};
std::shared_ptr<service_config> service_config_{};
Expand Down
Loading

0 comments on commit 15c89e7

Please sign in to comment.