Pentagi Logging Mechanisms: Structured Logrus, HTTP Tracing, and OpenTelemetry Integration
Pentagi implements a four-layer logging architecture that combines structured Logrus logging with contextual flow tracking, HTTP/GraphQL request tracing, and full OpenTelemetry observability for comprehensive monitoring across the vxcontrol/pentagi platform.
Pentagi is an open-source AI security automation platform that requires robust observability to track complex multi-step flows. The logging system in vxcontrol/pentagi uses a hierarchical approach where every log entry is enriched with flow, task, and subtask identifiers to enable precise debugging and distributed tracing.
Layered Logging Architecture
The Pentagi logging mechanisms consist of four integrated layers that work together to provide consistent, searchable telemetry.
Structured Logrus with Contextual Enrichment
At the foundation, Pentagi uses Logrus for structured JSON logging. The key innovation is the enrichLogrusFields function in backend/pkg/tools/tools.go (lines 1536-1549), which automatically injects execution context into every log entry.
When tools execute operations, they create loggers that include:
flow_id– The unique identifier for the workflow executiontask_id– The specific task within the flowsubtask_id– The granular subtask identifiercomponent– The tool or service name
// From backend/pkg/tools/traversaal.go (lines 57-67)
logger := logrus.WithContext(ctx).WithFields(
enrichLogrusFields(t.flowID, t.taskID, t.subtaskID, logrus.Fields{
"component": "traversaal",
}),
)
if err := json.Unmarshal(action.Args, &args); err != nil {
logger.WithError(err).Error("failed to unmarshal traversaal search action")
}
This enrichment ensures that every log line can be correlated back to its exact execution context, making it possible to trace a single flow through thousands of concurrent operations.
HTTP Request Tracing via Gin Middleware
For API observability, Pentagi registers the WithGinLogger middleware in backend/pkg/server/logger/logger.go (lines 23-63). This middleware intercepts every HTTP request and records:
- Client IP and request URI
- HTTP method and status code
- Request duration
- Error details for 4xx/5xx responses
// Registration in backend/pkg/server/router.go
router := gin.New()
router.Use(logger.WithGinLogger("pentagi-api"))
// Produces log entries like:
// {"component":"api","http_method":"GET","http_uri":"/flows/12/msglogs","duration":"12.3ms","http_status_code":200,"level":"debug"}
Successful requests log at the debug level, while failures (HTTP ≥ 400) automatically log at error level with full context.
GraphQL Operation Logging
The GraphQL layer uses WithGqlLogger (lines 66-98 in backend/pkg/server/logger/logger.go) to wrap resolver execution. This middleware captures:
- GraphQL operation name and type (query/mutation/subscription)
- Execution duration
- Resolver-level errors
// From backend/pkg/server/logger/logger.go
srv := handler.NewDefaultServer(generated.NewExecutableSchema(...))
srv.AroundResponses(logger.WithGqlLogger("pentagi-gql"))
// Example output:
// {"component":"pentagi-gql","operation_name":"CreateFlow","operation_type":"mutation","duration":"45ms","level":"debug"}
This provides visibility into AI flow creation and management operations without exposing sensitive query parameters in logs.
OpenTelemetry Integration
The fourth layer extends beyond traditional logging to full observability. The observability.NewTelemetryClient in backend/pkg/observability/otelclient.go initializes an OTLP (OpenTelemetry Protocol) client that exports logs, metrics, and traces to compatible collectors like Grafana Tempo or Prometheus.
cfg := config.Load() // Reads TELEMETRY_ENDPOINT env var
telemetry, _ := observability.NewTelemetryClient(context.Background(), cfg)
// Emit structured logs to OTLP collector
otelLogger := telemetry.Logger()
otelLogger.LogRecord(ctx, otellog.Record{
Severity: otellog.SeverityInfo,
Body: otellog.StringValue("Flow started"),
Attributes: []attribute.KeyValue{
attribute.Int64("flow_id", flowID),
},
})
This integration allows Pentagi to feed observability data into existing enterprise monitoring infrastructure while maintaining the same contextual fields used in Logrus logging.
Key Implementation Files
Understanding the Pentagi logging mechanisms requires familiarity with these specific source files:
| File | Purpose |
|---|---|
backend/pkg/tools/tools.go |
Contains enrichLogrusFields (lines 1536-1549) for adding flow/task/subtask IDs to log entries |
backend/pkg/server/logger/logger.go |
Implements WithGinLogger and WithGqlLogger middleware, plus FromContext helper |
backend/pkg/observability/otelclient.go |
OpenTelemetry client initialization and OTLP export configuration |
backend/pkg/server/router.go |
Registers HTTP logging middleware with the Gin router |
backend/pkg/tools/traversaal.go |
Example tool implementation showing enriched logger usage (lines 57-67) |
backend/pkg/server/services/msglogs.go |
Demonstrates error logging patterns using logger.FromContext |
Summary
The Pentagi logging mechanisms provide enterprise-grade observability through these key capabilities:
- Structured JSON logging via Logrus with automatic contextual enrichment using
enrichLogrusFields - Request correlation across HTTP (Gin) and GraphQL layers using middleware that captures timing and error states
- Execution context tracking that binds every log entry to specific flow, task, and subtask IDs for precise debugging
- OpenTelemetry export enabling integration with OTLP-compatible observability platforms for distributed tracing and metrics
- Dual-level output with debug logging for successes and automatic error escalation for failed operations
Frequently Asked Questions
How does Pentagi correlate logs across different tools and services?
Pentagi uses the enrichLogrusFields helper function defined in backend/pkg/tools/tools.go to inject consistent identifiers (flow_id, task_id, subtask_id) into every Logrus entry. When a tool like the Traversaal search in backend/pkg/tools/traversaal.go initializes its logger, it passes these IDs along with a component name. This ensures that logs from the web browser, terminal, or search tools can be filtered and joined using the same execution context fields.
What environment variables configure Pentagi's OpenTelemetry export?
The OpenTelemetry client in backend/pkg/observability/otelclient.go reads configuration via config.Load(), which typically sources the TELEMETRY_ENDPOINT environment variable to specify the OTLP collector URL. Additional standard OpenTelemetry environment variables (like OTEL_SERVICE_NAME or OTEL_EXPORTER_OTLP_HEADERS) are respected by the underlying SDK, allowing flexible deployment to Grafana Tempo, Prometheus, or other observability backends without code changes.
How does Pentagi handle error logging versus debug logging in HTTP requests?
The WithGinLogger middleware in backend/pkg/server/logger/logger.go (lines 23-63) implements automatic log level selection based on HTTP status codes. Requests completing with status < 400 are logged at the debug level to reduce noise in production logs, while any request returning 4xx or 5xx status codes automatically triggers error level logging with full request context including the URI, method, and duration. This provides immediate visibility into API failures without requiring manual log level configuration.
Can Pentagi's logging mechanism trace individual AI operations within a flow?
Yes. Every AI operation, tool execution, and subtask within a Pentagi flow receives a unique subtask_id that propagates through the context. When tools log messages using logrus.WithContext(ctx).WithFields(), the enrichLogrusFields function extracts these IDs from the context and attaches them to the log entry. This allows operators to query for a specific flow_id in their log aggregation system (or OTLP backend) and retrieve the complete execution trace from flow initialization through individual AI tool calls to final output generation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →