Files
safetynet/scripts/debug-collector-batch.mjs
T

19 lines
2.4 KiB
JavaScript

// Normalize the diagnostic index completely before committing an encrypted batch.
function object(value){if(!value||typeof value!=='object'||Array.isArray(value))throw Error('Invalid OTLP object');return value;}
function array(value){if(value===undefined)return [];if(!Array.isArray(value))throw Error('Invalid OTLP array');return value;}
function time(value){if(typeof value!=='string'||!/^\d{1,20}$/.test(value))throw Error('Invalid span timestamp');const number=BigInt(value);if(number>18446744073709551615n)throw Error('Span timestamp overflow');return number;}
export function normalizeCollectorBatch(signal,payload){
object(payload);const normalized={spans:[],logs:0,metrics:0};
if(signal==='traces')for(const resource of array(payload.resourceSpans))for(const scope of array(object(resource).scopeSpans))for(const entry of array(object(scope).spans)){
const span=object(entry);if(typeof span.traceId!=='string'||! /^[a-f0-9]{32}$/.test(span.traceId)||/^0+$/.test(span.traceId)||typeof span.spanId!=='string'||! /^[a-f0-9]{16}$/.test(span.spanId)||/^0+$/.test(span.spanId))throw Error('Invalid span identity');
if(span.parentSpanId!==undefined&&span.parentSpanId!==''&&(typeof span.parentSpanId!=='string'||! /^[a-f0-9]{16}$/.test(span.parentSpanId)))throw Error('Invalid parent span identity');
if(typeof span.name!=='string')throw Error('Invalid span name');const start=time(span.startTimeUnixNano),end=time(span.endTimeUnixNano),duration=end-start;if(duration<0n||duration>BigInt(Number.MAX_SAFE_INTEGER))throw Error('Invalid span duration');
const attributes=array(span.attributes);for(const attribute of attributes)object(attribute);const value=attributes.find(a=>a.key==='safetynet.operation')?.value?.stringValue;
normalized.spans.push({traceId:span.traceId,spanId:span.spanId,parentSpanId:span.parentSpanId||null,name:span.name.slice(0,80),operation:typeof value==='string'?value.slice(0,80):'',durationMs:Number(duration)/1e6});
}
else if(signal==='logs')for(const resource of array(payload.resourceLogs))for(const scope of array(object(resource).scopeLogs)){const records=array(object(scope).logRecords);for(const record of records)object(record);normalized.logs+=records.length;}
else if(signal==='metrics'){for(const resource of array(payload.resourceMetrics))for(const scope of array(object(resource).scopeMetrics))for(const metric of array(object(scope).metrics))object(metric);normalized.metrics=1;}
else throw Error('Unknown OTLP signal');
return normalized;
}