Use knotel
Querying
Fields, filters and aggregates for slicing spans by any attribute.
Every span attribute can be filtered and grouped on. The Traces page covers the common filters; the MCP run_query tool gives your AI assistant the full query model.
Fields
Well-known fields map to columns. Any other name reads a span attribute by its key (http.user_agent, cart.items), and a resource. prefix reads a resource attribute (resource.host.name).
| Field | Meaning |
|---|---|
service.name | The service that sent the span |
name | Span name |
duration_ms | Duration in milliseconds |
error | true for error spans |
trace.id | Trace id |
span.kind | 1 internal, 2 server, 3 client, 4 producer, 5 consumer |
http.request.method | HTTP method |
http.route | Route template, e.g. /users/:id |
http.response.status_code | HTTP status |
url.full | URL |
db.system.name | mongodb, postgresql, redis, … |
db.operation.name | find, SELECT, GET, … |
db.namespace | Database name |
db.collection.name | Collection or table |
db.query.text | Query text |
peer.service | The remote service or host |
service.version | The build the span ran, from service.version. Group by it to read a rollout. |
deployment.environment.name | production, staging, … The older deployment.environment spelling is read too. |
commit | The git revision the build came from, from vcs.ref.head.revision |
session.id | The browser visit a span belongs to; set by the browser script |
user.id | Who the span was for. enduser.id reads the same column. |
gen_ai.conversation.id | The AI agent conversation a span belongs to (also gen_ai.operation.name) |
otel.scope.name | The instrumentation that emitted the span, e.g. @opentelemetry/instrumentation-mongodb |
otel.scope.version | Version of that instrumentation |
parent.remote | true when the span's parent ran in another process; false for work inside one |
trace.state | W3C tracestate, as the sender set it |
span.flags | OTLP trace flags; bit 0 is sampled |
dropped.attributes | What the sender's SDK threw away before exporting (also dropped.events, dropped.links) |
A span also carries the scope's own attributes under otel.scope.*, and the semantic-convention version its sender speaks as resource.otel.schema_url.
Filters
Filters are combined with AND.
| Operator | Matches |
|---|---|
= != > >= < <= | Comparison. Booleans are true/false. |
contains | Substring, case-insensitive |
starts_with | Prefix |
exists / not_exists | The field is set or missing |
Aggregates
A query groups by up to three fields and returns, per group: count, errors, error rate, and average, p50, p95, p99 and max duration. Order by any of them. Set entry_spans_only to count requests into services rather than every span.
{
"time_range": "24h",
"filters": [{ "field": "db.system.name", "op": "=", "value": "mongodb" }],
"group_by": ["db.collection.name", "db.operation.name"],
"order_by": "p95",
"limit": 10
}{
"filters": [{ "field": "service.name", "op": "=", "value": "api" }],
"group_by": ["http.route"],
"entry_spans_only": true,
"order_by": "error_rate"
}Name spans for grouping
Groups are only as useful as the names in them. Keep ids out of span names and put the template in http.route (see Workers), and give database spans db.operation.name and db.collection.name. Put ids you want to search for, like a user or order id, in attributes instead.