Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webserver): implement metrics endpoint #3140

Merged
merged 22 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
aa4ae6f
feat(webserver): implement metrics endpoint
sgaist Mar 15, 2024
d527083
fix(webserver): correct enabled check
sgaist Mar 19, 2024
1bb9b4e
fix(webserver): remove extra line return
sgaist Mar 19, 2024
e0f9c92
fix(webserver): use falcosecurity as metric namespace
sgaist Mar 19, 2024
d6e980e
refactor(webserver): move metrics endpoint activation under webserver
sgaist Mar 22, 2024
0cf84c8
refactor(configuration): move webserver items in own struct
sgaist Mar 24, 2024
beda9dd
refactor(metrics): move metrics handling to its own class
sgaist Mar 26, 2024
9d3e602
fix(metrics): correct metrics namespace
sgaist Mar 29, 2024
d575380
fix(metrics): correct static metrics
sgaist Mar 29, 2024
c940ceb
fix(metrics): correct hostname metrics name and namespace
sgaist Apr 4, 2024
71e1783
doc(falco_metrics): add basic documentation
sgaist Apr 10, 2024
459f4bd
refactor(falco_metrics): put content type in documented constant
sgaist Apr 10, 2024
aa0e813
refactor(metrics): make to_text get the application state
sgaist Apr 16, 2024
34436d6
refactor(metrics): use prometheus_metrics_enabled for configuration
sgaist Apr 16, 2024
6746e3b
feat(falco_metrics): add outputs_queue_num_drops
sgaist Apr 21, 2024
2c2db8d
feat(falco_metrics): add duration_sec
sgaist Apr 21, 2024
2a60be3
feat(falco_metrics): add event sources
sgaist Apr 21, 2024
494ecc2
fix(falco_metrics): remove redundant falco in version metrics
sgaist Apr 24, 2024
934df4c
fix(falco_metrics): make duration_sec a count and not a timestamp
sgaist Apr 24, 2024
b587754
chore(configuration): add reference to Prometheus endpoint in metrics…
sgaist Apr 24, 2024
815af40
fix(falco_metrics): make duration_sec and outputs_queue_num_drops mon…
sgaist Apr 24, 2024
77a6a71
fix(falco_metrics): remove falco_ prefix for version
sgaist Apr 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions falco.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ webserver:
# Can be an IPV4 or IPV6 address, defaults to IPV4
listen_address: 0.0.0.0
k8s_healthz_endpoint: /healthz
metrics_enabled: false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure we want to overload the listen_port or instead add another metrics_port config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that the same webserver would serve both endpoints.
This brings the following question: should we have different web server instance for the metrics part ?

Copy link
Contributor

@incertum incertum Apr 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair, you actually asked me at the beginning if we should just use the existing webserver and I said yes as for me I was referring to existing code ... What would you suggest? Or what is better practice if you want to expose multiple ports? @FedeDP what's you take on this?

I personally never set up webservers, instead if anything I tried to break into them in the past 🙃 .

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should reuse the same webserver we already use; having everything on the same ports on different endpoints is ok from my PoV, indeed it is better to remember "right, on port X there is Falco webserver".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok then it seems settled, we keep it as is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have used metrics_enabled as I though that, while using Prometheus currently, it would be subject to change so rather than having the name hard coded in the option name, having just "web server will also provide a metrics end point" would be simpler for admins in the long run.

I agree.

Maybe providing a metrics_backend at a later stage to allow switching would be cleaner and clearer.

  • Use metrics_enabled with a comment stating that it's currently Prometheus that is the backend

@sgaist This works for me too 👍

perhaps metrics_backend should be an array of strings similar to the plugins config setup.

@incertum We noticed that an array of strings does not play well with the -o command line flag. So, I'd recommend using multiple _enabled options so that it's easy to do -o foo.bar_enabled=true.
Again, I strongly believe we have to re-audit all config options and make them consistent, but it's out of scope for this PR, so I'd leave this decision for later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we might want to call the config prometheus_enabled?
Anyway, metrics_enabled works fine for me too. I'd avoid the complexity to deal with possible multiple metrics backend atm.
We can always introduce the new feat as Incubating to be able to play with it and be free to drop it/rename it in the future: https://github.com/falcosecurity/falco/blob/master/proposals/20231220-features-adoption-and-deprecation.md#maturation-levels

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right @leogr re arrays configs. @FedeDP would then just prometheus_metrics_enabled be ok? I believe it could be beneficial for this to show up when string searching for metrics. In addition, its even clearer for newbies to metrics.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1! Looks fine to me!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a look at this. To make the config file easier to use I think it's important to highlight that you need both metrics_enabled and metrics.enabled to true in order for this to have any effect. So I would suggest prometheus_metrics_enabled with a comment that mentions that this only does something if metrics.enabled is true.

Technically I would also be ok with setting prometheus_metrics_enabled to true since metrics are disabled by default but maybe let's do it after the support is stable.

ssl_enabled: false
ssl_certificate: /etc/falco/falco.pem

Expand Down
2 changes: 1 addition & 1 deletion unit_tests/falco/test_configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ TEST(Configuration, configuration_webserver_ip)

EXPECT_NO_THROW(falco_config.init(cmdline_config_options));

ASSERT_EQ(falco_config.m_webserver_listen_address, address);
ASSERT_EQ(falco_config.m_webserver_config.m_listen_address, address);
}

std::vector<std::string> invalid_addresses = {"327.0.0.1",
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,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_server_impl.cpp
Expand Down
38 changes: 19 additions & 19 deletions userspace/falco/app/actions/start_webserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,56 +19,56 @@ limitations under the License.

#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "webserver.h"
#include "falco_metrics.h"
#endif

using namespace falco::app;
using namespace falco::app::actions;

falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s)
falco::app::run_result falco::app::actions::start_webserver(falco::app::state& state)
{
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
if(!state.is_capture_mode() && state.config->m_webserver_enabled)
{
if (s.options.dry_run)
if (state.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping starting webserver in dry-run\n");
return run_result::ok();
}

std::string ssl_option = (s.config->m_webserver_ssl_enabled ? " (SSL)" : "");
falco_configuration::webserver_config webserver_config = state.config->m_webserver_config;
std::string ssl_option = (webserver_config.m_ssl_enabled ? " (SSL)" : "");
falco_logger::log(falco_logger::level::INFO, "Starting health webserver with threadiness "
+ std::to_string(s.config->m_webserver_threadiness)
+ std::to_string(webserver_config.m_threadiness)
+ ", listening on "
+ s.config->m_webserver_listen_address
+ webserver_config.m_listen_address
+ ":"
+ std::to_string(s.config->m_webserver_listen_port)
+ std::to_string(webserver_config.m_listen_port)
+ ssl_option + "\n");

s.webserver.start(
s.offline_inspector,
s.config->m_webserver_threadiness,
s.config->m_webserver_listen_port,
s.config->m_webserver_listen_address,
s.config->m_webserver_k8s_healthz_endpoint,
s.config->m_webserver_ssl_certificate,
s.config->m_webserver_ssl_enabled);
falco_metrics metrics(state);

state.webserver.start(
state.offline_inspector,
webserver_config,
metrics);
}
#endif
return run_result::ok();
}

falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& s)
falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& state)
{
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
if(!state.is_capture_mode() && state.config->m_webserver_enabled)
{
if (s.options.dry_run)
if (state.options.dry_run)
{
falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping webserver in dry-run\n");
return run_result::ok();
}

s.webserver.stop();
state.webserver.stop();
}
#endif
return run_result::ok();
Expand Down
26 changes: 11 additions & 15 deletions userspace/falco/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ falco_configuration::falco_configuration():
m_grpc_enabled(false),
m_grpc_threadiness(0),
m_webserver_enabled(false),
m_webserver_threadiness(0),
m_webserver_listen_port(8765),
m_webserver_listen_address("0.0.0.0"),
m_webserver_k8s_healthz_endpoint("/healthz"),
m_webserver_ssl_enabled(false),
m_syscall_evt_drop_threshold(.1),
m_syscall_evt_drop_rate(.03333),
m_syscall_evt_drop_max_burst(1),
Expand Down Expand Up @@ -372,21 +367,22 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false);

