Logging and Metrics#

The core’s logging sink and the run output: the metric groups behind performance_log.csv and the writers of the run directory’s files. Run Output and Analysis lists every file and column.

Logging#

namespace logging#

Typedefs

using Sink = std::function<void(Severity, const std::string&)>#

Enums

enum class Severity#

Ordered by increasing severity; setMinSeverity filters against this order.

Values:

enumerator kDebug#
enumerator kInfo#
enumerator kWarning#
enumerator kError#
enumerator kFatal#

Functions

void debug(const std::string &text)#
void error(const std::string &text)#
void fatal(const std::string &text)#
void info(const std::string &text)#
void setMinSeverity(Severity min_severity)#

Drops messages below min_severity. Default is Info (Debug is off).

void setSink(Sink sink)#

Replaces the message backend. Pass nullptr to restore the default timestamped stdout/stderr sink. Safe to call concurrently with logging.

void warning(const std::string &text)#

Metrics#

struct Metrics#
#include <open_apero_core/logging/metrics.h>

Common reset and field-declaration interface for metric groups.

Subclasses declare each field once in declareFields(), chaining the base first so base columns precede derived ones; PerformanceLog handles serialization.

Subclassed by open_apero::AgentMetrics, open_apero::LayerMetrics

Public Functions

template<class T>
inline T *as()#

Downcast to a derived metrics type.

Template Parameters:

T – The target derived type.

Returns:

Pointer to the derived type, or nullptr if the cast fails.

virtual void declareFields(MetricsFields &fields) const = 0#

Declares this group’s fields as {column name, field pointer} pairs.

Parameters:

fields – Collector the fields are appended to in column order.

virtual void resetCycle() = 0#

Clears the per-cycle fields; the agent calls it once a cycle has selected its step, after the cycle’s CSV row (if any).

virtual void resetEpisode() = 0#

Clears the per-episode totals; called when the owning agent or layer resets for a new episode.

virtual ~Metrics() = default#
class MetricsFields#
#include <open_apero_core/logging/metrics.h>

Ordered collection of named metric fields declared by a Metrics group.

Each field pairs a column name with a pointer to the live value, plus a unit and an optional parent for the run manifest. Registered pointers must outlive the collection.

Public Types

using Value = std::variant<const double*, const int*>#

Public Functions

inline void add(std::string name, const double *value, std::string unit = "", ParentRef parent = {})#
inline void add(std::string name, const int *value, std::string unit = "", ParentRef parent = {})#
inline const std::vector<Field> &fields() const#
struct Field#
#include <open_apero_core/logging/metrics.h>

Public Members

std::string name#
ParentRef parent#

Enclosing timer, or ParentRef::none().

std::string unit#

Unit string (e.g. “s”, “m”, “count”); “” if none/dynamic.

Value value#
struct ParentRef#
#include <open_apero_core/logging/metrics.h>

Reference to the timer whose wall time wholly contains a field’s, for nesting.

kLocal resolves to “<prefix>.<name>” within the same metric group; kGlobal to the unprefixed agent-level “<name>”.

Public Types

enum class Scope#

Values:

enumerator kNone#
enumerator kLocal#
enumerator kGlobal#

Public Members

std::string name#

Unqualified parent column (leaf) name.

Scope scope = Scope::kNone#

Public Static Functions

static inline ParentRef global(std::string name)#
static inline ParentRef local(std::string name)#
static inline ParentRef none()#
struct AgentMetrics : public open_apero::Metrics#
#include <open_apero_core/agent/agent_metrics.h>

Per-cycle and cumulative metrics owned by Agent.

Per-cycle fields are reset after every replan by resetCycle(); cumulative and row-identity fields only by resetEpisode(). Subclasses add fields by overriding the virtuals and chaining.

Subclassed by open_apero::ros::RosAgentMetrics

Public Functions

inline virtual void declareFields(MetricsFields &fields) const override#

Declares this group’s fields as {column name, field pointer} pairs.

Parameters:

fields – Collector the fields are appended to in column order.

inline virtual void resetCycle() override#

Clears the per-cycle fields; the agent calls it once a cycle has selected its step, after the cycle’s CSV row (if any).

inline virtual void resetEpisode() override#

Clears the per-episode totals; called when the owning agent or layer resets for a new episode.

Public Members

int commands_dispatched = 0#

Movement commands published since the previous replan.

int cycle_index = 0#

Zero-based index of this planning cycle within the episode.

double elapsed_wall_time_s = 0.0#

Monotonic (steady_clock) seconds since episode start.

int frames_mapped = 0#

Frames the map reports integrating since the previous replan.

int num_visited_nodes = 0#

Executed edges (steps) since planning started, recovery steps included.

double plan_path_total_s = 0.0#

Aggregate Layer::planPath time across every layer attempted this cycle (the priority sort is outside the timer).

double replan_time_wall_s = 0.0#

Wall-clock elapsed time since the previous replan call [s].

double total_cost = 0.0#

Sum of executed edge costs (unit set by the cost computer).

double total_path_duration = 0.0#

Sum of executed trajectory durations [s].

double total_path_length = 0.0#

Sum of executed trajectory lengths [m].

double visualization_s = 0.0#

Time building and publishing all markers (graph, map, robot, path, trajectory).

struct LayerMetrics : public open_apero::Metrics#
#include <open_apero_core/plugin/layer/layer_metrics.h>

Subclassed by open_apero::layer::BacktrackingLayerMetrics, open_apero::layer::PlanningLayerMetrics

Public Functions

inline virtual void declareFields(MetricsFields &fields) const override#

Declares this group’s fields as {column name, field pointer} pairs.

Parameters:

fields – Collector the fields are appended to in column order.

inline virtual void resetCycle() override#

Clears the per-cycle fields; the agent calls it once a cycle has selected its step, after the cycle’s CSV row (if any).

inline virtual void resetEpisode() override#

Clears the per-episode totals; called when the owning agent or layer resets for a new episode.

Public Members

double expand_s = 0.0#
double plan_path_s = 0.0#
int times_selected_as_winner = 0#
double update_s = 0.0#
struct PlanningLayerMetrics : public open_apero::LayerMetrics#
#include <open_apero_core/plugin/layer/planning_layer_metrics.h>

Public Functions

inline virtual void declareFields(MetricsFields &fields) const override#

Declares this group’s fields as {column name, field pointer} pairs.

Parameters:

fields – Collector the fields are appended to in column order.

inline virtual void resetCycle() override#

Clears the per-cycle fields; the agent calls it once a cycle has selected its step, after the cycle’s CSV row (if any).

Public Members

double evaluate_node_s = 0.0#

Time evaluating the gain of each newly generated node.

double evaluator_update_s = 0.0#

Time in Evaluator::updateEvaluation() to refresh gain estimates.

double generate_edge_s = 0.0#

Time in GraphGenerator::generateNewEdges().

double generate_node_s = 0.0#

Time in GraphGenerator::generateNewNode() across all expansion attempts.

double generator_update_s = 0.0#

Time in GraphGenerator::updateNodeEdge() inside update() (strictly ⊂ UpdateTime).

int num_expansions = 0#

Number of expansion rounds run inside expand() this cycle.

int num_nodes_after_expansion = 0#

Graph size after this cycle’s start-node update, update and expansion.

int num_nodes_after_new_start = 0#

Graph size after the setNewStartNode() prune pass.

int num_nodes_at_selection = 0#

Graph size at the time of next-best-view selection.

double planned_value = 0.0#

Value of the graph candidate selected before final trajectory validation. May be nonzero when the layer declines it; TimesSelected records accepted layer wins.

double real_accumulated_gain = 0.0#

The evaluator’s accumulated gain, read in onStateReached() at the start of the cycle.

double start_node_update_s = 0.0#

Time updating the start node: GraphGenerator::setNewStartNode() and insertIntermediateNodeAtCurrentState() in onStateReached() (outside update()).

struct BacktrackingLayerMetrics : public open_apero::LayerMetrics#
#include <open_apero_core/plugin/layer/backtracking_layer_metrics.h>

Public Functions

inline virtual void declareFields(MetricsFields &fields) const override#

Declares this group’s fields as {column name, field pointer} pairs.

Parameters:

fields – Collector the fields are appended to in column order.

inline virtual void resetCycle() override#

Clears the per-cycle fields; the agent calls it once a cycle has selected its step, after the cycle’s CSV row (if any).

Public Members

Backtracker *backtracker = nullptr#

The strategy whose columns ride along; set once it exists.

