Langertha-Knarr

 view release on metacpan or  search on metacpan

lib/Langertha/Knarr/Tracing.pm  view on Meta::CPAN

  return;
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Langertha::Knarr::Tracing - Automatic Langfuse tracing per proxy request

=head1 VERSION

version 1.101

=head1 SYNOPSIS

    use Langertha::Knarr::Tracing;

    my $tracing = Langertha::Knarr::Tracing->new(config => $config);

    my $trace_id = $tracing->start_trace(
      model    => 'gpt-5.6-terra',
      engine   => 'Langertha::Engine::OpenAI',
      messages => \@messages,
      params   => \%params,
      format   => 'openai',
    );

    # ... handle request ...

    $tracing->end_trace($trace_id,
      output => $response_text,
      model  => 'gpt-5.6-terra',
      usage  => { input => 100, output => 50, total => 150 },
    );

=head1 DESCRIPTION

Records every proxy request as a Langfuse trace with a nested generation. When
tracing is not configured (no public and secret key), all methods are no-ops.

Langfuse credentials are read from the config file's C<langfuse:> section or
from the C<LANGFUSE_PUBLIC_KEY>, C<LANGFUSE_SECRET_KEY>, and C<LANGFUSE_URL>
environment variables. The module strips surrounding quotes from environment
variable values, which Docker C<--env-file> sometimes adds literally.

=head2 Timing sources

Knarr has two request paths and they do not measure latency the same way.
The generation's C<startTime> always marks the moment L</start_trace> ran;
what differs is where C<endTime> and C<completionStartTime> come from.

=over

=item * B<Routed, non-streaming> — a L<Langertha> engine produced a
L<Langertha::Response>, so L<Langertha::Knarr::Handler::Tracing> hands the
engine-measured C<timing> hash to L</end_trace>. C<endTime> becomes
C<startTime + total_seconds> and C<completionStartTime> becomes
C<startTime + ttft_seconds>, both anchored to the high-resolution
timestamp L</start_trace> recorded. This is the only path with a real
time-to-first-token, and the durations exclude the proxy's own
formatting overhead.

=item * B<Routed, streaming> — the decorator accumulates deltas and never
sees a response object, so there is no C<timing>. C<endTime> is the
wall-clock moment the stream was exhausted and no C<completionStartTime>
is emitted.

=item * B<Raw passthrough> — bytes are piped 1:1 and never parsed, so no
L<Langertha::Response> exists at all. C<endTime> is again the proxy's own
wall clock at L</end_trace>, which includes network time to the upstream
provider.

=back

Callers that pass no C<timing> therefore keep exactly the previous
behaviour: proxy-measured C<endTime>, no C<completionStartTime>.

=head2 config

The L<Langertha::Knarr::Config> object. Required. Provides Langfuse
credentials and C<trace_name>.

=head2 trace_name

The Langfuse trace name applied to all traces. Resolved in priority order from:
C<langfuse.trace_name> in config, C<LANGFUSE_TRACE_NAME> env var,
C<KNARR_TRACE_NAME> env var, or the default C<knarr-proxy>.

=head2 start_trace

    my $trace_info = $tracing->start_trace(
      model    => $model_name,
      engine   => $engine_class,
      messages => \@messages,
      params   => \%params,
      format   => 'openai',
    );

Creates a new Langfuse trace and generation. Returns a C<$trace_info> hashref
that must be passed to L</end_trace>. Returns C<undef> when tracing is
disabled.

The returned hashref carries C<start_hires>, the C<gettimeofday> pair behind
C<start_time>. L</end_trace> anchors engine-measured durations to it; see
L</Timing sources>.

=head2 end_trace

    $tracing->end_trace($trace_info,
      output => $response_text,
      model  => $model,
      usage  => { input => 100, output => 50, total => 150 },
      timing => { ttft_seconds => 0.25, total_seconds => 1.5 },
      response_id => 'chatcmpl-123',
    );

    # On error:
    $tracing->end_trace($trace_info, error => "Something went wrong");

Closes the generation and trace started by L</start_trace>, then flushes the
batch to Langfuse. Pass C<error> to record a failed generation at level ERROR.
Does nothing when C<$trace_info> is C<undef> (tracing was disabled at start).



( run in 0.739 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )