{% extends "base.html" %} {% import "_panel.html" as panel_macros %} {% block content %}

FTMON self-monitoring

Web process version {{ web_version }}.

Budgets

{% if panel %} {% macro history(metric, label) -%} 6h 24h history for {{ label }} {%- endmacro %} {{ panel_macros.budget_row( panel.cpu.row, '%.1f%%'|format(panel.cpu.row.value) if panel.cpu.row.value is not none else '', '%.1f%%'|format(panel.cpu.row.limit) if panel.cpu.row.limit else 'no threshold') }} {{ panel_macros.budget_row( panel.memory.row, panel_macros.bytes_mb(panel.memory.row.value), panel_macros.bytes_mb(panel.memory.row.limit)) }} {{ panel_macros.budget_row( panel.database.row, panel_macros.bytes_mb(panel.database.row.value), panel_macros.bytes_mb(panel.database.row.limit)) }}
Measured against this host's self.toml thresholds. RB-01's cross-platform targets are shown where they differ.
Current {% if panel.cpu.current is none %}—{% else %}{{ '%.1f'|format(panel.cpu.current) }}%{% endif %}, 10-minute average {% if panel.cpu.avg10m is none %}—{% else %}{{ '%.1f'|format(panel.cpu.avg10m) }}%{% endif %}. RB-01 target {{ '%.1f'|format(panel.cpu.row.spec) }}% of one core. {{ history('cpu_10m', 'CPU') }}
{{ history('rss_bytes', 'RSS') }}
Used pages are the DM-05 figure. File allocation {{ panel_macros.bytes_mb(panel.database.allocated) }}, of which {{ panel_macros.bytes_mb(panel.database.freelist) }} is reusable. Headroom to the 200 MB target {% if panel.database.headroom is none %}—{% else %}{{ panel_macros.bytes_mb(panel.database.headroom) }}{% endif %}. {{ history('db_used_bytes', 'used pages') }}

Catalog

Persisted {% if panel.catalog.entities_persisted is none %} not available yet — no daemon has published it {% else %} {{ panel.catalog.entities_persisted }} entities of {{ panel.catalog.max_entities_persisted }} (DM-16 budget), {{ panel.catalog.series_persisted }} series of {{ panel.catalog.max_series_persisted }} (worksheet assumption) {% endif %}
Promotion guardrail {% if panel.catalog.promotion_limited_monitors is none %} not available yet — no daemon has published it {% else %} {{ panel.catalog.promotion_limited_monitors }} monitors currently limited, {{ panel.catalog.promotion_rejections_total }} admissions refused since daemon start — {{ panel.catalog.promotion_limit_per_monitor }} promoted entities per monitor {% endif %}
Running {{ panel.catalog.entities_not_gone }} entities, {{ panel.catalog.series_not_gone }} series — present, not persisted; not budget figures
Reap {{ panel_macros.age(panel.catalog.reap_age_s) }}{% if panel.catalog.reap_count is not none %}, {{ panel.catalog.reap_count }} removed{% endif %}
Degradation {{ panel_macros.age(panel.catalog.degradation_age_s) }}

Retained catalog by monitor

{% if panel.catalog.monitor_attribution.monitors %} {% for item in panel.catalog.monitor_attribution.monitors %} {% endfor %}
Catalog rows retained for each monitor. Present entities are running or otherwise present; they are not per-monitor persisted-selection pressure.
Monitor Present entities Gone entities Total entities Total series
{{ item.monitor }} {{ item.entities_present }} {{ item.entities_gone }} {{ item.entities_total }} {{ item.series_total }}
{% if panel.catalog.monitor_attribution.monitors_truncated %}

Showing {{ panel.catalog.monitor_attribution.monitors_returned }} of {{ panel.catalog.monitor_attribution.monitors_matched }} monitors, ordered by retained series and entity count.

{% endif %} {% else %}

No retained monitor catalog rows.

{% endif %}

Where the tick goes

{# Rates, not the cumulative counters: total seconds since start answer no operator question. rejectattr('pct','none') rather than selectattr, because a measured 0.0% is a reading -- a stage that genuinely did no work in the window -- and truthiness would report it as uncollected. #} {% if panel.stages.stages | rejectattr('pct', 'none') | list %} {% for stage in panel.stages.stages if stage.pct is not none %} {% endfor %}
Share of one core over the last {{ '%.1f'|format((panel.stages.elapsed_s or panel.stages.window_s) / 3600) }} h, from counter deltas. Sampling source rows partition sampling; the five phase rows partition pipeline; prune and reap are parts of retention. Child rows are explanations, not additional tick cost. exempt includes building each entity's evaluation context, which it consumes first, so a monitor declaring no exemptions still shows a non-zero exempt share.
StageRelationship ShareTime
{{ stage.name }} {{ 'part of ' ~ stage.parent if stage.parent else 'top level' }} {{ '%.2f'|format(stage.pct) }}% {{ '%.1f'|format(stage.seconds) }}s
{% elif panel.stages.reset %}

The daemon restarted inside this window, so the counters went backwards and no rate can be derived yet.

{% else %}

Per-stage rates need at least two samples. Until then, the budgets above say whether the daemon is within its limits but not where its time goes.

{% endif %} {% else %}

No database yet.

{% endif %}

Notification delivery

{% if dispatch %}
Dispatcher {{ dispatch.state }} ({{ dispatch.mode }}){% if dispatch.last_error_category %} — last error {{ dispatch.last_error_category }}{% endif %}
Pending {{ dispatch.pending_total }} ({{ dispatch.due_claimable }} due, {{ dispatch.quiet_held }} held by quiet hours)
Oldest claimable {{ dispatch.oldest_claimable_due_age_s|round|int }}s
Failed {{ dispatch.failed }}{% if dispatch.failed_by_channel %} — {% for channel, count in dispatch.failed_by_channel.items() %}{{ channel }}={{ count }}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}
{% else %}

No database yet.

{% endif %}

All self metrics

{% for row in metrics %}{% else %}{% endfor %}
{{ row.metric }}{{ row.value }}
No self metrics yet.

Configuration errors

{% for path,error in config_errors %}
{{ path.name }}: {{ error }}
{% else %}

None.

{% endfor %}

Daemon log tail

{{ log_tail }}
{% endblock %}