refactor(metrics): move metrics handling to its own class

This will keep the details out of the webserver itself and make
it easier to manage metrics.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
This commit is contained in:
Samuel Gaist 2024-03-26 23:04:50 +01:00 committed by poiana
parent e50d647dc9
commit daf7efde67
6 changed files with 174 additions and 39 deletions

View File

@ -93,6 +93,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
PRIVATE
outputs_grpc.cpp
outputs_http.cpp
falco_metrics.cpp
webserver.cpp
grpc_context.cpp
grpc_request_context.cpp

View File

@ -19,6 +19,7 @@ limitations under the License.
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "webserver.h"
#include "falco_metrics.h"
#endif
using namespace falco::app;
@ -45,19 +46,12 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s
+ std::to_string(webserver_config.m_listen_port)
+ ssl_option + "\n");
std::vector<libs::metrics::libs_metrics_collector> metrics_collectors;
if (state.config->m_metrics_enabled && webserver_config.m_metrics_enabled)
{
for (const auto& source_info: state.source_infos)
{
metrics_collectors.push_back(libs::metrics::libs_metrics_collector(source_info.inspector.get(), state.config->m_metrics_flags));
}
}
falco_metrics metrics(state);
state.webserver.start(
state.offline_inspector,
metrics_collectors,
webserver_config);
webserver_config,
metrics);
}
#endif
return run_result::ok();

View File

@ -0,0 +1,114 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "falco_metrics.h"
#include "app/state.h"
#include <libsinsp/sinsp.h>
falco_metrics::falco_metrics(falco::app::state& state)
{
falco_configuration::webserver_config webserver_config = state.config->m_webserver_config;
m_metrics_enabled = state.config->m_metrics_enabled && webserver_config.m_metrics_enabled;
if (m_metrics_enabled)
{
for (const auto& source_info: state.source_infos)
{
sinsp *source_inspector = source_info.inspector.get();
m_inspectors.push_back(source_inspector);
m_metrics_collectors.push_back(libs::metrics::libs_metrics_collector(source_inspector, state.config->m_metrics_flags));
}
}
}
std::string falco_metrics::to_text() const
{
if (!m_metrics_enabled)
{
return "";
}
static const char* all_driver_engines[] = {
BPF_ENGINE, KMOD_ENGINE, MODERN_BPF_ENGINE,
SOURCE_PLUGIN_ENGINE, NODRIVER_ENGINE, GVISOR_ENGINE };
libs::metrics::prometheus_metrics_converter prometheus_metrics_converter;
std::string prometheus_text;
for (auto* inspector: m_inspectors)
{
for (size_t i = 0; i < sizeof(all_driver_engines) / sizeof(const char*); i++)
{
if (inspector->check_current_engine(all_driver_engines[i]))
{
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("engine_name", "falcosecurity", "scap", {{"engine_name", all_driver_engines[i]}});
break;
}
}
const scap_agent_info* agent_info = inspector->get_agent_info();
const scap_machine_info* machine_info = inspector->get_machine_info();
libs::metrics::libs_metrics_collector libs_metrics_collector(inspector, 0);
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("falco_version", "falcosecurity", "falco", {{"falco_version", FALCO_VERSION}});
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("kernel_release", "falcosecurity", "falco", {{"kernel_release", agent_info->uname_r}});
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus("evt_hostname", "falcosecurity", "falco", {{"evt_hostname", machine_info->hostname}});
std::vector<metrics_v2> static_metrics;
static_metrics.push_back(libs_metrics_collector.new_metric("start_ts",
METRICS_V2_LIBBPF_STATS,
METRIC_VALUE_TYPE_U64,
METRIC_VALUE_UNIT_TIME_NS_COUNT,
METRIC_VALUE_METRIC_TYPE_MONOTONIC,
agent_info->start_ts_epoch));
static_metrics.push_back(libs_metrics_collector.new_metric("falco_host_boot_ts",
METRICS_V2_LIBBPF_STATS,
METRIC_VALUE_TYPE_U64,
METRIC_VALUE_UNIT_TIME_NS_COUNT,
METRIC_VALUE_METRIC_TYPE_MONOTONIC,
machine_info->boot_ts_epoch));
static_metrics.push_back(libs_metrics_collector.new_metric("falco_host_num_cpus",
METRICS_V2_LIBBPF_STATS,
METRIC_VALUE_TYPE_U64,
METRIC_VALUE_UNIT_TIME_NS_COUNT,
METRIC_VALUE_METRIC_TYPE_MONOTONIC,
machine_info->num_cpus));
for (auto metrics: static_metrics)
{
prometheus_metrics_converter.convert_metric_to_unit_convention(metrics);
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metrics, "falcosecurity", "falco");
}
}
for (auto metrics_collector: m_metrics_collectors)
{
metrics_collector.snapshot();
auto metrics_snapshot = metrics_collector.get_metrics();
for (auto& metric: metrics_snapshot)
{
prometheus_metrics_converter.convert_metric_to_unit_convention(metric);
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "falcosecurity", "scap");
}
}
return prometheus_text;
}

