https://promptfoo.dev/ logo
Trace-timeline not shown
# questions
s
Hey! I am facing some issues when trying to view the trace timeline of promptfoo GUI. I get the following error in the GUI. “Traces were created but no spans were received. Make sure your provider is: - Configured to send traces to the OTLP endpoint (http://localhost:4318) -Creating spans within the trace context -Properly exporting spans before the evaluation completes. I am trying to calculate the trace-error-spans of my LLM. But since it didn’t work, I tried writing a FAST API app and view the trace timeline in the GUI. Can someone help me in this matter please?
m
Hey! @singhe.silva I looked into this. The tracing system is working correctly - you just need to instrument your provider to send spans to the OTLP endpoint. When you see "Traces were created but no spans were received", it means Promptfoo created the trace and started the OTLP receiver, but your provider didn't send any spans back. Here's what you need to do: 1. Install OpenTelemetry packages: npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http @opentelemetry/sdk-trace-base 2. In your provider, initialize OpenTelemetry at the module level: const { trace, context, SpanStatusCode } = require('@opentelemetry/api'); const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http'); const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const provider = new NodeTracerProvider(); const exporter = new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces', }); const spanProcessor = new BatchSpanProcessor(exporter); provider.addSpanProcessor(spanProcessor); provider.register(); const tracer = trace.getTracer('my-provider');
4. Make sure your config has tracing enabled and your tests have the metadata: tracing: enabled: true otlp: http: enabled: true port: 4318 tests: - vars: topic: 'example' metadata: tracingEnabled: true The most common mistake is forgetting the forceFlush() call. Without it, spans don't export before the evaluation completes. For Python/FastAPI: from opentelemetry import trace from opentelemetry.propagate import extract from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter provider = TracerProvider() exporter = OTLPSpanExporter(endpoint="http://localhost:4318/v1/traces") provider.add_span_processor(BatchSpanProcessor(exporter)) trace.set_tracer_provider(provider) tracer = trace.get_tracer(__name__) def call_api(prompt, context): if 'traceparent' not in context: return {"output": your_llm_call(prompt)} ctx = extract({"traceparent": context["traceparent"]}) with tracer.start_as_current_span("provider.call", context=ctx) as span: result = your_llm_call(prompt) provider.force_flush() return {"output": result} Check out the working example in the repo: examples/opentelemetry-tracing/ Let me know if you run into any issues.
3. In your callApi function, parse the traceparent and create spans: async callApi(prompt, promptfooContext) { if (!promptfooContext?.traceparent) { return { output: await yourLLMCall(prompt) }; } // Parse traceparent const matches = promptfooContext.traceparent.match( /^(\d{2})-([a-f0-9]{32})-([a-f0-9]{16})-(\d{2})$/ ); if (!matches) return { output: await yourLLMCall(prompt) }; const [, , traceId, parentId, traceFlags] = matches; // Create parent context const parentCtx = trace.setSpanContext(context.active(), { traceId, spanId: parentId, traceFlags: parseInt(traceFlags, 16), isRemote: true, }); // Run within trace context return context.with(parentCtx, async () => { const span = tracer.startSpan('provider.call'); try { const result = await yourLLMCall(prompt); span.setStatus({ code: SpanStatusCode.OK }); // CRITICAL: Force flush before returning await spanProcessor.forceFlush(); return { output: result }; } catch (error) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); throw error; } finally { span.end(); } }); }
s
Thank you Michael, will try this and get back to you!
2 Views