Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions docs/integrations/agent-frameworks/agent-framework-dotnet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
title: "Pydantic Logfire Integrations: Microsoft Agent Framework (.NET)"
description: "Send Microsoft Agent Framework (.NET, Microsoft.Agents.AI) telemetry to Pydantic Logfire using the OpenTelemetry .NET SDK and an OTLP exporter."
integration: otel
---
# Microsoft Agent Framework (.NET)

The [Microsoft Agent Framework](https://learn.microsoft.com/en-us/agent-framework/) (namespace
`Microsoft.Agents.AI`) is Microsoft's GA framework that unifies Semantic Kernel and AutoGen. It builds on
`Microsoft.Extensions.AI` and emits OpenTelemetry traces and metrics following the
[OTel GenAI semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/), so you send its
telemetry to **Logfire** with the standard OpenTelemetry .NET SDK plus an OTLP exporter.

## Installation

```bash
dotnet add package Microsoft.Agents.AI
dotnet add package Microsoft.Agents.AI.OpenAI
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
```

## Usage

Enable OpenTelemetry on the chat client and/or the agent with a shared `sourceName`, register that source, and
export over OTLP to **Logfire**:

```csharp title="Program.cs"
using System.ClientModel;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

const string LogfireBase = "https://logfire-us.pydantic.dev"; // or logfire-eu.pydantic.dev
const string SourceName = "weather-agent"; // one name for client + agent
string logfireToken = Environment.GetEnvironmentVariable("LOGFIRE_TOKEN")!;

var resource = ResourceBuilder.CreateDefault().AddService("maf-agent");

// HttpProtobuf + per-signal exporter => supply the FULL /v1/traces path.
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(resource)
.AddSource(SourceName) // must match the UseOpenTelemetry/WithOpenTelemetry sourceName
.AddOtlpExporter(o =>
{
o.Endpoint = new Uri($"{LogfireBase}/v1/traces");
o.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.HttpProtobuf;
o.Headers = $"Authorization={logfireToken}";
})
.Build();

// Build an instrumented IChatClient from the OpenAI client.
IChatClient chatClient = new OpenAIClient(
new ApiKeyCredential(Environment.GetEnvironmentVariable("OPENAI_API_KEY")!))
.GetChatClient("gpt-4o")
.AsIChatClient()
.AsBuilder()
.UseOpenTelemetry(sourceName: SourceName, configure: cfg => cfg.EnableSensitiveData = true)
.Build();

AIAgent agent = new ChatClientAgent(
chatClient,
name: "WeatherAgent",
instructions: "You are a concise, helpful assistant.")
.WithOpenTelemetry(sourceName: SourceName, configure: cfg => cfg.EnableSensitiveData = true);

var response = await agent.RunAsync("Why is the sky blue in one sentence?");
Console.WriteLine(response);
```

You'll see `invoke_agent`, `chat`, and (if the agent calls tools) `execute_tool` spans, plus
`gen_ai.client.*` metrics, in **Logfire**.

!!! warning "Common pitfalls"
- **Default OTLP protocol is gRPC.** Set `OtlpExportProtocol.HttpProtobuf` and supply the full `/v1/traces`
path with per-signal `AddOtlpExporter` (it isn't appended automatically).
- **`sourceName` must match `AddSource`.** If you omit `sourceName`, register the defaults instead:
`AddSource("Experimental.Microsoft.Agents.AI")` (agent) and
`AddSource("Experimental.Microsoft.Extensions.AI")` (chat client).
- **Don't double-instrument unnecessarily.** Enabling OTel on **both** the chat client and the agent (with
`EnableSensitiveData`) duplicates prompt/response content across `chat` and `invoke_agent` spans.
Instrument one layer if duplication is a problem.
- **`EnableSensitiveData = true`** captures prompts, responses, and tool args — dev/test only.

!!! tip "Env-var alternative"
Set `OTEL_EXPORTER_OTLP_ENDPOINT=https://logfire-us.pydantic.dev` (base URL),
`OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf`, and `OTEL_EXPORTER_OTLP_HEADERS=Authorization=<token>`, then a
bare `.AddOtlpExporter()` picks them up and appends the signal paths.

## Managed prompts

