mirror of
https://github.com/Dvorinka/Primora.git
synced 2026-10-28 15:51:23 +00:00
feat: phase 3 observability — IMS telemetry merge
Port IMS telemetry into Primora conventions: - core.components/core.events (migration 00004 + sqlc) scoped to projects - POST /api/v1/ingest — single or <=500-event batches via project prm_ keys (X-Primora-Key alias), auto-registering components, permissive CORS - Issues: fingerprint-grouped errors with count/severity/first+last seen - Reads: events w/ filters + before-cursor, components, stats (1h/24h/7d/30d bucketed series + component health + totals + metric names), metric series (avg/p50/p95/max) - GET .../telemetry/stream — project-scoped SSE through an in-process hub (buffered subs, drop-on-slow, 25s keepalives); ?api_key=/?token= auth for EventSource - Telemetry page: health/issues/events/metrics/integrate tabs, live badge, 390px-clean; demo stubs - @primora/client SDK (createPrimoraClient: capture*/heartbeat/installAuto, queued keepalive flushes) - MCP: primora_list_issues/list_events/telemetry_stats/metric_series - IMS README deprecation note pointing here Also fixes workspace pins to 0.3.0 — npm ci in the frontend image was resolving the unpublished 0.2.0 spec from the registry. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
6507eee606
commit
8cfddf9184
60 files changed
+3694
-30
No files matched your search
@@ -22,7 +22,7 @@
|
||||
"zod": "^4.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@primora/api-client": "0.2.0",
|
||||
"@primora/api-client": "0.3.0",
|
||||
"@types/node": "^24.0.0",
|
||||
"esbuild": "^0.27.4",
|
||||
"typescript": "^5.9.2"
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
PlatformService,
|
||||
ProjectsService,
|
||||
StorageService,
|
||||
TelemetryService,
|
||||
} from "@primora/api-client";
|
||||
|
||||
import { configureClient, loadConfig, type McpConfig } from "./config.js";
|
||||
@@ -362,4 +363,94 @@ server.registerTool(
|
||||
},
|
||||
);
|
||||
|
||||
const eventType = z.enum(["error", "metric", "log", "heartbeat", "event"]);
|
||||
|
||||
server.registerTool(
|
||||
"primora_list_issues",
|
||||
{
|
||||
description: "Error groups by fingerprint — count, severity, first/last seen",
|
||||
inputSchema: {
|
||||
projectId: z.string().optional(),
|
||||
days: z.number().int().optional().describe("Lookback window (default 30)"),
|
||||
},
|
||||
},
|
||||
async ({ projectId: p, days }) => {
|
||||
try {
|
||||
return ok(await TelemetryService.listTelemetryIssues({ projectId: projectId(p), days }));
|
||||
} catch (e) {
|
||||
return fail(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"primora_list_events",
|
||||
{
|
||||
description: "Telemetry events, newest first — errors, metrics, logs, heartbeats",
|
||||
inputSchema: {
|
||||
projectId: z.string().optional(),
|
||||
type: eventType.optional(),
|
||||
component: z.string().optional(),
|
||||
fingerprint: z.string().optional().describe("Limit to one error group"),
|
||||
limit: z.number().int().optional(),
|
||||
before: z.number().int().optional().describe("Event id cursor for pagination"),
|
||||
},
|
||||
},
|
||||
async ({ projectId: p, type, component, fingerprint, limit, before }) => {
|
||||
try {
|
||||
return ok(
|
||||
await TelemetryService.listTelemetryEvents({
|
||||
projectId: projectId(p),
|
||||
type,
|
||||
component,
|
||||
fingerprint,
|
||||
limit,
|
||||
before,
|
||||
}),
|
||||
);
|
||||
} catch (e) {
|
||||
return fail(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"primora_telemetry_stats",
|
||||
{
|
||||
description: "Aggregated telemetry: event series, component health, totals, metric names",
|
||||
inputSchema: {
|
||||
projectId: z.string().optional(),
|
||||
window: z.enum(["1h", "24h", "7d", "30d"]).optional(),
|
||||
},
|
||||
},
|
||||
async ({ projectId: p, window }) => {
|
||||
try {
|
||||
return ok(await TelemetryService.getTelemetryStats({ projectId: projectId(p), window }));
|
||||
} catch (e) {
|
||||
return fail(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
"primora_metric_series",
|
||||
{
|
||||
description: "Time series for one metric name — avg, p50, p95, max per bucket",
|
||||
inputSchema: {
|
||||
projectId: z.string().optional(),
|
||||
name: z.string(),
|
||||
window: z.enum(["1h", "24h", "7d", "30d"]).optional(),
|
||||
},
|
||||
},
|
||||
async ({ projectId: p, name, window }) => {
|
||||
try {
|
||||
return ok(
|
||||
await TelemetryService.getTelemetryMetricSeries({ projectId: projectId(p), name, window }),
|
||||
);
|
||||
} catch (e) {
|
||||
return fail(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await server.connect(new StdioServerTransport());
|
||||
Reference in new issue
Block a user