tonic-debug
A debugging and diagnostics middleware for tonic gRPC servers.
Problem
Debugging gRPC services built with tonic is hard:
- Messages are binary-encoded protobufs — not human-readable
- Connection issues between clients and servers are opaque
- Standard logging lacks the detail needed to quickly diagnose problems
Solution
tonic-debug is a Tower middleware that slots into your tonic server and provides:
- Human-readable protobuf inspection — decodes protobuf wire format without needing
.protoschemas, showing field numbers, wire types, and values - Connection lifecycle observability — tracks connection events (connect, disconnect, errors) with active/total counters via tower/hyper integration
- Structured logging via
tracing— all output goes through thetracingcrate with structured fields for easy filtering and aggregation - Optional OpenTelemetry export — enable the
opentelemetryfeature flag to forward spans and attributes to your OTel collector
Quick Start
Add tonic-debug to your Cargo.toml:
[]
= "0.1"
Then add the DebugLayer to your tonic server:
use DebugLayer;
async
Configuration
Fine-tune what gets logged using the builder API or DebugConfig:
use ;
// Builder API
let layer = new
.log_headers
.log_bodies
.log_response_frames
.max_body_bytes
.hex_dump;
// Or use DebugConfig directly
let layer = with_config;
| Option | Default | Description |
|---|---|---|
log_headers |
true |
Log request/response headers and custom metadata |
log_bodies |
true |
Log protobuf message contents |
log_response_frames |
true |
Log individual response body frames as they stream |
max_body_bytes |
4096 |
Maximum bytes to capture for body inspection |
hex_dump |
false |
Include hex dump of raw bytes in output |
Connection Tracking
Track client connection lifecycle with ConnectionTrackerLayer:
use ;
let metrics = new;
let connection_layer = with_metrics;
// Query metrics at any time
println!;
println!;
println!;
Protobuf Inspection
The crate decodes raw protobuf wire format without schemas, producing output like:
gRPC frame (compressed=false, 15 bytes)
field 1 (varint): 42
field 2 (length-delimited): "hello world"
You can also use the inspection utilities directly:
use inspect;
let data = &; // field 1, varint 150
if let Some = decode_protobuf
Feature Flags
| Feature | Description |
|---|---|
opentelemetry |
Adds OpenTelemetry semantic convention attributes and |
span enrichment via tracing-opentelemetry |
Enable with:
[]
= { = "0.1", = ["opentelemetry"] }
Log Levels
tonic-debug uses the following tracing levels:
| Level | What gets logged |
|---|---|
INFO |
Request/response summary, connection events |
WARN |
Non-OK gRPC status codes |
ERROR |
Connection errors, response body errors |
DEBUG |
Headers, custom metadata, response frames, protobuf fields |
TRACE |
Stream completion summaries |
🏛️ License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
🧩 Contribution
This is a free and open project and lives from contributions of the community.
See our Contribution Guide