Files
safetynet/apps/server/telemetry.mjs
T

23 lines
1.7 KiB
JavaScript
Raw Normal View History

2026-10-13 10:33:31 +02:00
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { trace, metrics } from '@opentelemetry/api';
import { logs } from '@opentelemetry/api-logs';
import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
export function startTelemetry() {
if(!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return null;
const sdk = new NodeSDK({serviceName:'safetynet-control-plane',traceExporter:new OTLPTraceExporter(),
metricReaders:[new PeriodicExportingMetricReader({exporter:new OTLPMetricExporter(),exportIntervalMillis:10000})],
logRecordProcessors:[new BatchLogRecordProcessor({exporter:new OTLPLogExporter()})]});
sdk.start(); return sdk;
}
export const tracer=trace.getTracer('safetynet','0.1.0');
export function recordSecurityEvent(kind,metadata,eventId){
// Only bounded, allowlisted fields. Never emit body text, rules, vectors or prompts.
const decision=metadata.decision??(kind.includes('block')?'block':'other');
metrics.getMeter('safetynet').createCounter('safetynet.security.events').add(1,{'event.action':kind,'dlp.decision':decision});
logs.getLogger('safetynet.security').emit({severityNumber:kind.includes('block')?13:9,severityText:kind.includes('block')?'WARN':'INFO',body:kind,
attributes:{'event.id':eventId,'event.action':kind,'dlp.decision':decision,...(metadata.ruleId?{'rule.id':metadata.ruleId}:{}),...(metadata.policyVersion?{'safetynet.policy.version':metadata.policyVersion}:{})}});
}