Skip to content

Pydantic Logfire Integrations: Genkit (Go)

Firebase Genkit 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.

Installation

Terminal
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

main.go
package main

import (
	"context"
	"fmt"
	"os"

	"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()
	writeToken := os.Getenv("LOGFIRE_WRITE_TOKEN")
	if writeToken == "" {
		fmt.Println("LOGFIRE_WRITE_TOKEN is required; copy it from your Logfire project settings")
		return
	}

	// 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, err := otlptracehttp.New(ctx,
		otlptracehttp.WithEndpointURL("https://logfire-us.pydantic.dev/v1/traces"),
		otlptracehttp.WithHeaders(map[string]string{"Authorization": writeToken}),
	)
	if err != nil {
		fmt.Println("telemetry setup error:", err)
		return
	}
	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"),
	)

	type incidentInput struct {
		IncidentID string `json:"incident_id" jsonschema:"description=The incident identifier"`
	}
	toolCalls := 0
	lookupIncident := genkit.DefineTool(
		g,
		"lookup_incident",
		"Look up the current status and owner of an incident by ID.",
		func(_ *ai.ToolContext, input incidentInput) (string, error) {
			toolCalls++
			return fmt.Sprintf("%s is resolved; owner=platform-observability", input.IncidentID), nil
		},
	)

	resp, err := genkit.Generate(
		ctx,
		g,
		ai.WithPrompt("Call lookup_incident exactly once with incident_id incident-42, then report the result."),
		ai.WithTools(lookupIncident),
	)
	if err != nil {
		fmt.Println("model error:", err)
		return
	}
	if resp == nil {
		fmt.Println("model returned no response")
		return
	}
	if toolCalls != 1 {
		fmt.Printf("expected one tool call, received %d\n", toolCalls)
		return
	}
	fmt.Println(resp.Text())
}

Set GEMINI_API_KEY (or your provider’s key) and run go run .. The example verifies that Genkit executes its native lookup_incident tool. You’ll see the generation, model, and tool spans in Logfire. Genkit runs are detected in the specialized Agents view; the support matrix shows which columns each view populates. Use https://logfire-eu.pydantic.dev/v1/traces for the EU region.

Managed prompts

Managed prompts are authored and versioned in Prompt Management. The dedicated prompt-fetching SDK helpers currently ship in the Python and TypeScript SDKs. From Go you can consume managed variables over the language-agnostic OpenFeature Remote Evaluation Protocol (OFREP) HTTP API, or resolve the prompt in a small Python/TypeScript sidecar and pass the rendered text into ai.WithPrompt(...).