Compare commits

..

6 Commits

Author SHA1 Message Date
Leonardo Grasso
abdf5512c8 fix(userspace): add portable compat wrappers for gmtime_r, localtime_r, strerror_r
The previous commits used gmtime_r/localtime_r (unavailable on Windows)
and assumed the GNU strerror_r variant returning char* (only on glibc).
This broke macOS, musl, WASM, and Win32 builds.

Add userspace/engine/compat.h with portable inline wrappers:
- falco_gmtime_r / falco_localtime_r: use gmtime_s/localtime_s on Win32
- falco_strerror_r: returns const char* on all platforms, detecting
  glibc via __GLIBC__ (not _GNU_SOURCE alone, since musl defines
  _GNU_SOURCE but provides the XSI variant returning int)

Also fixes a pre-existing bug in create_signal_handlers.cpp where
the GNU strerror_r return value was incorrectly compared to 0 and
the actual error string was discarded.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2026-04-09 16:57:04 +02:00
Leonardo Grasso
26daebb1a9 fix(userspace): replace strerror() with thread-safe strerror_r()
strerror() returns a pointer to a shared static buffer, making it
unsafe when called concurrently from different threads. Replace all
call sites with strerror_r() using stack-local buffers, consistent
with the existing pattern in create_signal_handlers.cpp.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2026-04-09 16:56:58 +02:00
Leonardo Grasso
bb96f26fce fix(userspace/engine): replace non-thread-safe random() with thread-local RNG
random() uses internal static state that is not thread-safe. Since
should_drop_evt() can be called concurrently from per-source event
processing threads, replace it with a thread_local std::mt19937
seeded by std::random_device. Remove the now-unused srandom() seed
and Windows compat defines.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2026-04-09 16:56:49 +02:00
Leonardo Grasso
5e91db569a fix(userspace): replace gmtime/localtime with reentrant variants
gmtime() and localtime() return pointers to a shared static buffer,
making them unsafe in multi-threaded contexts. Replace all call sites
with gmtime_r() and localtime_r() which use caller-provided buffers.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2026-04-09 16:56:43 +02:00
Leonardo Di Giovanna
1d73b2f0a9 ci: restore minimum set of required permissions
Commit #8171176 reduced workflow permissions and only allowed read
accesses to repo content. However, some workflows require write
permissions for token-id and attestations: these requirements resulted
in both master and release CIs being broken in the last month.

While still applying least privilege principle, this patch restores
the minimum set of required ones.

Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2026-04-01 11:28:39 +02:00
Leonardo Di Giovanna
8207e20e46 feat(userspace/falco): add support for kernel iterator metrics
Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
2026-04-01 09:42:39 +02:00
20 changed files with 158 additions and 46 deletions

View File

@@ -56,6 +56,9 @@ jobs:
publish-dev-packages:
needs: [fetch-version, test-dev-packages, test-dev-packages-arm64]
permissions:
id-token: write
contents: read
uses: ./.github/workflows/reusable_publish_packages.yaml
with:
bucket_suffix: '-dev'
@@ -84,6 +87,10 @@ jobs:
publish-dev-docker:
needs: [fetch-version, build-dev-docker, build-dev-docker-arm64]
permissions:
attestations: write
id-token: write
contents: read
uses: ./.github/workflows/reusable_publish_docker.yaml
with:
tag: master

View File

@@ -96,6 +96,9 @@ jobs:
publish-packages:
needs: [release-settings, test-packages, test-packages-arm64]
permissions:
id-token: write
contents: read
uses: ./.github/workflows/reusable_publish_packages.yaml
with:
bucket_suffix: ${{ needs.release-settings.outputs.bucket_suffix }}
@@ -125,6 +128,10 @@ jobs:
publish-docker:
needs: [release-settings, build-docker, build-docker-arm64]
permissions:
attestations: write
id-token: write
contents: read
uses: ./.github/workflows/reusable_publish_docker.yaml
secrets: inherit
with:

View File

@@ -35,9 +35,9 @@ else()
# FALCOSECURITY_LIBS_VERSION. In case you want to test against another driver version (or
# branch, or commit) just pass the variable - ie., `cmake -DDRIVER_VERSION=dev ..`
if(NOT DRIVER_VERSION)
set(DRIVER_VERSION "7b08f8a0a12b56d59eab73052e637ca123623f61")
set(DRIVER_VERSION "ed3ac8a370d5a3d946ed735df40c85fc7395052e")
set(DRIVER_CHECKSUM
"SHA256=43c72a98e48d04177c8223ccdfe88de6f09958f2330b6b9ee26882f1a77e369f"
"SHA256=ef21c3e15038aa2ba2be5841e7cde0d6675ecffb6e2840468fe81418d97ec95f"
)
endif()