m_webserver_enabled = config.get_scalar<bool>("webserver.enabled", false);
m_webserver_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0);
m_webserver_listen_port = config.get_scalar<uint32_t>("webserver.listen_port", 8765);
m_webserver_listen_address = config.get_scalar<std::string>("webserver.listen_address", "0.0.0.0");
if(!re2::RE2::FullMatch(m_webserver_listen_address, ip_address_re))
m_webserver_config.m_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0);
m_webserver_config.m_listen_port = config.get_scalar<uint32_t>("webserver.listen_port", 8765);
m_webserver_config.m_listen_address = config.get_scalar<std::string>("webserver.listen_address", "0.0.0.0");
if(!re2::RE2::FullMatch(m_webserver_config.m_listen_address, ip_address_re))
{
throw std::logic_error("Error reading config file (" + config_name + "): webserver listen address \"" + m_webserver_listen_address + "\" is not a valid IP address");
throw std::logic_error("Error reading config file (" + config_name + "): webserver listen address \"" + m_webserver_config.m_listen_address + "\" is not a valid IP address");
}

m_webserver_k8s_healthz_endpoint = config.get_scalar<std::string>("webserver.k8s_healthz_endpoint", "/healthz");
m_webserver_ssl_enabled = config.get_scalar<bool>("webserver.ssl_enabled", false);
m_webserver_ssl_certificate = config.get_scalar<std::string>("webserver.ssl_certificate", "/etc/falco/falco.pem");
if(m_webserver_threadiness == 0)
m_webserver_config.m_k8s_healthz_endpoint = config.get_scalar<std::string>("webserver.k8s_healthz_endpoint", "/healthz");
m_webserver_config.m_ssl_enabled = config.get_scalar<bool>("webserver.ssl_enabled", false);
m_webserver_config.m_ssl_certificate = config.get_scalar<std::string>("webserver.ssl_certificate", "/etc/falco/falco.pem");
if(m_webserver_config.m_threadiness == 0)
{
m_webserver_threadiness = falco::utils::hardware_concurrency();
m_webserver_config.m_threadiness = falco::utils::hardware_concurrency();
}
m_webserver_config.m_metrics_enabled = config.get_scalar<bool>("webserver.metrics_enabled", false);

std::list<std::string> syscall_event_drop_acts;
config.get_sequence(syscall_event_drop_acts, "syscall_event_drops.actions");
Expand Down
17 changes: 11 additions & 6 deletions userspace/falco/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ class falco_configuration
std::string m_root;
};

struct webserver_config {
uint32_t m_threadiness = 0;
uint32_t m_listen_port = 8765;
std::string m_listen_address = "0.0.0.0";
std::string m_k8s_healthz_endpoint = "/healthz";
bool m_ssl_enabled = false;
std::string m_ssl_certificate;
bool m_metrics_enabled = false;
};

falco_configuration();
virtual ~falco_configuration() = default;

Expand Down Expand Up @@ -120,12 +130,7 @@ class falco_configuration
std::string m_grpc_root_certs;

bool m_webserver_enabled;
uint32_t m_webserver_threadiness;
uint32_t m_webserver_listen_port;
std::string m_webserver_listen_address;
std::string m_webserver_k8s_healthz_endpoint;
bool m_webserver_ssl_enabled;
std::string m_webserver_ssl_certificate;
webserver_config m_webserver_config;

syscall_evt_drop_actions m_syscall_evt_drop_actions;
double m_syscall_evt_drop_threshold;
Expand Down
120 changes: 120 additions & 0 deletions userspace/falco/falco_metrics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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("hostname", "falcosecurity", "evt", {{"hostname", machine_info->hostname}});

std::vector<metrics_v2> static_metrics;
static_metrics.push_back(libs_metrics_collector.new_metric("start_ts",
sgaist marked this conversation as resolved.
Show resolved Hide resolved
METRICS_V2_MISC,
METRIC_VALUE_TYPE_U64,
METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS,
METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT,
agent_info->start_ts_epoch));
static_metrics.push_back(libs_metrics_collector.new_metric("host_boot_ts",
METRICS_V2_MISC,
METRIC_VALUE_TYPE_U64,
METRIC_VALUE_UNIT_TIME_TIMESTAMP_NS,
METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT,
machine_info->boot_ts_epoch));
static_metrics.push_back(libs_metrics_collector.new_metric("host_num_cpus",
METRICS_V2_MISC,
METRIC_VALUE_TYPE_U32,
METRIC_VALUE_UNIT_COUNT,
METRIC_VALUE_METRIC_TYPE_NON_MONOTONIC_CURRENT,
machine_info->num_cpus));