View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include "configuration.h"
#include <libsinsp/sinsp.h>
namespace falco::app {
struct state;
}
class falco_metrics
{
public:
falco_metrics(falco::app::state& state);
bool is_enabled() const { return m_metrics_enabled; };
std::string to_text() const;
private:
bool m_metrics_enabled = false;
std::vector<sinsp*> m_inspectors;
std::vector<libs::metrics::libs_metrics_collector> m_metrics_collectors;
};

View File

@ -17,6 +17,7 @@ limitations under the License.
#include "webserver.h"
#include "falco_utils.h"
#include "falco_metrics.h"
#include "versions_info.h"
#include <atomic>
@ -27,8 +28,8 @@ falco_webserver::~falco_webserver()
void falco_webserver::start(
const std::shared_ptr<sinsp>& inspector,
const std::vector<libs::metrics::libs_metrics_collector>& metrics_collectors,
const falco_configuration::webserver_config& configuration)
const falco_configuration::webserver_config& webserver_config,
const falco_metrics& metrics)
{
if (m_running)
{
@ -37,11 +38,11 @@ void falco_webserver::start(
}
// allocate and configure server
if (configuration.m_ssl_enabled)
if (webserver_config.m_ssl_enabled)
{
m_server = std::make_unique<httplib::SSLServer>(
configuration.m_ssl_certificate.c_str(),
configuration.m_ssl_certificate.c_str());
webserver_config.m_ssl_certificate.c_str(),
webserver_config.m_ssl_certificate.c_str());
}
else
{
@ -49,10 +50,10 @@ void falco_webserver::start(
}
// configure server
m_server->new_task_queue = [configuration] { return new httplib::ThreadPool(configuration.m_threadiness); };
m_server->new_task_queue = [webserver_config] { return new httplib::ThreadPool(webserver_config.m_threadiness); };
// setup healthz endpoint
m_server->Get(configuration.m_k8s_healthz_endpoint,
m_server->Get(webserver_config.m_k8s_healthz_endpoint,
[](const httplib::Request &, httplib::Response &res) {
res.set_content("{\"status\": \"ok\"}", "application/json");
});
@ -64,26 +65,11 @@ void falco_webserver::start(
res.set_content(versions_json_str, "application/json");
});
if (!metrics_collectors.empty())
if (metrics.is_enabled())
{
libs::metrics::prometheus_metrics_converter prometheus_metrics_converter;
m_server->Get("/metrics",
[metrics_collectors, prometheus_metrics_converter](const httplib::Request &, httplib::Response &res) {
std::string prometheus_text;
for (auto metrics_collector: metrics_collectors) {
metrics_collector.snapshot();
auto metrics_snapshot = metrics_collector.get_metrics();
for (auto& metric: metrics_snapshot)
{
prometheus_metrics_converter.convert_metric_to_unit_convention(metric);
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metric, "falcosecurity", "falco");
}
}
res.set_content(prometheus_text, "text/plain; version=0.0.4");
[metrics](const httplib::Request &, httplib::Response &res) {
res.set_content(metrics.to_text(), "text/plain; version=0.0.4");
});
}
// run server in a separate thread
@ -95,11 +81,11 @@ void falco_webserver::start(
std::atomic<bool> failed;
failed.store(false, std::memory_order_release);
m_server_thread = std::thread([this, configuration, &failed]
m_server_thread = std::thread([this, webserver_config, &failed]
{
try
{
this->m_server->listen(configuration.m_listen_address, configuration.m_listen_port);
this->m_server->listen(webserver_config.m_listen_address, webserver_config.m_listen_port);
}
catch(std::exception &e)
{

View File

@ -25,6 +25,8 @@ limitations under the License.
#include <memory>
#include <thread>
class falco_metrics;
class falco_webserver
{
public:
@ -36,8 +38,8 @@ public:
falco_webserver& operator = (const falco_webserver&) = delete;
virtual void start(
const std::shared_ptr<sinsp>& inspector,
const std::vector<libs::metrics::libs_metrics_collector>& metrics_collectors,
const falco_configuration::webserver_config& configuration);
const falco_configuration::webserver_config& webserver_config,
const falco_metrics& metrics);
virtual void stop();
private: