{#- Telemetry components, ported from the Dragon resources/*.dr helpers. Import WITH CONTEXT (they use `h`, the view helpers): {% import 'ui/telemetry/_t.html' as t with context %} JS strings: values interpolated into onclick handlers go through js() (JSON, every quote and angle bracket \u-escaped, then HTML-escaped for the attribute) or h.enc() (percent encoding), never raw, so a hostile service or metric name cannot break out. -#} {% import 'ui/kit.html' as kit %} {% macro js(value) %}{{ value|tojson|forceescape }}{% endmacro %} {% macro css() %}{% endmacro %} {% macro check_svg() %}{% endmacro %} {#- The time range control. `params` are the other query parameters to carry along. -#} {% macro rng(target, cur, params={}) %}
{%- for w in h.WINDOWS %} {%- endfor %}
{% endmacro %} {% macro opt(value, label, cur) %}{% endmacro %} {% macro service_options(seen, cur) %} {{ opt('', 'Every service', cur) }} {%- for s in seen %}{{ opt(s.service, s.service, cur) }}{% endfor %} {% endmacro %} {% macro hstat(value, label, tone='') %}
{{ value }}
{{ label }}
{% endmacro %} {% macro chip(label, value) %}{{ label }}{{ value }}{% endmacro %} {% macro pctl(label, value, note) %}
{{ label }}
{{ value }}
{{ note }}
{% endmacro %} {% macro card(n, label, tone, blurb) %}
{{ label }}
{{ n }}
{{ blurb }}
{% endmacro %} {% macro spark(vals, tone='') %} {%- set p = h.spark(vals) -%} {%- if not p.line -%} {%- else -%} {%- endif -%} {% endmacro %} {% macro kpi(label, value, unit, d, vals, tone, note) %}
{{ label }}{{ note }}
{{ value }}{{ unit }}
{{ spark(vals, tone) }}
{%- set tri %}{% endset -%} {%- if d[1] == 'up' %}{{ tri }}{{ d[0] }} {%- elif d[1] == 'down' %}{{ tri }}{{ d[0] }} {%- else %}{{ d[0] }}{% endif %}vs previous window
{% endmacro %} {#- The six golden-signal cards both APM pages share. `last` is (label, value, delta, note). -#} {% macro kpis(now_s, prev_s, points, w, last) %} {%- set counts = points|map(attribute='count')|list -%} {%- set errs = points|map(attribute='errors')|list -%} {%- set p95s = points|map(attribute='p95_us')|list -%} {%- set p99s = points|map(attribute='p99_us')|list -%} {%- set err_ppm = h.ppm(now_s.errors, now_s.count) -%} {%- set prev_ppm = h.ppm(prev_s.errors, prev_s.count) -%} {%- set err_tone = 'bad' if err_ppm >= 10000 else '' -%}
{{ kpi('Throughput', now_s.count, 'spans', h.delta(now_s.count, prev_s.count, True), counts, '', w.label) }} {{ kpi('Error rate', h.rate(now_s.errors, now_s.count), '', h.delta(err_ppm, prev_ppm, False), errs, err_tone, now_s.errors ~ ' errors') }} {{ kpi('p50 latency', h.dur(now_s.p50_us), '', h.delta(now_s.p50_us, prev_s.p50_us, False), p95s, '', 'median') }} {{ kpi('p95 latency', h.dur(now_s.p95_us), '', h.delta(now_s.p95_us, prev_s.p95_us, False), p95s, '', 'slowest 5%') }} {{ kpi('p99 latency', h.dur(now_s.p99_us), '', h.delta(now_s.p99_us, prev_s.p99_us, False), p99s, '', 'slowest 1%') }} {{ kpi(last[0], last[1], last[4], last[2], (p99s if last[5] else counts), '', last[3]) }}
{% endmacro %} {% macro health(points) %}

Health error rate per bucket across the window

clean under 1% 1% or more no traffic
{% for cls, title in h.health_cells(points) %}{% endfor %}
{%- set ax = h.axis(points) %}
{{ ax[0] }}{{ ax[1] }}{{ ax[2] }}
{% endmacro %} {% macro apm_charts(w, service) %}
{{ kit.chart_panel('Throughput', 'spans per bucket', 'ch-apm-tput') }} {{ kit.chart_panel('Latency', 'p50, p95 and p99', 'ch-apm-lat') }} {{ kit.chart_panel('Errors', 'error rate and count', 'ch-apm-err') }}
{% endmacro %} {% macro err_cell(errors, count) %} {%- if errors == 0 %}0.00% {%- else %}{{ h.rate(errors, count) }} {{ errors }}{% endif %} {% endmacro %} {% macro app_cell(app) %}{% if not app %}unclaimed{% else %}{{ app }}{% endif %}{% endmacro %} {% macro trace_err(n) %}{% if n == 0 %}0{% else %}{{ n }}{% endif %}{% endmacro %} {% macro dbar(v, mx, err) %}{{ h.dur(v) }}{% endmacro %} {% macro trace_table(rows, show_service) %} {%- if not rows %}

No traces in the live index

The explorer lists the root spans retained in this window. Errors, slow spans and traces carrying an amebo event are always retained; a specific trace stays readable by id.

{%- else %} {%- set mx = [1] + rows|map(attribute='duration_us')|list %} {%- set mx = mx|max %} {% if show_service %}{% endif %} {%- for r in rows %} {%- if show_service %}{% endif %} {%- endfor %}
traceroot spanserviceroute spanserrorsdurationwhen
{%- endif %} {% endmacro %} {#- The waterfall. `cap` bounds the inline rows on a page that is not the trace page. -#} {% macro waterfall(v, cap=0) %} {%- if not v.found %}

No retained spans for this trace

Traces are sampled: errors and slow spans are always kept, the rest at the configured sample rate.

{%- else %} {%- set shown = v.nodes[:cap] if cap > 0 else v.nodes %}
span
{% for left, label in h.ticks(v.duration_us) %}{{ label }}{% endfor %}
{%- for n in shown %}
{% for _ in range(n.depth) %}{% endfor %} {{ n.op }} {{ n.name }} {{ h.span_detail(n) }}
{{ h.dur(n.duration_us) }}
{%- endfor %}
{%- if v.nodes|length > shown|length %}
{{ v.nodes|length - shown|length }} more spans in the full trace
{% endif %}
{%- endif %} {% endmacro %} {% macro logrow(l, chip=False) %}
{{ h.clock_ms(l.ts_us) }} {{ l.severity }} {{ l.service }} {{ l.body }} {%- if chip and l.trace_id %} {{ l.trace_id[:8] }} {%- endif %}
{% endmacro %} {#- Every log line a trace emitted, oldest first. -#} {% macro trace_logs(lines) %} {%- if not lines %}

Logs nothing correlated

No log line carries this trace id. Emit logs through an OpenTelemetry SDK inside an active span, or send `trace_id` on POST /v1/logs, and they appear here automatically.

{%- else %}

Logs {{ lines|length }} lines this trace emitted, oldest first

{% for l in lines %}{{ logrow(l) }}{% endfor %}
{%- endif %} {% endmacro %} {% macro level_pill(level) %}{{ level }}{% endmacro %} {% macro status_pill(status) %} {%- if status == 'resolved' %}resolved {%- elif status == 'ignored' %}ignored {%- elif status == 'regressed' %}regressed {%- else %}ongoing{% endif %} {% endmacro %} {% macro prio(priority) %} {%- set bars = h.prio_bars(priority) -%} {% for i in range(1, 4) %}{% endfor %}{{ priority }} {%- endmacro %} {% macro trend(vals) %} {%- if not vals %}- {%- else %}{% endif %} {% endmacro %} {% macro assignee(who) %} {%- if not who %}? {%- else %}{{ who[:1]|upper }}{% endif %} {% endmacro %} {% macro empty(message, hint='') %}
{{ check_svg() }}

{{ message }}

{% if hint %}

{{ hint }}

{% endif %}
{% endmacro %} {% macro attrs_table(m) %} {% for k in m|sort %}{% endfor %}
{{ k }}{{ m[k] }}
{% endmacro %}