for (auto metrics: static_metrics)
incertum marked this conversation as resolved.
Show resolved Hide resolved
{
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& metrics: metrics_snapshot)
{
prometheus_metrics_converter.convert_metric_to_unit_convention(metrics);
std::string namespace_name = "scap";
if (metrics.flags & METRICS_V2_RESOURCE_UTILIZATION || metrics.flags & METRICS_V2_KERNEL_COUNTERS)
{
namespace_name = "falco";
}
prometheus_text += prometheus_metrics_converter.convert_metric_to_text_prometheus(metrics, "falcosecurity", namespace_name);
}

}
return prometheus_text;
}
38 changes: 38 additions & 0 deletions userspace/falco/falco_metrics.h
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sgaist would you mind getting me up to speed why we need a vector with inspectors? Thanks!
Plus you still have an open question around sinsp and config init sequences etc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to the initialization state of the sinsp objects when starting the webserver.

In my original implementation, all static stuff was created in the constructor of the falco_metrics but since the machine_info and agent_info objects are null pointers at that point, it's not doable. Hence I am currently keeping them as they cannot be retrieved through the converter class.

It's a temporary design to have something working that we can discuss about.

Copy link
Contributor

@incertum incertum Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FedeDP @Andreagit97 plz advice, do we really need the vectors here because of the various source_infos. https://github.com/falcosecurity/falco/pull/3140/files#diff-0ebdd484eb8f6b10eb0df365c052ec7a91640bd6502ac3a7af1da82d9e62f3b1R31. We don't distinguish between the source info for the stats_writer either ... conversely maybe we should. Right now we primarily advertise metrics for syscalls source -- it's not properly working for plugin only either atm given the scap refactor regression.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd cc @jasondellaluce on this point, he might be able to help us :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't falco_metrics::to_text just take falco::app::state& as an argument? That way we avoid maintaining raw pointers all around the place. Also, why is falco::app::state declared with a forward declaration few lines above. What's the intention there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FedeDP @jasondellaluce @leogr +1 would appreciate final guidance on what you prefer so that we can get this over the finish line. Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have strong opinions, but I agree with this 👇

avoid maintaining raw pointers all around the place

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re. the raw pointers, generally non-owning raw pointers are fine but the problems we can have is when these objects are free'd or reallocated by their owners.

I don't completely remember the complete mechanism that happens in the restart case, but will this work if Falco is restarted, e.g. when a rule is replaced and Falco auto-reloads (therefore rebuilding inspectors)? iirc it should but could you please double check?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any issue with re-implementing this part passing the application state as parameter of the to_text method, I would just like to have an agreement about which architecture we would like to adopt.

I see your point about creating non-mutating info at construction time, however I think that these non-owning raw pointers can create more harm than benefit. The issue is that they rely on leaked knowledge about:

  • The order in which inspectors are allocated in the state, which is transitively dependent on how event sources are ordered, taking also for granted that this order won't change (which is like so now, but who knows later on)
  • The lifecycle of these inspectors, meaning at "which point" in their initialization process they are (plugins, configs, captures being open, etc..), which is strongly dependent on the execution flow and the app actions ordering

So IMO it's not just the raw pointer (that could be solved by making it owner through a shared_ptr instance), but more that we leak implicit knowledge about other parts of the codebase. IMO, moving everything in to_text is clearer, meaning that the invoker of that method has responsibility of having everything in the right preconditions before invocation time, and doesn't have to care about small parts being retained. If re-computation is a concern, you can consider stateful lazy caching mechanisms (e.g. after getting a non-mutating metric the first time, save it in the state and don't re-compute it again).

I'm not gonna fight for this of course, but this is my point overall.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to your excellent points, I did not take into account the dynamic reloading use case which also goes in the favor of your suggested implementation so I will do that.

I think the lazy caching is a good idea for a follow up PR.

std::vector<libs::metrics::libs_metrics_collector> m_metrics_collectors;
};
Loading
Loading