diff --git a/specs/telemetry.md b/specs/telemetry.md index fa6532d..a84bc88 100644 --- a/specs/telemetry.md +++ b/specs/telemetry.md @@ -233,12 +233,12 @@ Emitted via `Sentry.metrics.*`. Each function is a no-op when Sentry is not init | Metric | Type | Attributes | |--------|------|------------| -| `skill.duration` | distribution (ms) | `skill` | -| `tokens.input` | distribution | `skill` | -| `tokens.output` | distribution | `skill` | -| `cost.usd` | distribution | `skill` | -| `findings.total` | count | `skill` | -| `findings` | count | `skill`, `severity` | +| `skill.duration` | distribution (ms) | `skill`, `repository`, `source` | +| `tokens.input` | distribution | `skill`, `repository`, `source` | +| `tokens.output` | distribution | `skill`, `repository`, `source` | +| `cost.usd` | distribution | `skill`, `repository`, `source` | +| `findings.total` | count | `skill`, `repository`, `source` | +| `findings` | count | `skill`, `repository`, `source`, `severity` | ### Extraction (`emitExtractionMetrics`) diff --git a/src/cli/output/tasks.ts b/src/cli/output/tasks.ts index 5d7577c..a3258dc 100644 --- a/src/cli/output/tasks.ts +++ b/src/cli/output/tasks.ts @@ -432,7 +432,9 @@ export async function runSkillTask( } // Emit metrics and log completion - emitSkillMetrics(report); + emitSkillMetrics(report, { + repository: context.repository.fullName, + }); logger.info(logger.fmt`Skill execution complete: ${displayName}`, { 'finding.count': report.findings.length, 'duration_ms': report.durationMs, diff --git a/src/sentry.ts b/src/sentry.ts index 4ae912f..d9766af 100644 --- a/src/sentry.ts +++ b/src/sentry.ts @@ -6,6 +6,7 @@ import { getVersion } from './utils/index.js'; export type SentryContext = 'cli' | 'action'; let initialized = false; +let deploymentContext: SentryContext | undefined; export function initSentry(context: SentryContext): void { const dsn = process.env['WARDEN_SENTRY_DSN']; @@ -25,6 +26,7 @@ export function initSentry(context: SentryContext): void { ], }); + deploymentContext = context; Sentry.setTag('deployment.context', context); Sentry.setTag('service.version', getVersion()); } @@ -45,9 +47,20 @@ function safeEmit(fn: () => void): void { } } -export function emitSkillMetrics(report: SkillReport): void { +export interface SkillMetricsContext { + /** Full repository name (e.g. "owner/repo") */ + repository?: string; +} + +export function emitSkillMetrics(report: SkillReport, context?: SkillMetricsContext): void { safeEmit(() => { - const attrs = { skill: report.skill }; + const attrs: Record = { skill: report.skill }; + if (context?.repository) { + attrs['repository'] = context.repository; + } + if (deploymentContext) { + attrs['source'] = deploymentContext; + } Sentry.metrics.distribution('skill.duration', report.durationMs ?? 0, { unit: 'millisecond',