Local observability and metrics
Genkit provides a robust set of built-in observability features, including tracing and metrics collection powered by OpenTelemetry. For local observability, such as during the development phase, the Genkit Developer UI provides detailed trace viewing and debugging capabilities. For production observability, we provide Genkit Monitoring in the Firebase console via the Firebase plugin. Alternatively, you can export your OpenTelemetry data to the observability tooling of your choice.
Tracing & metrics
Section titled “Tracing & metrics”Genkit automatically collects traces and metrics without requiring explicit configuration, allowing you to observe and debug your Genkit code’s behavior in the Developer UI. Genkit stores these traces, enabling you to analyze your Genkit flows step-by-step with detailed input/output logging and statistics. In production, Genkit can export traces and metrics to Firebase Genkit Monitoring for further analysis.
Log and export events
Section titled “Log and export events”Genkit Go logs through github.com/firebase/genkit/go/core/logger, a thin
layer over the standard library’s log/slog. Log with the package-level
functions, passing the context first:
import "github.com/firebase/genkit/go/core/logger"
genkit.DefineFlow(g, "summarize", func(ctx context.Context, input string) (string, error) { logger.Info(ctx, "summarizing", "size", len(input))
resp, err := genkit.Generate(ctx, g, ai.WithPrompt(input)) if err != nil { logger.Warn(ctx, "generation failed, returning the input unchanged", "error", err) return input, nil }
logger.Debug(ctx, "summary ready", "outputSize", len(resp.Text())) return resp.Text(), nil})Passing the context is what ties a record to its surroundings. The context carries the trace span that is active at that moment, so the record is correlated with the step that produced it, and it carries any attributes bound to the context’s logger. The basic-errors sample logs through these helpers as it classifies and recovers from failures.
logger.FromContext(ctx) is still supported and still correlates: it returns
the context’s logger bound to that context, so records logged through its plain
methods keep the span. Reach for it when you want to bind attributes once and
have them follow everything logged downstream:
ctx = logger.WithContext(ctx, logger.FromContext(ctx).With("requestId", requestID))
// Everything logged below carries requestId, with no extra plumbing.logger.Info(ctx, "handling request")Plain slog works too, with one caveat: only the *Context methods carry the
span. slog.InfoContext(ctx, ...) is correlated, slog.Info(...) is not.
View logs in the Developer UI
Section titled “View logs in the Developer UI”Running your app under the CLI is enough to get logs into the Developer UI:
genkit start -- go run .No code change and no configuration is needed. The CLI sets the environment the
runtime looks for, genkit.Init installs the export handler, and records stream
to the Developer UI, which lists them against the span that emitted them in the
trace viewer. Starting the Developer UI separately with genkit ui:start also
works, since the CLI hands the telemetry server’s address to the running app.
The Developer UI receives every record at debug level and above, independent of the console level, so the terminal can stay quiet while the full debug narrative lands in the trace viewer. Genkit’s own records travel the same channel: span start and finish, the resolved generate request, each model turn with its finish reason and token counts, tool batches, and each middleware hook with its duration and whether it short-circuited.
A record logged without a context is still exported, but it carries no span, so it never appears against a step.
// Mirror every record to a file without disturbing console output or// Developer UI streaming.f, err := os.Create("genkit.log")if err != nil { log.Fatal(err)}logger.AddHandler(slog.NewJSONHandler(f, &slog.HandlerOptions{Level: slog.LevelDebug}))Set the console level
Section titled “Set the console level”The console starts at info. To see Genkit’s per-request detail in the terminal as well, lower the level:
// Console only. In dev the Developer UI already receives debug and above,// whatever this is set to.logger.SetLevel(slog.LevelDebug)SetLevel installs Genkit’s console handler as the process default. If your
application configured its own default slog handler, Genkit leaves it alone
and warns instead, so set that handler’s level rather than calling SetLevel.
Environment variables
Section titled “Environment variables”| Variable | Accepted values | Default | Effect |
|---|---|---|---|
GENKIT_LOG_LEVEL | debug, info, warn, error, case-insensitive, with an optional offset such as error+2 | info | Minimum level for the console. It never changes what the Developer UI receives. A value it cannot parse, such as warning, verbose, or a number, is ignored with a warning, and so is the variable as a whole if your application installed its own default slog handler. |
GENKIT_OTEL_ENABLE_LOGS | any value that parses as false (false, 0, f) turns export off | unset, so export is on | An opt-out. You do not have to set it to see logs. Unset, true, and anything that does not parse as false all leave export on. |
GENKIT_ENV | dev installs the Developer UI log sink | prod | genkit start sets dev. Nothing is exported outside the dev environment. |
GENKIT_TELEMETRY_SERVER | a base URL, for example http://localhost:4033 | empty | Where records are posted. genkit start sets it. When it is empty, the CLI supplies the address at runtime instead. |
What survives the trip
Section titled “What survives the trip”Attribute values reach the Developer UI as strings, integers, or booleans.
Everything else is rendered to text on the way: a float64 arrives as its
decimal string, a time.Duration as 412ms, an error as its Error() text,
and anything else as JSON. slog groups flatten into dotted keys.
Export never blocks your code. Records are batched and posted in the background,
and dropped rather than queued when the buffer fills, with one warning on
stderr. There is no flush at process exit either, so a short-lived go run .
can lose its last few records.
Production observability
Section titled “Production observability”The Genkit Monitoring dashboard helps you understand the overall health of your Genkit features. It is also useful for debugging stability and content issues that may indicate problems with your LLM prompts and/or Genkit Flows. See the Getting Started guide for more details.