class ScopedTimer#
#include <open_apero_core/logging/scoped_timer.h>

Measures elapsed wall-clock time [s] from construction to destruction and adds it to a caller-supplied accumulator. A no-op (no clock reads, no writes) when disabled.

Public Functions

ScopedTimer &operator=(const ScopedTimer&) = delete#
ScopedTimer(const ScopedTimer&) = delete#
inline ScopedTimer(double &accumulator, bool enabled)#
inline ~ScopedTimer()#

Run Output#

class PerformanceLog#
#include <open_apero_core/logging/performance_log.h>

Writes registered metric groups to a per-cycle performance CSV.

Header and rows derive from the same field declarations; column prefixes are applied here. Registered Metrics objects must outlive this log.

Public Functions

void addMetrics(const Metrics &metrics, const std::string &prefix = "")#

Registers a metric group’s fields as columns.

Must be called for all groups before open(); registering afterwards throws std::logic_error, as the header is already written. Columns appear in registration order, fields in declaration order within each group.

Parameters:
  • metrics – The metric group; must outlive this log.

  • prefix – Optional column prefix, emitted as “<prefix>.<Name>”.

void close()#
inline const std::vector<Column> &columns() const#

Registered columns in output order (for the manifest / fingerprint).

inline bool isOpen() const#
bool open(const std::string &file_path)#

Opens the CSV file and writes the header line.

Parameters:

file_path – Path of the CSV file to create.

Returns:

True if the file was opened successfully.

void writeRow()#

Appends one row with the current value of every registered field.

Flushes after the row so data survives a crash mid-episode.

struct Column#
#include <open_apero_core/logging/performance_log.h>

One resolved output column: name, live value, and manifest metadata.

Populated at addMetrics(); the run manifest reads these to record units and the fully-qualified timer nesting, and to compute the schema fingerprint.

Public Members

std::string name#

Fully-qualified column name (prefix applied).

std::string qualified_parent#

Resolved parent column name, or “”.

std::string type#

“double” or “int”.

std::string unit#

Unit string, or “” if none/dynamic.

MetricsFields::Value value#

Live field pointer read on writeRow().

struct RunManifest#
#include <open_apero_core/logging/run_manifest.h>

Public Functions

std::string serialize() const#

Renders the complete manifest YAML.

Fills the schema fingerprint, git provenance (build-time), and UTC start time internally. Pure: touches no filesystem, so write() can fail before it has created anything.

bool write(const std::string &path, std::string *error_message = nullptr) const#

Publishes the manifest YAML at path, completely or not at all.

Returns false, leaving path untouched and no temporary behind, if path already exists or any step fails; error_message, when given, names the failed operation and errno cause.

Public Members

std::vector<PerformanceLog::Column> columns#

Schema: drives units + fingerprint.

std::optional<double> cost_budget#

Omitted from YAML when unset.

int format_version = kRunManifestFormatVersion#
std::vector<std::pair<std::string, std::string>> layers#

instanceName -> layerName.

std::optional<int> random_seed#

Agent random_seed (-1 = nondeterministic); omitted when unset.

struct EpisodeSummary#
#include <open_apero_core/logging/episode_summary.h>

Public Functions

std::string serialize() const#

Renders the YAML: keys in declaration order, doubles with 15 significant digits.

bool write(const std::string &path, std::string *error_message = nullptr) const#

Writes the YAML to path, atomically replacing an earlier summary.

Returns:

False on failure, leaving any earlier file and no temporary behind; error_message, when given, names the failed operation and errno cause.

Public Members

double cost_budget = 0.0#

The episode’s cost budget; written as .inf when unbounded.

int cycles = 0#

Planning cycles that dispatched a step: the rows of performance_log.csv.

double elapsed_wall_time_s = 0.0#

Steady clock since episode start [s].

std::string end_reason#

budget_exhausted, goal_reached, no_step or stopped.

int format_version = kEpisodeSummaryFormatVersion#
int num_visited_nodes = 0#

Executed edges (steps), recovery steps included.

std::vector<std::pair<std::string, double>> real_accumulated_gain#

Layer instance name -> gain, layers that report one.

double total_cost = 0.0#

Sum of executed edge costs.

double total_path_duration = 0.0#

[s]

double total_path_length = 0.0#

[m]