Skip to main content
Wrap functions with Laminar to capture inputs, outputs, and errors automatically.

observe(options, fn, …args)

Wrap a function to create a span. Automatically captures inputs, outputs, and errors.
import { observe } from '@lmnr-ai/lmnr';

const result = await observe(
  { name: 'my_operation' },
  async (param1, param2) => {
    return param1 + param2;
  },
  1, 2
);
// Span input: [1, 2], output: 3
Parameters:
NameTypeDefaultDescription
namestringfn.nameSpan name
sessionIdstringAssociate trace with session
userIdstringAssociate trace with user
metadataRecord<string, any>Trace metadata (JSON-serializable)
tagsstring[]Span tags (deduplicated)
traceType'DEFAULT' | 'EVALUATION''DEFAULT'Trace type
spanType'DEFAULT' | 'LLM' | 'TOOL' | 'EXECUTOR' | 'EVALUATOR' | 'EVALUATION''DEFAULT'Span type
inputanyExplicit input (overrides function args)
ignoreInputbooleanfalseDon’t record input
ignoreOutputbooleanfalseDon’t record output
parentSpanContextstring | LaminarSpanContextParent context for distributed tracing
Returns: Promise<ReturnType<F>>Behavior:
  • If one non-Map object argument, records that object as input; otherwise records array
  • Maps converted to entries, circular references become "[Circular reference]"
  • Exceptions recorded via recordException and re-thrown
  • Anonymous function name becomes "" if name not provided
  • Works with both sync and async functions
Examples: Group multiple LLM calls under one parent span
import { observe } from '@lmnr-ai/lmnr';

export const handle = async (userMessage: string) =>
  observe({ name: 'requestHandler' }, async () => {
    const routerResponse = await openai.chat.completions.create({
      model: 'gpt-4o-mini',
      messages: [{ role: 'user', content: `Route this: ${userMessage}` }],
    });

    const modelResponse = await openai.chat.completions.create({
      model: 'gpt-4o',
      messages: [{ role: 'user', content: userMessage }],
    });

    return {
      route: routerResponse.choices[0].message.content,
      answer: modelResponse.choices[0].message.content,
    };
  });
Examples: Nested spans for multi-step workflows
import { observe } from '@lmnr-ai/lmnr';

await observe({ name: 'checkout', sessionId: `checkout-${userId}` }, async () => {
  await observe({ name: 'validateCart' }, async () => {
    // ...
  });

  await observe({ name: 'processPayment' }, async () => {
    // ...
  });

  await observe({ name: 'createOrder' }, async () => {
    // ...
  });
});

observeDecorator(config)

Class method decorator version of observe.
import { observeDecorator } from '@lmnr-ai/lmnr';

class MyService {
  @observeDecorator({ name: 'process_request' })
  async processRequest(input: string) {
    return await this.doWork(input);
  }
}
Parameters: Same as observe options. Config can be an object or a function (thisArg, ...args) => config for per-call configuration.Returns: Method decorator