View File

@@ -42,9 +42,9 @@ else()
# version (or branch, or commit) just pass the variable - ie., `cmake
# -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "7b08f8a0a12b56d59eab73052e637ca123623f61")
set(FALCOSECURITY_LIBS_VERSION "ed3ac8a370d5a3d946ed735df40c85fc7395052e")
set(FALCOSECURITY_LIBS_CHECKSUM
"SHA256=43c72a98e48d04177c8223ccdfe88de6f09958f2330b6b9ee26882f1a77e369f"
"SHA256=ef21c3e15038aa2ba2be5841e7cde0d6675ecffb6e2840468fe81418d97ec95f"
)
endif()

View File

@@ -1180,7 +1180,7 @@ metrics:
# (a.k.a. the threadtable).
state_counters_enabled: true
# -- Add kernel side event and drop counters to metrics output.
# This isan alternative to `syscall_event_drops`, but with some differences.
# This is an alternative to `syscall_event_drops`, but with some differences.
# These counters reflect monotonic values since Falco's start and are exported at a
# constant stats interval.
kernel_event_counters_enabled: true
@@ -1200,6 +1200,10 @@ metrics:
# Please note that if the respective plugin has no metrics implemented,
# there will be no metrics available.
plugins_metrics_enabled: true
# -- Add kernel side iterator event and drop counters to metrics output.
# These counters reflect monotonic values since Falco's start and are exported at a
# constant stats interval.
kernel_iter_event_counters_enabled: true
# -- Add jemalloc stats to metrics output.
# This option requires that Falco is built with jemalloc support, otherwise
# it will have no effect.

59
userspace/engine/compat.h Normal file
View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2025 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 <ctime>
#include <cstring>
// Portable gmtime_r: Windows provides gmtime_s with reversed arg order.
inline struct tm* falco_gmtime_r(const time_t* timer, struct tm* buf) {
#ifdef _WIN32
return gmtime_s(buf, timer) == 0 ? buf : nullptr;
#else
return gmtime_r(timer, buf);
#endif
}
// Portable localtime_r: Windows provides localtime_s with reversed arg order.
inline struct tm* falco_localtime_r(const time_t* timer, struct tm* buf) {
#ifdef _WIN32
return localtime_s(buf, timer) == 0 ? buf : nullptr;
#else
return localtime_r(timer, buf);
#endif
}
// Portable strerror_r: returns const char* on all platforms.
//
// - glibc with _GNU_SOURCE: returns char* that may point to buf or a static string
// - musl/macOS/WASM (XSI): returns int, always writes to buf
// - Windows: no strerror_r, uses strerror_s instead
//
// We check __GLIBC__ (not _GNU_SOURCE alone) because musl defines _GNU_SOURCE
// but always provides the XSI variant.
inline const char* falco_strerror_r(int errnum, char* buf, size_t len) {
#if defined(__GLIBC__) && defined(_GNU_SOURCE)
return strerror_r(errnum, buf, len);
#elif defined(_WIN32)
strerror_s(buf, len, errnum);
return buf;
#else
strerror_r(errnum, buf, len);
return buf;
#endif
}

View File

@@ -15,15 +15,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <cstdlib>
#ifndef _WIN32
#include <unistd.h>
#else
#include <stdlib.h>
#include <io.h>
#define srandom srand
#define random rand
#endif
#include <random>
#include <string>
#include <fstream>
#include <functional>
@@ -52,7 +49,7 @@ const std::string falco_engine::s_default_ruleset = "falco-default-ruleset";
using namespace falco;
falco_engine::falco_engine(bool seed_rng):
falco_engine::falco_engine(bool /* seed_rng */):
m_syscall_source(NULL),
m_syscall_source_idx(SIZE_MAX),
m_rule_reader(std::make_shared<rule_loader::reader>()),
@@ -62,10 +59,6 @@ falco_engine::falco_engine(bool seed_rng):
m_min_priority(falco_common::PRIORITY_DEBUG),
m_sampling_ratio(1),
m_sampling_multiplier(0) {
if(seed_rng) {
srandom((unsigned)getpid());
}
m_default_ruleset_id = find_ruleset_id(s_default_ruleset);
fill_engine_state_funcs(m_engine_state);
@@ -1007,6 +1000,8 @@ inline bool falco_engine::should_drop_evt() const {
return false;
}
double coin = (random() * (1.0 / RAND_MAX));
thread_local std::mt19937 rng(std::random_device{}());
std::uniform_real_distribution<double> dist(0.0, 1.0);
double coin = dist(rng);
return (coin >= (1.0 / (m_sampling_multiplier * m_sampling_ratio)));
}

