Use Laminar.startSpan() and Laminar.withSpan() to create and continue spans:import { Laminar, observe, Span } from '@lmnr-ai/lmnr';
const processData = (span: Span, data: any) => {
return Laminar.withSpan(span, async () => {
// This code runs within the provided span context
await observe({ name: 'dataValidation' }, async () => {
// Child span - will be nested under the passed span
return validateData(data);
});
});
};
const generateResponse = async (span: Span, processedData: any) => {
await Laminar.withSpan(span, async () => {
await observe({ name: 'responseGeneration' }, async () => {
// Another child span under the same parent
return await generateLLMResponse(processedData);
});
});
};
// Main orchestrator
const handleRequest = async (userInput: string) => {
const rootSpan = Laminar.startSpan('handleUserRequest');
try {
const processedData = await processData(rootSpan, userInput);
const response = await generateResponse(rootSpan, processedData);
return response;
} finally {
// Always end the span!
rootSpan.end();
}
};
Remember to call span.end() to complete the trace.
You can also pass true as the third argument (endOnExit) to the last Laminar.withSpan() call to automatically end the span.
Use Laminar.start_span() and use_span to create and continue spans:from lmnr import Laminar, use_span, observe
from opentelemetry.trace import Span
def process_data(span: Span, data: dict):
with use_span(span):
# This code runs within the provided span context
with Laminar.start_as_current_span(name="data_validation"):
# Child span - will be nested under the passed span
return validate_data(data)
def generate_response(span: Span, processed_data: dict):
with use_span(span):
with Laminar.start_as_current_span(name="response_generation"):
# Another child span under the same parent
return generate_llm_response(processed_data)
def handle_request(user_input: str):
root_span = Laminar.start_span(name="handle_user_request")
try:
processed_data = process_data(root_span, user_input)
response = generate_response(root_span, processed_data)
return response
finally:
# Always end the span!
root_span.end()
Remember to call span.end() to complete the trace. You can also pass end_on_exit=True to the last use_span() call to automatically end the span.