Managed prompts are authored and versioned in
[Prompt Management](../../reference/advanced/prompt-management/index.md). The dedicated prompt-fetching SDK
helpers currently ship in the [Python](../../reference/advanced/prompt-management/application.md) and
[TypeScript](https://pydantic.dev/docs/logfire/typescript-sdk/) SDKs. From .NET you can consume managed
variables over the language-agnostic [OFREP HTTP API](../../reference/advanced/managed-variables/external.md),
or resolve the prompt in a small Python/TypeScript sidecar and pass the rendered text into the agent's
`instructions`.
116 changes: 116 additions & 0 deletions docs/integrations/agent-frameworks/eino.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
title: "Pydantic Logfire Integrations: Eino (Go)"
description: "Send CloudWeGo Eino (Go) agent telemetry to Pydantic Logfire with a small OpenTelemetry callback handler over OTLP."
integration: otel
---
# Eino (Go)

[Eino](https://www.cloudwego.io/docs/eino/) is ByteDance/CloudWeGo's Go framework for LLM and agent
applications. Its observability is built on a **callbacks** system rather than automatic OpenTelemetry. To send
Eino traces to **Logfire**, register a standard OpenTelemetry OTLP exporter (pointed at **Logfire**) and a
small custom `callbacks.Handler` that opens a span per node on that provider.

!!! note
The official `eino-ext` callback handlers (`apmplus`, `cozeloop`, `langfuse`) are vendor-specific and don't
expose a generic OTLP endpoint with auth headers, so a tiny custom handler is the cleanest path to Logfire.

## Installation

```bash
go get github.com/cloudwego/eino
go get github.com/cloudwego/eino-ext/components/model/openai
go get go.opentelemetry.io/otel \
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \
go.opentelemetry.io/otel/sdk
```

## Usage

```go title="main.go"
package main

import (
"context"
"fmt"

"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/callbacks"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/schema"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/trace"
oteltrace "go.opentelemetry.io/otel/trace"
)

// Minimal handler that wraps each Eino node in an OTel span.
type otelHandler struct{ tr oteltrace.Tracer }

func (h *otelHandler) OnStart(ctx context.Context, info *callbacks.RunInfo, in callbacks.CallbackInput) context.Context {
ctx, _ = h.tr.Start(ctx, info.Name)
return ctx
}
func (h *otelHandler) OnEnd(ctx context.Context, info *callbacks.RunInfo, out callbacks.CallbackOutput) context.Context {
if s := oteltrace.SpanFromContext(ctx); s != nil {
s.End()
}
return ctx
}
func (h *otelHandler) OnError(ctx context.Context, info *callbacks.RunInfo, err error) context.Context {
if s := oteltrace.SpanFromContext(ctx); s != nil {
s.RecordError(err)
s.End()
}
return ctx
}
func (h *otelHandler) OnStartWithStreamInput(ctx context.Context, _ *callbacks.RunInfo, in *schema.StreamReader[callbacks.CallbackInput]) context.Context {
in.Close()
return ctx
}
func (h *otelHandler) OnEndWithStreamOutput(ctx context.Context, _ *callbacks.RunInfo, out *schema.StreamReader[callbacks.CallbackOutput]) context.Context {
out.Close()
return ctx
}

func main() {
ctx := context.Background()

// 1. OTel -> Logfire (HTTP/protobuf).
exp, _ := otlptracehttp.New(ctx,
otlptracehttp.WithEndpointURL("https://logfire-us.pydantic.dev/v1/traces"),
otlptracehttp.WithHeaders(map[string]string{"Authorization": "your-write-token"}),
)
tp := trace.NewTracerProvider(trace.WithBatcher(exp))
defer tp.Shutdown(ctx)
otel.SetTracerProvider(tp)

// 2. Register the handler globally (init only — not thread-safe).
callbacks.AppendGlobalHandlers(&otelHandler{tr: tp.Tracer("eino")})

// 3. One model call -> traced to Logfire.
cm, _ := openai.NewChatModel(ctx, &openai.ChatModelConfig{APIKey: "sk-...", Model: "gpt-4o-mini"})
out, _ := cm.Generate(ctx,
[]*schema.Message{schema.UserMessage("One-line joke about Go?")},
model.WithTemperature(0.7),
)
fmt.Println(out.Content)
}
```

Use `https://logfire-eu.pydantic.dev/v1/traces` for the EU region.

!!! warning "Common pitfalls"
- **`callbacks.AppendGlobalHandlers` is not thread-safe** — call it only at process init.
- **Close the stream readers** in the streaming callback variants or you'll leak.
- **Use the HTTP exporter** with the `/v1/traces` path, and **flush on exit** via `defer tp.Shutdown(ctx)`.
- Component constructors (the OpenAI chat model here) live in the separate `eino-ext` module, not core
`eino`.

## Managed prompts

Managed prompts are authored and versioned in
[Prompt Management](../../reference/advanced/prompt-management/index.md). The dedicated prompt-fetching SDK
helpers currently ship in the [Python](../../reference/advanced/prompt-management/application.md) and
[TypeScript](https://pydantic.dev/docs/logfire/typescript-sdk/) SDKs. From Go you can consume managed variables
over the language-agnostic [OFREP HTTP API](../../reference/advanced/managed-variables/external.md), or resolve
the prompt in a small Python/TypeScript sidecar and pass the rendered text into your Eino messages.
86 changes: 86 additions & 0 deletions docs/integrations/agent-frameworks/genkit-go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
title: "Pydantic Logfire Integrations: Genkit (Go)"
description: "Send Firebase Genkit (Go) agent telemetry to Pydantic Logfire by registering a standard OpenTelemetry OTLP exporter as the global tracer provider."
integration: otel
---
# Genkit (Go)

[Firebase Genkit](https://genkit.dev/go/) for Go is built directly on the OpenTelemetry Go SDK and emits its
spans through the **global** `TracerProvider`. So to send Genkit traces to **Logfire**, register a standard
OpenTelemetry OTLP exporter (pointed at **Logfire**) as the global provider **before** `genkit.Init(...)` — and
Genkit's agent, model, and tool spans flow in automatically.

!!! note
Don't use Genkit's `googlecloud.EnableGoogleCloudTelemetry` for **Logfire** — it targets Google Cloud
Operations and has no generic OTLP endpoint. The standard OTel exporter below has no extra dependency on
Genkit internals.

## Installation

```bash
go get github.com/firebase/genkit/go
go get go.opentelemetry.io/otel \
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \
go.opentelemetry.io/otel/sdk
```

## Usage

```go title="main.go"
package main

import (
"context"
"fmt"

"github.com/firebase/genkit/go/ai"
"github.com/firebase/genkit/go/genkit"
"github.com/firebase/genkit/go/plugins/googlegenai"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/trace"
)

func main() {
ctx := context.Background()

// 1. Point the global OTel TracerProvider at Logfire (HTTP/protobuf).
// Endpoint + Authorization can also come from
// OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_HEADERS.
exp, _ := otlptracehttp.New(ctx,
otlptracehttp.WithEndpointURL("https://logfire-us.pydantic.dev/v1/traces"),
otlptracehttp.WithHeaders(map[string]string{"Authorization": "your-write-token"}),
)
tp := trace.NewTracerProvider(trace.WithBatcher(exp))
defer tp.Shutdown(ctx)
otel.SetTracerProvider(tp) // MUST be before genkit.Init

// 2. Init Genkit; its spans now export to Logfire.
g := genkit.Init(ctx,
genkit.WithPlugins(&googlegenai.GoogleAI{}),
genkit.WithDefaultModel("googleai/gemini-2.5-flash"),
)

resp, _ := genkit.Generate(ctx, g, ai.WithPrompt("Tell me a one-line joke about Go."))
fmt.Println(resp.Text())
}
```

Set `GEMINI_API_KEY` (or your provider's key) and run `go run .`. You'll see the generation span with model and
token attributes in **Logfire**. Use `https://logfire-eu.pydantic.dev/v1/traces` for the EU region.

!!! warning "Common pitfalls"
- **Set the global provider before `genkit.Init`**, or early spans are dropped.
- **Use the HTTP exporter** (`otlptracehttp`) with the `/v1/traces` path — the gRPC exporter won't match
Logfire's HTTP ingest.
- **Flush on exit.** The `defer tp.Shutdown(ctx)` flushes the batch exporter; without it a short program may
exit before spans are sent.

## Managed prompts

Managed prompts are authored and versioned in
[Prompt Management](../../reference/advanced/prompt-management/index.md). The dedicated prompt-fetching SDK
helpers currently ship in the [Python](../../reference/advanced/prompt-management/application.md) and
[TypeScript](https://pydantic.dev/docs/logfire/typescript-sdk/) SDKs. From Go you can consume managed variables
over the language-agnostic [OFREP HTTP API](../../reference/advanced/managed-variables/external.md), or resolve
the prompt in a small Python/TypeScript sidecar and pass the rendered text into `ai.WithPrompt(...)`.
84 changes: 84 additions & 0 deletions docs/integrations/agent-frameworks/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: Agent Frameworks
description: "How to send telemetry from popular AI agent frameworks — in Python, TypeScript, Go, Rust, and .NET — to Pydantic Logfire, and how to use managed prompts with each."
---
# Agent Frameworks

**Pydantic Logfire** is built on [OpenTelemetry](https://opentelemetry.io/), so it can ingest traces from
essentially any AI agent framework. Each guide below shows three things:

- **How to send telemetry to Logfire** — the exact setup for that framework.
- **A runnable sample agent** you can copy, run, and watch appear in the Logfire Live view.
- **How to use managed prompts** — authoring and versioning prompts in
[Prompt Management](../../reference/advanced/prompt-management/index.md) and fetching them at runtime.

There are three integration patterns, depending on the framework:

1. **Native OpenTelemetry** — the framework already emits OTel spans through the global tracer provider. In
Python, calling [`logfire.configure()`][logfire.configure] is enough (e.g. Pydantic AI, Google ADK, Strands,
Semantic Kernel). In other languages, point the standard OTel SDK at Logfire's OTLP endpoint.
2. **An instrumentor** — an [OpenInference](https://github.com/Arize-ai/openinference) or
[OpenLLMetry](https://github.com/traceloop/openllmetry) package adds the spans. Because
[`logfire.configure()`][logfire.configure] sets the global provider, the instrumentor's spans flow to
Logfire automatically (e.g. CrewAI, AutoGen, smolagents, Haystack, Agno).
3. **OTLP over the wire** — for languages and frameworks without an in-process exporter, send to Logfire's
OTLP endpoint directly (or via an [OpenTelemetry Collector](../../how-to-guides/otel-collector/otel-collector-overview.md)).

## Python

| Framework | Guide |
| --------- | ----- |
| Pydantic AI | [Pydantic AI](../llms/pydanticai.md) |
| OpenAI Agents SDK | [OpenAI](../llms/openai.md#openai-agents) |
| LangChain | [LangChain](../llms/langchain.md) |
| LangGraph | [LangGraph](../llms/langgraph.md) |
| CrewAI | [CrewAI](../llms/crewai.md) |
| AutoGen | [AutoGen](../llms/autogen.md) |
| Google ADK | [Google ADK](../llms/google-adk.md) |
| smolagents | [smolagents](../llms/smolagents.md) |
| Strands Agents | [Strands Agents](../llms/strands.md) |
| Agno | [Agno](../llms/agno.md) |
| Haystack | [Haystack](../llms/haystack.md) |
| LlamaIndex | [LlamaIndex](../llms/llamaindex.md) |
| DSPy | [DSPy](../llms/dspy.md) |
| Instructor | [Instructor](../llms/instructor.md) |
| Semantic Kernel | [Semantic Kernel (Python)](../llms/semantic-kernel.md) |
| Letta | [Letta](../llms/letta.md) |
| Claude Agent SDK | [Claude Agent SDK](../llms/claude-agent-sdk.md) |

## TypeScript / JavaScript

| Framework | Guide |
| --------- | ----- |
| Vercel AI SDK | [Vercel AI SDK](vercel-ai-sdk.md) |
| Mastra | [Mastra](mastra.md) |
| LangChain.js / LangGraph.js | [LangChain.js](langchain-js.md) |
| OpenAI Agents SDK (TS) | [OpenAI Agents SDK (TS)](openai-agents-js.md) |
| VoltAgent | [VoltAgent](voltagent.md) |
| LlamaIndex.TS | [LlamaIndex.TS](llamaindex-ts.md) |

## Go

| Framework | Guide |
| --------- | ----- |
| Firebase Genkit | [Genkit (Go)](genkit-go.md) |
| Eino | [Eino (Go)](eino.md) |

## Rust

| Framework | Guide |
| --------- | ----- |
| Rig | [Rig (Rust)](rig.md) |

## .NET

| Framework | Guide |
| --------- | ----- |
| Semantic Kernel | [Semantic Kernel (.NET)](semantic-kernel-dotnet.md) |
| Microsoft Agent Framework | [Microsoft Agent Framework (.NET)](agent-framework-dotnet.md) |

!!! tip "Don't see your framework?"
Any OpenTelemetry-compatible library works with Logfire. See
[Use Alternative Clients](../../how-to-guides/alternative-clients.md) for the generic OTLP setup in any
language, and let us know on [Slack](https://pydantic.dev/docs/logfire/join-slack/) what you'd like us to
document next.
Loading
Loading