View File

@@ -20,7 +20,7 @@ limitations under the License.
// The version of this Falco engine
#define FALCO_ENGINE_VERSION_MAJOR 0
#define FALCO_ENGINE_VERSION_MINOR 60
#define FALCO_ENGINE_VERSION_MINOR 61
#define FALCO_ENGINE_VERSION_PATCH 0
#define FALCO_ENGINE_VERSION \
@@ -36,4 +36,4 @@ limitations under the License.
// It represents the fields supported by this version of Falco,
// the event types, and the underlying driverevent schema. It's used to
// detetect changes in engine version in our CI jobs.
#define FALCO_ENGINE_CHECKSUM "17c1ac99576c032a58895a10f7091cf777008a1059b7f1bff3c78a6451b17fdf"
#define FALCO_ENGINE_CHECKSUM "cff88efbc5ebf54d4a0763342ac480da48880d9c6edf9f65c65cda5c1b1fdc7c"

View File

@@ -17,6 +17,7 @@ limitations under the License.
#include <nlohmann/json.hpp>
#include "compat.h"
#include "formats.h"
#include "falco_engine.h"
@@ -98,7 +99,9 @@ std::string falco_formats::format_event(sinsp_evt *evt,
char time_ns[12]; // sizeof ".sssssssssZ"
std::string iso8601evttime;
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
struct tm tm_buf;
falco_gmtime_r(&evttime, &tm_buf);
strftime(time_sec, sizeof(time_sec), "%FT%T", &tm_buf);
snprintf(time_ns, sizeof(time_ns), ".%09luZ", evt->get_ts() % 1000000000);
iso8601evttime = time_sec;
iso8601evttime += time_ns;

View File

@@ -16,6 +16,7 @@ limitations under the License.
*/
#include <ctime>
#include "compat.h"
#include "logger.h"
#include "falco_common.h"
@@ -122,14 +123,16 @@ void falco_logger::log(falco_logger::level priority, const std::string&& msg) {
std::time_t result = std::time(nullptr);
if(falco_logger::time_format_iso_8601) {
char buf[sizeof "YYYY-MM-DDTHH:MM:SS-0000"];
const struct tm* gtm = std::gmtime(&result);
if(gtm != NULL && (strftime(buf, sizeof(buf), "%FT%T%z", gtm) != 0)) {
struct tm gtm;
if(falco_gmtime_r(&result, &gtm) != NULL &&
(strftime(buf, sizeof(buf), "%FT%T%z", &gtm) != 0)) {
fprintf(stderr, "%s: %s", buf, copy.c_str());
}
} else {
const struct tm* ltm = std::localtime(&result);
struct tm ltm;
falco_localtime_r(&result, &ltm);
char tstr[std::size("WWW MMM DD HH:mm:ss YYYY")];
std::strftime(std::data(tstr), std::size(tstr), "%a %b %d %H:%M:%S %Y", ltm);
std::strftime(std::data(tstr), std::size(tstr), "%a %b %d %H:%M:%S %Y", &ltm);
fprintf(stderr, "%s: %s", tstr, copy.c_str());
}
}

View File

@@ -18,6 +18,7 @@ limitations under the License.
#include <functional>
#include "actions.h"
#include "compat.h"
#include "../app.h"
#include "../signals.h"
@@ -49,12 +50,10 @@ bool create_handler(int sig, void (*func)(int), run_result& ret) {
#ifdef __linux__
if(signal(sig, func) == SIG_ERR) {
char errbuf[1024];
if(strerror_r(errno, errbuf, sizeof(errbuf)) != 0) {
snprintf(errbuf, sizeof(errbuf) - 1, "Errno %d", errno);
}
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
ret = run_result::fatal(std::string("Could not create signal handler for ") +
strsignal(sig) + ": " + errbuf);
strsignal(sig) + ": " + errstr);
}
#endif
return ret.success;

View File

@@ -70,10 +70,7 @@ falco::app::run_result falco::app::actions::load_config(const falco::app::state&
std::chrono::system_clock::now().time_since_epoch())
.count();
// -U/--unbuffered CLI flag overrides the YAML config value
if(s.options.unbuffered_outputs) {
s.config->m_buffered_outputs = false;
}
s.config->m_buffered_outputs = !s.options.unbuffered_outputs;
return apply_deprecated_options(s);
}

View File

@@ -16,6 +16,7 @@ limitations under the License.
*/
#include "actions.h"
#include "compat.h"
#include "helpers.h"
#include "../app.h"
#include <fstream>
@@ -36,10 +37,13 @@ falco::app::run_result falco::app::actions::print_kernel_version(const falco::ap
std::ifstream input_file("/proc/version");
if(!input_file.is_open()) {
// We don't want to fail, we just need to log something
falco_logger::log(
falco_logger::level::INFO,
"Cannot read under '/proc/version' (err_message: '" + std::string(strerror(errno)) +
"', err_code: " + std::to_string(errno) + "). No info provided, go on.");
int saved_errno = errno;
char errbuf[256];
const char* errstr = falco_strerror_r(saved_errno, errbuf, sizeof(errbuf));
falco_logger::log(falco_logger::level::INFO,
"Cannot read under '/proc/version' (err_message: '" +
std::string(errstr) + "', err_code: " +
std::to_string(saved_errno) + "). No info provided, go on.");
return run_result::ok();
}

View File

@@ -20,6 +20,7 @@ limitations under the License.
#else
#include <windows.h>
#endif
#include "compat.h"
#include <iostream>
#include "actions.h"
@@ -95,7 +96,9 @@ falco::app::run_result falco::app::actions::print_support(falco::app::state& s)
nlohmann::json support;
if(get_sysinfo(support) != 0) {
return run_result::fatal(std::string("Could not get system info: ") + strerror(errno));
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
return run_result::fatal(std::string("Could not get system info: ") + errstr);
}
const falco::versions_info infos(s.offline_inspector);

View File

@@ -569,6 +569,9 @@ const char config_schema_string[] = LONG_STRING_CONST(
"plugins_metrics_enabled": {
"type": "boolean"
},
"kernel_iter_event_counters_enabled": {
"type": "boolean"
},
"convert_memory_to_mb": {
"type": "boolean"
},

View File

@@ -590,6 +590,9 @@ void falco_configuration::load_yaml(const std::string &config_name) {
if(m_config.get_scalar<bool>("metrics.plugins_metrics_enabled", true)) {
m_metrics_flags |= METRICS_V2_PLUGINS;
}
if(m_config.get_scalar<bool>("metrics.kernel_iter_event_counters_enabled", true)) {
m_metrics_flags |= METRICS_V2_KERNEL_ITER_COUNTERS;
}
if(m_config.get_scalar<bool>("metrics.jemalloc_stats_enabled", true)) {
m_metrics_flags |= METRICS_V2_JEMALLOC_STATS;
}

View File

@@ -59,6 +59,8 @@ namespace fs = std::filesystem;
- `libbpf_stats_enabled` -> Resides in libs; must be retrieved by the syscalls inspector;
not available for other inspectors.
- `plugins_metrics_enabled` -> Must be retrieved for each inspector.
- `kernel_iter_event_counters_enabled` -> Resides in libs; must be retrieved by the syscalls
inspector; not available for other inspectors.
- `jemalloc_stats_enabled` -> Agnostic; resides in falco; inspector is irrelevant;
only performed once.
*/
@@ -308,6 +310,7 @@ std::string falco_metrics::sources_to_text_prometheus(
// kernel_event_counters_enabled
// kernel_event_counters_per_cpu_enabled
// libbpf_stats_enabled
// kernel_iter_event_counters_enabled
auto metrics_collector =
libs::metrics::libs_metrics_collector(source_inspector.get(),
state.config->m_metrics_flags);

View File

@@ -16,6 +16,7 @@ limitations under the License.
*/
#include "falco_outputs.h"
#include "compat.h"
#include "config_falco.h"
#include "formats.h"
@@ -181,7 +182,9 @@ void falco_outputs::handle_msg(uint64_t ts,
char time_ns[12]; // sizeof ".sssssssssZ"
std::string iso8601evttime;
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
struct tm tm_buf;
falco_gmtime_r(&evttime, &tm_buf);
strftime(time_sec, sizeof(time_sec), "%FT%T", &tm_buf);
snprintf(time_ns, sizeof(time_ns), ".%09luZ", ts % 1000000000);
iso8601evttime = time_sec;
iso8601evttime += time_ns;

View File

@@ -16,6 +16,7 @@ limitations under the License.
*/
#include "outputs_program.h"
#include "compat.h"
#include "logger.h"
#include <stdio.h>
#include <cerrno>
@@ -26,9 +27,11 @@ void falco::outputs::output_program::open_pfile() {
m_pfile = popen(m_oc.options["program"].c_str(), "w");
if(m_pfile == nullptr) {
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
falco_logger::log(falco_logger::level::ERR,
"Failed to open program output: " + m_oc.options["program"] +
" (error: " + std::string(std::strerror(errno)) + ")");
" (error: " + errstr + ")");
return;
}
@@ -38,7 +41,7 @@ void falco::outputs::output_program::open_pfile() {
}
}
void falco::outputs::output_program::output(const message *msg) {
void falco::outputs::output_program::output(const message* msg) {
open_pfile();
if(m_pfile != nullptr) {

View File

@@ -24,6 +24,7 @@ limitations under the License.
#include <nlohmann/json.hpp>
#include "compat.h"
#include "falco_common.h"
#include "stats_writer.h"
#include "logger.h"
@@ -71,7 +72,9 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) {
memset(&handler, 0, sizeof(handler));
handler.sa_handler = &timer_handler;
if(sigaction(SIGALRM, &handler, NULL) == -1) {
err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno);
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
err = std::string("Could not set up signal handler for periodic timer: ") + errstr;
return false;
}
@@ -93,7 +96,9 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) {
memset(&handler, 0, sizeof(handler));
handler.sa_handler = &timer_handler;
if(sigaction(SIGALRM, &handler, NULL) == -1) {
err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno);
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
err = std::string("Could not set up signal handler for periodic timer: ") + errstr;
return false;
}
@@ -119,7 +124,9 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) {
memset(&handler, 0, sizeof(handler));
handler.sa_handler = &timer_handler;
if(sigaction(SIGALRM, &handler, NULL) == -1) {
err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno);
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
err = std::string("Could not set up signal handler for periodic timer: ") + errstr;
return false;
}
@@ -131,14 +138,18 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) {
// delete any previously set timer
if(s_timerid_exists) {
if(timer_delete(s_timerid) == -1) {
err = std::string("Could not delete previous timer: ") + strerror(errno);
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
err = std::string("Could not delete previous timer: ") + errstr;
return false;
}
s_timerid_exists = false;
}
if(timer_create(CLOCK_MONOTONIC, &sev, &s_timerid) == -1) {
err = std::string("Could not create periodic timer: ") + strerror(errno);
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
err = std::string("Could not create periodic timer: ") + errstr;
return false;
}
s_timerid_exists = true;
@@ -148,7 +159,9 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string& err) {
timer.it_interval = timer.it_value;
if(timer_settime(s_timerid, 0, &timer, NULL) == -1) {
err = std::string("Could not set up periodic timer: ") + strerror(errno);
char errbuf[256];
const char* errstr = falco_strerror_r(errno, errbuf, sizeof(errbuf));
err = std::string("Could not set up periodic timer: ") + errstr;
return false;
}
@@ -485,6 +498,7 @@ void stats_writer::collector::get_metrics_output_fields_additional(
// state_counters_enabled
// kernel_event_counters_enabled
// libbpf_stats_enabled
// kernel_iter_event_counters_enabled
// Refresh / New snapshot
auto& libs_metrics_collector = m_writer->m_libs_metrics_collectors[src];
@@ -508,7 +522,8 @@ void stats_writer::collector::get_metrics_output_fields_additional(
char metric_name[METRIC_NAME_MAX] = "falco.";
if((metric.flags & METRICS_V2_LIBBPF_STATS) ||
(metric.flags & METRICS_V2_KERNEL_COUNTERS) ||
(metric.flags & METRICS_V2_KERNEL_COUNTERS_PER_CPU)) {
(metric.flags & METRICS_V2_KERNEL_COUNTERS_PER_CPU) ||
(metric.flags & METRICS_V2_KERNEL_ITER_COUNTERS)) {
strlcpy(metric_name, "scap.", sizeof(metric_name));
}
if(metric.flags & METRICS_V2_PLUGINS) {
@@ -624,7 +639,8 @@ void stats_writer::collector::collect(const std::shared_ptr<sinsp>& inspector,
// Note: src is static for live captures
if(src != falco_common::syscall_source) {
flags &= ~(METRICS_V2_KERNEL_COUNTERS | METRICS_V2_KERNEL_COUNTERS_PER_CPU |
METRICS_V2_STATE_COUNTERS | METRICS_V2_LIBBPF_STATS);
METRICS_V2_STATE_COUNTERS | METRICS_V2_LIBBPF_STATS |
METRICS_V2_KERNEL_ITER_COUNTERS);
}
m_writer->m_libs_metrics_collectors[src] =
std::make_unique<libs::metrics::libs_metrics_collector>(inspector.get(), flags);