Current section

Files

Jump to
langchain lib telemetry.ex
Raw

lib/telemetry.ex

defmodule LangChain.Telemetry do
@moduledoc """
Telemetry events for LangChain.
This module defines telemetry events that other applications can attach to.
It provides a standardized way to emit events for various operations in the
LangChain library without implementing tracing functionality.
## Event Naming
Events follow the convention: `[:langchain, component, operation, stage]`
## Core Events
* `[:langchain, :llm, :call, :start]` - Emitted when an LLM call starts
* `[:langchain, :llm, :call, :stop]` - Emitted when an LLM call completes
* `[:langchain, :llm, :call, :exception]` - Emitted when an LLM call raises an exception
* `[:langchain, :llm, :prompt]` - Emitted when a prompt is sent to an LLM
* `[:langchain, :llm, :response]` - Emitted when a response is received from an LLM
* `[:langchain, :llm, :response, :non_streaming]` - Emitted when a non-streaming response is received from an LLM
* `[:langchain, :llm, :response, :streaming]` - Emitted when a streaming response is received from an LLM
* `[:langchain, :chain, :execute, :start]` - Emitted when a chain execution starts
* `[:langchain, :chain, :execute, :stop]` - Emitted when a chain execution completes
* `[:langchain, :chain, :execute, :exception]` - Emitted when a chain execution raises an exception
* `[:langchain, :message, :process, :start]` - Emitted when message processing starts
* `[:langchain, :message, :process, :stop]` - Emitted when message processing completes
* `[:langchain, :message, :process, :exception]` - Emitted when message processing raises an exception
* `[:langchain, :tool, :call, :start]` - Emitted when a tool call starts
* `[:langchain, :tool, :call, :stop]` - Emitted when a tool call completes
* `[:langchain, :tool, :call, :exception]` - Emitted when a tool call raises an exception
## Usage
To attach to these events in your application:
```elixir
:telemetry.attach(
"my-handler-id",
[:langchain, :llm, :call, :stop],
&MyApp.handle_llm_call/4,
nil
)
def handle_llm_call(_event_name, measurements, metadata, _config) do
# Process the event
IO.inspect(measurements)
IO.inspect(metadata)
end
```
"""
@doc """
Emits a telemetry event with the given name, measurements, and metadata.
## Parameters
* `event_name` - The name of the event as a list of atoms
* `measurements` - A map of measurements for the event
* `metadata` - A map of metadata for the event
## Examples
iex> LangChain.Telemetry.emit_event([:langchain, :llm, :call, :start], %{system_time: System.system_time()}, %{model: "gpt-4"})
"""
@spec emit_event(list(atom()), map(), map()) :: :ok
def emit_event(event_name, measurements, metadata) do
:telemetry.execute(event_name, measurements, metadata)
end
@doc """
Emits a start event and returns a function to emit the corresponding stop event.
This is useful for span-like events where you want to measure the duration of an operation.
## Parameters
* `event_prefix` - The prefix for the event name as a list of atoms
* `metadata` - A map of metadata for the event
## Returns
A function that accepts additional metadata to be merged with the original metadata
and emits the stop event with the duration measurement.
## Examples
iex> stop_fun = LangChain.Telemetry.start_event([:langchain, :llm, :call], %{model: "gpt-4"})
iex> # Do some work
iex> stop_fun.(%{result: "success"})
"""
@spec start_event(list(atom()), map()) :: (map() -> :ok)
def start_event(event_prefix, metadata) do
start_time = System.monotonic_time()
start_system_time = System.system_time()
emit_event(event_prefix ++ [:start], %{system_time: start_system_time}, metadata)
fn additional_metadata ->
end_time = System.monotonic_time()
duration = end_time - start_time
emit_event(
event_prefix ++ [:stop],
%{duration: duration, system_time: System.system_time()},
Map.merge(metadata, additional_metadata)
)
end
end
@doc """
Wraps a function call with start and stop telemetry events.
## Parameters
* `event_prefix` - The prefix for the event name as a list of atoms
* `metadata` - A map of metadata for the event
* `fun` - The function to execute
## Returns
The result of the function call.
## Examples
iex> LangChain.Telemetry.span([:langchain, :llm, :call], %{model: "gpt-4"}, fn ->
...> # Call the LLM
...> {:ok, "response"}
...> end)
"""
@spec span(list(atom()), map(), (-> result)) :: result when result: any()
def span(event_prefix, metadata, fun) do
stop = start_event(event_prefix, metadata)
try do
result = fun.()
stop.(%{result: result})
result
rescue
exception ->
stacktrace = __STACKTRACE__
emit_event(
event_prefix ++ [:exception],
%{system_time: System.system_time()},
Map.merge(metadata, %{
kind: :error,
error: exception,
stacktrace: stacktrace
})
)
reraise exception, stacktrace
end
end
# LLM Events
@doc """
Emits an LLM call start event.
"""
@spec llm_call_start(map()) :: (map() -> :ok)
def llm_call_start(metadata) do
start_event([:langchain, :llm, :call], metadata)
end
@doc """
Emits an LLM prompt event.
"""
@spec llm_prompt(map(), map()) :: :ok
def llm_prompt(measurements, metadata) do
emit_event([:langchain, :llm, :prompt], measurements, metadata)
end
@doc """
Emits an LLM response event.
"""
@spec llm_response(map(), map()) :: :ok
def llm_response(measurements, metadata) do
emit_event([:langchain, :llm, :response], measurements, metadata)
end
# Chain Events
@doc """
Emits a chain execution start event.
"""
@spec chain_execute_start(map()) :: (map() -> :ok)
def chain_execute_start(metadata) do
start_event([:langchain, :chain, :execute], metadata)
end
# Message Events
@doc """
Emits a message processing start event.
"""
@spec message_process_start(map()) :: (map() -> :ok)
def message_process_start(metadata) do
start_event([:langchain, :message, :process], metadata)
end
# Tool Events
@doc """
Emits a tool call start event.
"""
@spec tool_call_start(map()) :: (map() -> :ok)
def tool_call_start(metadata) do
start_event([:langchain, :tool, :call], metadata)
end
@doc """
Emits a tool call event.
"""
@spec tool_call(map(), map()) :: :ok
def tool_call(measurements, metadata) do
emit_event([:langchain, :tool, :call], measurements, metadata)
end
# Memory Events
@doc """
Emits a memory read start event.
"""
@spec memory_read_start(map()) :: (map() -> :ok)
def memory_read_start(metadata) do
start_event([:langchain, :memory, :read], metadata)
end
@doc """
Emits a memory write start event.
"""
@spec memory_write_start(map()) :: (map() -> :ok)
def memory_write_start(metadata) do
start_event([:langchain, :memory, :write], metadata)
end
# Retriever Events
@doc """
Emits a retriever get relevant documents start event.
"""
@spec retriever_get_relevant_documents_start(map()) :: (map() -> :ok)
def retriever_get_relevant_documents_start(metadata) do
start_event([:langchain, :retriever, :get_relevant_documents], metadata)
end
end