diff --git a/genkit-tools/telemetry-server/src/localFileTraceStore.ts b/genkit-tools/telemetry-server/src/file-trace-store.ts similarity index 90% rename from genkit-tools/telemetry-server/src/localFileTraceStore.ts rename to genkit-tools/telemetry-server/src/file-trace-store.ts index 82a7198eb0..66d5fb88c4 100644 --- a/genkit-tools/telemetry-server/src/localFileTraceStore.ts +++ b/genkit-tools/telemetry-server/src/file-trace-store.ts @@ -15,6 +15,7 @@ */ import { + SpanData, TraceDataSchema, type TraceData, type TraceQueryFilter, @@ -29,6 +30,7 @@ import { version as currentVersion } from './utils/version'; const MAX_TRACES = 1000; const MAX_INDEX_FILES = 10; +const MAX_LIST_ATTR_LENGTH = 1000; /** * Implementation of trace store that persists traces on local disk. @@ -148,7 +150,7 @@ export class LocalFileTraceStore implements TraceStore { path.resolve(this.storeRoot, `${id}`), JSON.stringify(trace) ); - const hasRootSpan = !!Object.values(trace.spans).find( + const hasRootSpan = !!Object.values(rawTrace.spans).find( (s) => !s.parentSpanId ); if (this.index && hasRootSpan) { @@ -176,7 +178,7 @@ export class LocalFileTraceStore implements TraceStore { }); const loadedTraces = await Promise.all( - searchResult.data.map((d) => this.load(d['id'])) + searchResult.data.map((d) => this.load(d['id']).then(trucateTraceDetails)) ); return { @@ -238,6 +240,48 @@ export class LocalFileTraceStore implements TraceStore { } } +function trucateTraceDetails(t?: TraceData): TraceData | undefined { + if (!t) return t; + + const { spans: originalSpans, ...restOfTrace } = t; + + const spans = {} as Record; + for (const spanId of Object.keys(originalSpans)) { + if (!originalSpans[spanId].parentSpanId) { + const { attributes: originalAttributes, ...restOfSpan } = + originalSpans[spanId]; + spans[spanId] = { + attributes: trucateLargeAttrs(originalAttributes), + ...restOfSpan, + } as SpanData; + break; + } + } + + return { spans, ...restOfTrace }; +} + +export function trucateLargeAttrs(input: T): T { + if ( + input === undefined || + input === null || + Array.isArray(input) || + typeof input !== 'object' + ) { + return input; + } + for (const key in input) { + if ( + typeof input[key] === 'string' && + (input[key] as string).length > MAX_LIST_ATTR_LENGTH + ) { + input[key] = ((input[key] as string).substring(0, MAX_LIST_ATTR_LENGTH) + + '...') as any; + } + } + return input; +} + export interface IndexSearchResult { pageLastIndex?: number; data: Record[]; diff --git a/genkit-tools/telemetry-server/src/index.ts b/genkit-tools/telemetry-server/src/index.ts index e514a75380..d934fb9968 100644 --- a/genkit-tools/telemetry-server/src/index.ts +++ b/genkit-tools/telemetry-server/src/index.ts @@ -23,7 +23,7 @@ import express from 'express'; import type * as http from 'http'; import type { TraceStore } from './types'; -export { LocalFileTraceStore } from './localFileTraceStore.js'; +export { LocalFileTraceStore } from './file-trace-store.js'; export { TraceQuerySchema, type TraceQuery, type TraceStore } from './types'; let server: http.Server;