Skip to content

Commit ffa59dd

Browse files
committed
Improving Metrics diagnostics page
1 parent b0b2534 commit ffa59dd

1 file changed

Lines changed: 75 additions & 13 deletions

File tree

  • apps/api-manager/src/routes/(protected)/metrics-diagnostics

apps/api-manager/src/routes/(protected)/metrics-diagnostics/+page.svelte

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
const config = $derived(diagnostics?.config);
1717
const metric = $derived(diagnostics?.metric);
1818
const metricArchive = $derived(diagnostics?.metric_archive);
19+
const lastRun = $derived(diagnostics?.last_run);
20+
const lastSuccessfulRun = $derived(diagnostics?.last_successful_run);
1921
const checks = $derived(diagnostics?.checks ?? []);
2022
const everythingAsExpected = $derived(
2123
diagnostics?.everything_as_expected ?? false,
@@ -38,32 +40,59 @@
3840
return `${days.toLocaleString()} day${days === 1 ? "" : "s"}`;
3941
}
4042
41-
// Check names are descriptive slugs, not OBP props — drop the underscores so
42-
// they don't masquerade as prop names. Actual props are printed verbatim.
43-
function humanize(name: string): string {
44-
const s = name.replace(/_/g, " ");
45-
return s.charAt(0).toUpperCase() + s.slice(1);
43+
// Each field of an archive run, paired with its prop path under the given
44+
// prefix (last_run / last_successful_run) so every value stays traceable.
45+
function runFields(run: any, prefix: string) {
46+
return [
47+
{ prop: `${prefix}.run_id`, value: run.run_id },
48+
{ prop: `${prefix}.api_instance_id`, value: run.api_instance_id },
49+
{ prop: `${prefix}.started_at`, value: formatDate(run.started_at) },
50+
{ prop: `${prefix}.ended_at`, value: formatDate(run.ended_at) },
51+
{ prop: `${prefix}.duration_ms`, value: formatCount(run.duration_ms) },
52+
{ prop: `${prefix}.rows_moved_to_archive`, value: formatCount(run.rows_moved_to_archive) },
53+
{ prop: `${prefix}.rows_deleted_from_archive`, value: formatCount(run.rows_deleted_from_archive) },
54+
{ prop: `${prefix}.success`, value: String(run.success) },
55+
{ prop: `${prefix}.remark`, value: run.remark === "" ? "" : run.remark },
56+
];
4657
}
4758
59+
// Explicit display label per check id — no string munging. An unmapped id
60+
// falls back to its literal value rather than being reworded.
61+
const checkLabels: Record<string, string> = {
62+
check_metrics_are_being_written: "Metrics are being written",
63+
check_archive_scheduler_is_enabled: "Archive scheduler is enabled",
64+
check_metric_retention_policy_is_respected: "Metric retention policy is respected",
65+
check_all_old_metrics_can_be_archived: "All old metrics can be archived",
66+
check_archive_retention_policy_is_respected: "Archive retention policy is respected",
67+
check_archive_metrics_is_fresh_enough: "Archive metrics is fresh enough",
68+
check_last_archive_run_succeeded: "Last archive run succeeded",
69+
};
70+
4871
// The props each derived integrity check is computed from, so every statement
4972
// on the page is traceable to a real field in the API response. Keyed by the
50-
// backend check.name; "+7d grace" in the messages is a hardcoded constant.
73+
// backend check id; "+7d grace" in the messages is a hardcoded constant.
74+
// check_all_old_metrics_can_be_archived has no matching prop (the blocked-row
75+
// count is computed server-side and not in the response), so it is omitted.
5176
const checkProps: Record<string, string[]> = {
52-
write_metrics_enabled: ["config.write_metrics"],
53-
metrics_scheduler_enabled: ["config.enable_metrics_scheduler"],
54-
metric_oldest_within_retention: [
77+
check_metrics_are_being_written: ["config.write_metrics"],
78+
check_archive_scheduler_is_enabled: ["config.enable_metrics_scheduler"],
79+
check_metric_retention_policy_is_respected: [
5580
"metric.oldest_record_age_days",
5681
"config.retain_metrics_days_effective",
5782
],
58-
archive_oldest_within_retention: [
83+
check_archive_retention_policy_is_respected: [
5984
"metric_archive.oldest_record_age_days",
6085
"config.retain_archive_metrics_days_effective",
6186
],
62-
archive_recently_updated: [
87+
check_archive_metrics_is_fresh_enough: [
6388
"metric.oldest_record_age_days",
6489
"metric_archive.newest_record_age_days",
6590
"config.retain_metrics_days_effective",
6691
],
92+
check_last_archive_run_succeeded: [
93+
"last_run.success",
94+
"last_run.started_at",
95+
],
6796
};
6897
6998
function checkBadgeColor(status: string): string {
@@ -190,7 +219,7 @@
190219
<div class="flex items-center gap-2 border-b border-gray-200 p-6 dark:border-gray-700">
191220
<Settings class="h-5 w-5 text-gray-500" />
192221
<h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
193-
Archiving Configuration
222+
Metrics Configuration
194223
</h2>
195224
</div>
196225
<div class="grid grid-cols-1 gap-px overflow-hidden rounded-b-lg bg-gray-200 dark:bg-gray-700 sm:grid-cols-2 lg:grid-cols-3">
@@ -211,6 +240,38 @@
211240
</div>
212241
</div>
213242

243+
<!-- Last Run / Last Successful Run -->
244+
{#each [{ title: "Last Run", prefix: "last_run", run: lastRun }, { title: "Last Successful Run", prefix: "last_successful_run", run: lastSuccessfulRun }] as section (section.prefix)}
245+
<div
246+
class="mb-6 rounded-lg border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800"
247+
data-testid="archive-run"
248+
data-prefix={section.prefix}
249+
>
250+
<div class="border-b border-gray-200 p-6 dark:border-gray-700">
251+
<h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
252+
{section.title}
253+
</h2>
254+
<code class="text-xs font-mono text-gray-500 dark:text-gray-400">{section.prefix}</code>
255+
</div>
256+
{#if section.run}
257+
<div class="grid grid-cols-1 gap-px overflow-hidden rounded-b-lg bg-gray-200 dark:bg-gray-700 sm:grid-cols-2 lg:grid-cols-3">
258+
{#each runFields(section.run, section.prefix) as field (field.prop)}
259+
<div class="bg-white p-4 dark:bg-gray-800" data-testid="run-field" data-prop={field.prop}>
260+
<code class="text-sm font-mono text-gray-600 dark:text-gray-400">{field.prop}</code>
261+
<p class="mt-1 text-lg font-semibold break-words text-gray-900 dark:text-gray-100">
262+
{field.value}
263+
</p>
264+
</div>
265+
{/each}
266+
</div>
267+
{:else}
268+
<p class="p-6 text-sm text-gray-600 dark:text-gray-400">
269+
No archive run recorded.
270+
</p>
271+
{/if}
272+
</div>
273+
{/each}
274+
214275
<!-- Integrity Checks -->
215276
<div
216277
class="mb-6 rounded-lg border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800"
@@ -235,12 +296,13 @@
235296
<div class="flex-1">
236297
<div class="flex items-center gap-2">
237298
<span class="text-sm font-semibold text-gray-900 dark:text-gray-100">
238-
{humanize(check.name)}
299+
{checkLabels[check.name] ?? check.name}
239300
</span>
240301
<span class="rounded-full px-2.5 py-0.5 text-xs font-medium {checkBadgeColor(check.status)}">
241302
{check.status}
242303
</span>
243304
</div>
305+
<code class="text-xs font-mono text-gray-500 dark:text-gray-400">{check.name}</code>
244306
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
245307
{check.message}
246308
</p>

0 commit comments

Comments
 (0)