diff --git a/ui/src/components/MustacheEditor/alert-variables.test.ts b/ui/src/components/MustacheEditor/alert-variables.test.ts index fb931125..9abd1569 100644 --- a/ui/src/components/MustacheEditor/alert-variables.test.ts +++ b/ui/src/components/MustacheEditor/alert-variables.test.ts @@ -10,18 +10,24 @@ describe('availableVariables', () => { const vars = availableVariables(undefined); expect(vars.find((v) => v.path === 'env.slug')).toBeTruthy(); expect(vars.find((v) => v.path === 'exchange.id')).toBeUndefined(); - expect(vars.find((v) => v.path === 'log.logger')).toBeUndefined(); + expect(vars.find((v) => v.path === 'log.pattern')).toBeUndefined(); + expect(vars.find((v) => v.path === 'app.slug')).toBeUndefined(); }); - it('adds exchange.* for EXCHANGE_MATCH kind', () => { + it('adds exchange.* + route.* + app.* for EXCHANGE_MATCH kind', () => { const vars = availableVariables('EXCHANGE_MATCH'); expect(vars.find((v) => v.path === 'exchange.id')).toBeTruthy(); - expect(vars.find((v) => v.path === 'log.logger')).toBeUndefined(); + expect(vars.find((v) => v.path === 'route.uri')).toBeTruthy(); + expect(vars.find((v) => v.path === 'app.slug')).toBeTruthy(); + expect(vars.find((v) => v.path === 'log.pattern')).toBeUndefined(); }); - it('adds log.* for LOG_PATTERN kind', () => { + it('adds log.* + app.* for LOG_PATTERN kind', () => { const vars = availableVariables('LOG_PATTERN'); - expect(vars.find((v) => v.path === 'log.message')).toBeTruthy(); + expect(vars.find((v) => v.path === 'log.pattern')).toBeTruthy(); + expect(vars.find((v) => v.path === 'log.matchCount')).toBeTruthy(); + expect(vars.find((v) => v.path === 'app.slug')).toBeTruthy(); + expect(vars.find((v) => v.path === 'exchange.id')).toBeUndefined(); }); it('reduces to env-only when reducedContext=true (connection URL editor)', () => { diff --git a/ui/src/components/MustacheEditor/alert-variables.ts b/ui/src/components/MustacheEditor/alert-variables.ts index 65a9dc76..c1f1833f 100644 --- a/ui/src/components/MustacheEditor/alert-variables.ts +++ b/ui/src/components/MustacheEditor/alert-variables.ts @@ -35,39 +35,50 @@ export const ALERT_VARIABLES: AlertVariable[] = [ { path: 'alert.link', type: 'url', description: 'UI link to this alert', sampleValue: 'https://cameleer.example.com/alerts/inbox/2222...', availableForKinds: 'always' }, { path: 'alert.currentValue', type: 'number', description: 'Observed metric value', sampleValue: '0.12', availableForKinds: 'always', mayBeNull: true }, { path: 'alert.threshold', type: 'number', description: 'Rule threshold', sampleValue: '0.05', availableForKinds: 'always', mayBeNull: true }, - { path: 'alert.comparator', type: 'string', description: 'Rule comparator', sampleValue: 'GT', availableForKinds: 'always', mayBeNull: true }, - { path: 'alert.window', type: 'string', description: 'Rule window (human)', sampleValue: '5m', availableForKinds: 'always', mayBeNull: true }, - // Scope-ish — still always available when scoped, but "may be null" if env-wide - { path: 'app.slug', type: 'string', description: 'App slug', sampleValue: 'orders', availableForKinds: 'always', mayBeNull: true }, - { path: 'app.id', type: 'uuid', description: 'App UUID', sampleValue: '33333333-...', availableForKinds: 'always', mayBeNull: true }, - { path: 'app.displayName', type: 'string', description: 'App display name', sampleValue: 'Order API', availableForKinds: 'always', mayBeNull: true }, + // App subtree — populated on every kind except env-wide rules + { path: 'app.slug', type: 'string', description: 'App slug', sampleValue: 'orders', + availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH', 'AGENT_STATE', 'DEPLOYMENT_STATE', 'LOG_PATTERN', 'JVM_METRIC'], mayBeNull: true }, + { path: 'app.id', type: 'uuid', description: 'App UUID', sampleValue: '33333333-...', + availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH', 'AGENT_STATE', 'DEPLOYMENT_STATE', 'LOG_PATTERN', 'JVM_METRIC'], mayBeNull: true }, - // ROUTE_METRIC - { path: 'route.id', type: 'string', description: 'Route ID', sampleValue: 'route-1', availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH'] }, + // ROUTE_METRIC + EXCHANGE_MATCH share route.* + { path: 'route.id', type: 'string', description: 'Route ID', sampleValue: 'route-1', + availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH'] }, + { path: 'route.uri', type: 'string', description: 'Route URI', sampleValue: 'direct:orders', + availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH'] }, // EXCHANGE_MATCH - { path: 'exchange.id', type: 'string', description: 'Exchange ID', sampleValue: 'exch-ab12', availableForKinds: ['EXCHANGE_MATCH'] }, - { path: 'exchange.status', type: 'string', description: 'Exchange status', sampleValue: 'FAILED', availableForKinds: ['EXCHANGE_MATCH'] }, - { path: 'exchange.link', type: 'url', description: 'UI link to exchange', sampleValue: '/exchanges/orders/route-1/exch-ab12', availableForKinds: ['EXCHANGE_MATCH'] }, + { path: 'exchange.id', type: 'string', description: 'Exchange ID', sampleValue: 'exch-ab12', + availableForKinds: ['EXCHANGE_MATCH'] }, + { path: 'exchange.status', type: 'string', description: 'Exchange status', sampleValue: 'FAILED', + availableForKinds: ['EXCHANGE_MATCH'] }, - // AGENT_STATE - { path: 'agent.id', type: 'string', description: 'Agent instance ID', sampleValue: 'prod-orders-0', availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] }, - { path: 'agent.name', type: 'string', description: 'Agent display name', sampleValue: 'orders-0', availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] }, - { path: 'agent.state', type: 'string', description: 'Agent state', sampleValue: 'DEAD', availableForKinds: ['AGENT_STATE'] }, + // AGENT_STATE + JVM_METRIC share agent.id/name; AGENT_STATE adds agent.state + { path: 'agent.id', type: 'string', description: 'Agent instance ID', sampleValue: 'prod-orders-0', + availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] }, + { path: 'agent.name', type: 'string', description: 'Agent display name', sampleValue: 'orders-0', + availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] }, + { path: 'agent.state', type: 'string', description: 'Agent state', sampleValue: 'DEAD', + availableForKinds: ['AGENT_STATE'] }, // DEPLOYMENT_STATE - { path: 'deployment.id', type: 'uuid', description: 'Deployment UUID', sampleValue: '44444444-...', availableForKinds: ['DEPLOYMENT_STATE'] }, - { path: 'deployment.status', type: 'string', description: 'Deployment status', sampleValue: 'FAILED', availableForKinds: ['DEPLOYMENT_STATE'] }, + { path: 'deployment.id', type: 'uuid', description: 'Deployment UUID', sampleValue: '44444444-...', + availableForKinds: ['DEPLOYMENT_STATE'] }, + { path: 'deployment.status', type: 'string', description: 'Deployment status', sampleValue: 'FAILED', + availableForKinds: ['DEPLOYMENT_STATE'] }, - // LOG_PATTERN - { path: 'log.logger', type: 'string', description: 'Logger name', sampleValue: 'com.acme.Api', availableForKinds: ['LOG_PATTERN'] }, - { path: 'log.level', type: 'string', description: 'Log level', sampleValue: 'ERROR', availableForKinds: ['LOG_PATTERN'] }, - { path: 'log.message', type: 'string', description: 'Log message', sampleValue: 'TimeoutException...', availableForKinds: ['LOG_PATTERN'] }, + // LOG_PATTERN — leaf names match NotificationContextBuilder (log.pattern + log.matchCount) + { path: 'log.pattern', type: 'string', description: 'Matched log pattern', sampleValue: 'TimeoutException', + availableForKinds: ['LOG_PATTERN'] }, + { path: 'log.matchCount', type: 'number', description: 'Matches in window', sampleValue: '7', + availableForKinds: ['LOG_PATTERN'] }, // JVM_METRIC - { path: 'metric.name', type: 'string', description: 'Metric name', sampleValue: 'heap_used_percent', availableForKinds: ['JVM_METRIC'] }, - { path: 'metric.value', type: 'number', description: 'Metric value', sampleValue: '92.1', availableForKinds: ['JVM_METRIC'] }, + { path: 'metric.name', type: 'string', description: 'Metric name', sampleValue: 'heap_used_percent', + availableForKinds: ['JVM_METRIC'] }, + { path: 'metric.value', type: 'number', description: 'Metric value', sampleValue: '92.1', + availableForKinds: ['JVM_METRIC'] }, ]; /** Filter variables to those available for the given condition kind.