Query Generate
Prerequisites
This skill calls SigNoz MCP server tools heavily (signoz_execute_builder_query,
signoz_query_metrics, signoz_search_logs, signoz_search_traces,
signoz_aggregate_logs, signoz_aggregate_traces, signoz_get_field_keys,
signoz_get_field_values, signoz_list_metrics, signoz_list_services,
signoz_get_service_top_operations, signoz_get_trace_details). Before
running the workflow, confirm the signoz_* tools are available. If they
are not, run signoz-mcp-setup first to initialize or repair the MCP connection.
Do not fall back to raw HTTP calls or fabricate query results without the MCP
tools.
When to use
Use this skill when the user asks to:
- Query, search, or look up observability data (traces, logs, metrics)
- Compute aggregations (error rate, p99 latency, request count, throughput)
- Find specific log entries, traces, or metric values
- Investigate patterns (spikes, drops, trends over time)
Do NOT use when:
- User wants raw ClickHouse SQL for a dashboard panel (custom joins, window
functions, regex over log bodies); that's a separate dashboard-panel SQL
workflow, not this skill.
- User needs the Exceptions Explorer as an exception-specific signal: the
current MCP contract has no exception query tool. Explain that limitation and
offer an equivalent error-trace or error-log query only if it answers their
underlying question.
Instructions
Step 1: Determine the signal type
Map the user's intent to the right signal:
| User intent |
Signal |
Why |
| Error rate, latency, throughput, request count |
metrics (preferred) or traces |
Metrics are pre-aggregated and fastest. Use traces if the user needs per-request detail or no matching metric exists. |
| p50/p75/p90/p95/p99 latency |
metrics (histogram) or traces (aggregate on duration_nano) |
Prefer metrics if a histogram metric exists (e.g., signoz_latency_bucket). Fall back to trace aggregation. |
| Find specific log entries, error messages, stack traces |
logs |
Text search, pattern matching, severity filtering. |
| Find specific traces, slow requests, error spans |
traces |
Per-request detail, span attributes, duration filtering. |
| Infrastructure metrics (CPU, memory, disk, network) |
metrics |
Always metrics for resource utilization. |
| Ingestion volume (bytes or count), cost, or billing usage |
metrics with source=meter (Cost Meter) |
signoz.meter.* ingestion metrics (logs/spans/datapoints by count and bytes) live only in the meter store; bytes are unavailable on the raw signals. Dollar cost is not a metric; derive it from volume × per-unit price (see Step 2). groupBy/filter work like a normal metric, but only over the limited attribute set the meter retains (not arbitrary log/trace fields). For a count sliced by an attribute the meter doesn't carry, aggregate logs/traces directly instead. |
| "How many X per Y" (count/rate grouped by dimension) |
traces or logs (aggregate) |
Use signoz_aggregate_traces or signoz_aggregate_logs for grouped counts. |
Traces have no unqualified full-text search; use CONTAINS against a discovered
structured trace field. searchText-style body search is logs-only.
If the signal is genuinely ambiguous, ask the user before proceeding. The
host application decides how the question is surfaced (e.g. a structured
clarification tool or an inline <assistant_question> tag); follow the
host's UI rendering rules.
Step 2: Discover available data
Always discover before querying. Use only names returned by tools, never
guess from training knowledge.
Run discovery calls in parallel where possible:
For metrics: Call signoz_list_metrics with a searchText substring
matching the user's intent (e.g., searchText: "http", searchText: "latency").
The response includes metric type, temporality, and isMonotonic; pass these to
signoz_query_metrics to avoid extra lookups. Before filtering or grouping,
discover labels with signoz_get_field_keys(signal: "metrics", metricName: <discovered-name>); metric labels are not trace/log attributes (db.system,
for example, is a span attribute unless discovery also returns it for metrics).
Choose timeAggregation from the discovered metric metadata:
| Metric type |
Valid timeAggregation |
| gauge |
latest, sum, avg, min, max, count, count_distinct |
| monotonic counter/sum |
rate, increase |
| non-monotonic sum |
avg, sum, min, max, count, count_distinct; never latest or rate |
| histogram / exponential histogram |
omit; aggregation is automatic |
For Cost Meter (ingestion volume, cost, billing): pass source=meter to
signoz_list_metrics to discover the metrics (signoz.meter.*); they're
invisible in the default store and the set evolves, so don't hardcode it.
groupBy/filters/aggregations then work like any metric, with three caveats:
bytes exist only here (count is also available via direct
signoz_aggregate_logs/_traces); the meter retains only a limited
attribute set, so discover groupable keys via signoz_get_field_keys(signal: "metrics", source: "meter"), and fall back to a direct count (no bytes) to
slice by an attribute it lacks; and dollar cost is not a meter metric:
the store holds only volume, so don't searchText: "cost" expecting a hit.
For a cost question, query the volume metric (bytes for logs/traces, count
for metric datapoints) and multiply by the per-unit price from Settings →
Billing; ask the user for the price if you don't have it.
For traces: Call signoz_list_services to confirm the service name exists,
following pagination.nextOffset while pagination.hasMore is true before
declaring it missing.
Optionally call signoz_get_service_top_operations for the service to find
operation names. Before any attribute filter or grouping, call
signoz_get_field_keys(signal: "traces").
For logs: Before any attribute filter or grouping, call
signoz_get_field_keys(signal: "logs"); use signoz_get_field_values only
after discovery to validate values.
Field keys are signal-specific: service.name may be absent on logs, while
body is logs-only. Never carry a key across signals. Skip key discovery only
when live output in this conversation returned it for the same signal, never
for user text or memory. Use returned dot notation verbatim, not camelCase
guesses such as traceID or hostname. Never assume tenant keys (org.id,
orgId, organization_id, etc.); discover the actual key per signal. Call
signoz_get_field_keys before signoz_get_field_values; both require signal,
and values also require a non-empty discovered name.
Step 3: Choose the right tool
Use the simplest tool that answers the question:
| Question type |
Tool |
When to use |
| Metric time series, scalar, ratio, or formula |
signoz_query_metrics |
Ordinary metrics queries, Cost Meter trends/rates, and metric ratios via formula + formulaQueries. |
| Cost Meter total or grouped total attribution |
signoz_execute_builder_query |
Use the discovered meter metric with raw timeAggregation: "sum"; sum complete hourly buckets. Do not use signoz_query_metrics for totals. |
| Log search (find matching entries) |
signoz_search_logs |
Finding specific log lines. Use searchText for body text, filter for field filters, severity for level filtering. |
| Trace search (find matching spans) |
signoz_search_traces |
Finding specific traces/spans. Use service, operation, error, minDuration/maxDuration shortcuts plus filter for field filters. |
| Log aggregation (count, avg, percentiles) |
signoz_aggregate_logs |
Plain totals, grouped counts, and top-N by one aggregation. |
| Trace aggregation (count, avg, percentiles) |
signoz_aggregate_traces |
Plain totals, grouped counts, and top-N by one aggregation. |
| Complex log/trace formula or shaping |
signoz_execute_builder_query |
Use when ratios, shaping, ordering, or cardinality control exceed the convenience tools; never hand-build a plain grouped count. |
For signoz_aggregate_logs / signoz_aggregate_traces, aggregation is one
bare token: count, count_distinct, avg, sum, min, max, p50, p75,
p90, p95, p99, or rate. Never include parentheses or a column; put the
column in aggregateOn (count and rate need none). Omit orderBy for the
default aggregation-expression descending order; explicit ordering should use a
groupBy key or the aggregation expression. Custom aliases or formulas require
signoz_execute_builder_query.
For every signoz_execute_builder_query payload, put a positive limit and
non-empty Query Builder v5 order on each builder_query and
builder_formula spec. Raw requests and trace-signal requestType: trace
default to 100 rows: traces order by timestamp desc, while raw logs order by
timestamp desc then id desc. Scalar/time-series requests default to 100 groups
ordered by __result desc for metrics/formulas or the primary aggregation desc
for logs/traces. Formula results stay at 100, but every builder_query
referenced by a formula uses 10000 because each component limit is applied
before formula evaluation; independently top-100 inputs can drop a high-ratio
group. When calculating those input bounds, inspect every formula expression,
including formulas with disabled: true, and follow formula references until
all builder_query leaves are found. This dependency walk sets bounds only; it
does not prove deterministic formula-to-formula evaluation order, so validate
the complete composite payload. Narrow filters/grouping if input cardinality
can exceed 10000. This wire field is order, not dashboard editor orderBy.
Time-series top-N ranks groups over the whole window, so a short-lived local
spike may fall outside the returned set.
requestType decision for aggregations:
scalar (default): "How many?", "What is the p99?", "Which service has the most?"
time_series: "When did errors spike?", "How did latency change?", "Show trend"
- If the question has ANY temporal component (spike, trend, change), use
time_series
Aggregate tools accept only scalar or time_series. For builder-query
envelopes passed to signoz_execute_builder_query, use only:
| Signal |
Valid requestType |
| metrics |
time_series, scalar |
| traces |
raw, trace, scalar, time_series |
| logs |
raw, scalar, time_series |
Never invent aggregate, table, timeseries, or series. This matrix does
not apply to PromQL or ClickHouse SQL envelopes.
Step 4: Execute the query
- Always include
searchContext with the user's original question; it improves
result relevance.
- Respect the requested range; otherwise use 1h. Search/aggregate log and trace
tools accept relative
timeRange strings ("1h", "24h"; default 1h);
prefer them. Valid Unix-ms start/end override timeRange; malformed explicit
timestamps return validation guidance pointing to timeRange.
signoz_execute_builder_query has no relative option: its outer query requires
absolute start and end as JSON integer Unix-ms or fails with
missing start or end timestamp.
- Use shortcut parameters (
service, severity, operation, error) when they
match the user's filters; they are simpler and less error-prone than building
filter expressions.
- Combine shortcut params with
filter for additional constraints; they
are ANDed together.
- For
signoz_query_metrics, pass metricType, temporality, and isMonotonic
from the signoz_list_metrics response to avoid an extra auto-fetch round trip.
- For a Cost Meter total or grouped total attribution, use
signoz_execute_builder_query, not signoz_query_metrics. Pass the full tool arguments with
an outer query object, Unix-millisecond start/end, requestType: "time_series",
formatOptions, and variables. The builder spec keeps signal: "metrics",
source: "meter", the discovered metricName and temporality, stepInterval: 3600,
and raw timeAggregation: "sum" plus spaceAggregation: "sum". For grouped totals,
discover the meter field with signoz_get_field_keys and copy its name,
fieldDataType, fieldContext, and signal into groupBy without dropping
or translating fields. Exclude datapoints marked partial: true, then sum the
complete hourly buckets for each returned group.
signoz_query_metrics remains appropriate for a Cost Meter trend or rate that is not a total
attribution. Carry source=meter, use stepInterval: 3600, use
timeAggregation: increase for a volume trend, and rate only for a per-second rate.
Step 5: Handle results
Data returned:
- Present findings as neutral observations with timestamps and values.
- Include the time range in your response.
- For aggregations with
groupBy, highlight the top entries and mention total
group count if truncated by limit.
- For search results, summarize patterns rather than listing every entry.
No data returned. Apply the three-way distinction:
- Healthy zero: The query ran successfully but the count is zero. Say so:
"No errors found for checkout-service in the last hour; error count is zero."
- No data in range: The field/metric exists but no data points fall in the
time window. Suggest expanding: "No data in the last hour. Try a wider range?"
- Missing instrumentation: The metric, field, or service doesn't exist in
discovery results. Say what's missing and suggest how to instrument.
Drill-down:
- If an aggregation reveals an interesting pattern (spike, outlier service),
offer to drill into individual traces or logs for that scope.
- If a trace search returns interesting spans, offer to fetch full trace details
via
signoz_get_trace_details.
Guardrails
- Discovery first: Never guess metric, field, or service names. A field is
confirmed only by live output for the same signal in this conversation.
- Supply required parameters: Never invoke tools hoping they auto-discover.
signoz_aggregate_* requires aggregation; signoz_query_metrics requires a
metricName from signoz_list_metrics; signoz_get_trace_details requires a
traceId; signoz_get_service_top_operations requires a service from
signoz_list_services. Discover first, then call.
- Never claim root cause: Present data patterns and correlations. Write
"Error rate for checkout increased from 0.2% to 4.1% at 14:05" not "The
deployment caused the errors."
- One focused query per question: Do not scatter-shot multiple queries when
one precise query answers the question. Use parallel discovery calls, but be
precise for execution.
- Respect MCP server rules: The MCP server enforces rules about resource
attribute filters, filter operators, and redundant queries. Follow them,
especially preferring resource attributes in filters for faster queries.
- No raw ClickHouse SQL: Always use the Query Builder tools. Never construct
raw SQL.
- Scope boundary: This skill queries data. If the user wants to wrap the
query into a recurring alert, redirect to
signoz-creating-alerts.
- Emit
apply_filter on the final message. When the user asks you to
write, build, generate, or show a query, include an apply_filter action
on your final assistant message with the exact full v5 query object you
passed to a successful signoz_execute_builder_query call in this turn. The
chip carries the entire query-range envelope (schemaVersion: "v1", start,
end, requestType, compositeQuery), not just the inner
compositeQuery, and you must copy it verbatim rather than reconstructing
it. If you answered via simplified tools (signoz_search_logs,
signoz_search_traces, signoz_aggregate_*, signoz_query_metrics), run
one validating signoz_execute_builder_query with a small limit and copy
that exact query object, or skip the chip. Use the appropriate signal
field (metrics, logs, or traces). This signals to the SigNoz UI that
the user wants to apply the query to an explorer page. Only emit
apply_filter when the user's primary intent is to obtain a runnable query,
not when the user is asking a one-shot data question that the analysis text
already answers. For a Cost Meter query keep signal: metrics and ensure the
copied query spec carries source: meter.
Examples
User: "Show me the error rate for the checkout service in the last hour"
Agent:
Calls signoz_list_metrics(searchText: "calls", timeRange: "1h") and
selects the exact returned request-count metric. In this example discovery
returns signoz_calls_total with metricType: "sum",
temporality: "cumulative", and isMonotonic: true.
Calls signoz_get_field_keys(signal: "metrics", metricName: "signoz_calls_total") to discover both service and error labels, then
signoz_get_field_values for each returned name / fieldContext with the
same metric, confirming checkout-service and STATUS_CODE_ERROR. This
example's returned names are service.name and status_code; use whatever
names live discovery returns.
Calls signoz_query_metrics with these complete arguments. The primary
arguments define query A; formulaQueries explicitly defines query B with
a different filter so the denominator includes every checkout request. Both
filters use the label names returned in Step 2 verbatim:
{
"searchContext": "Show me the error rate for the checkout service in the last hour",
"metricName": "signoz_calls_total",
"metricType": "sum",
"isMonotonic": true,
"temporality": "cumulative",
"timeAggregation": "increase",
"spaceAggregation": "sum",
"filter": "service.name = 'checkout-service' AND status_code = 'STATUS_CODE_ERROR'",
"timeRange": "1h",
"requestType": "scalar",
"formula": "A / B * 100",
"formulaQueries": [{
"name": "B",
"metricName": "signoz_calls_total",
"metricType": "sum",
"isMonotonic": true,
"temporality": "cumulative",
"timeAggregation": "increase",
"spaceAggregation": "sum",
"filter": "service.name = 'checkout-service'"
}]
}
Replace every concrete metric, metadata value, field, and field value above
with the tenant's discovery results; never assume this example exists.
Presents: "Error rate for checkout-service: 2.3% over the last hour (14:00–
15:00 UTC). 47 errors out of 2,041 total requests."
Offers drill-down: "Want me to check which operations have the highest error
rate?"
User: "Find timeout errors in logs"
Agent:
- Calls
signoz_search_logs(searchText: "timeout", severity: "ERROR", timeRange: "1h").
- Presents: "Found 23 timeout errors in the last hour. Most are from
payment-service (18) and gateway (5). Common pattern: 'context deadline
exceeded' in gRPC calls to downstream-api."
- Offers: "Want me to check traces for these services to see where the
timeouts occur?"
User: "What's the p99 latency for the cart service?"
Agent:
- Calls
signoz_aggregate_traces(aggregation: "p99", aggregateOn: "duration_nano", service: "cart-service", requestType: "scalar", timeRange: "1h").
- Presents: "p99 latency for cart-service: 1.2s over the last hour."
- Offers: "Want me to break this down by operation or show the trend over time?"
User: "When did errors spike for the frontend?"
Agent:
- Calls
signoz_aggregate_traces(aggregation: "count", error: "true", service: "frontend", requestType: "time_series", timeRange: "6h").
- Presents: "Error count for frontend over the last 6 hours. Spike at 11:30 UTC:
error count jumped from ~5/min to ~45/min, returning to baseline by 12:15."
- Offers: "Want me to check what error types appeared during the spike?"
User: "How much log data is each service ingesting?"
Agent:
- Bytes by service → Cost Meter.
signoz_list_metrics(searchText: "log", source: "meter") and selects the returned log-volume metric from its live name and unit.
- Calls
signoz_execute_builder_query with the outer query wrapper,
schemaVersion: "v1", integer Unix-ms range,
requestType: "time_series", formatOptions, variables, and a builder spec using
signal: "metrics", source: "meter", the discovered metric name and temporality,
stepInterval: 3600, raw timeAggregation: "sum", spaceAggregation: "sum", and
the service.name field returned by signoz_get_field_keys, copying its
name, fieldDataType, fieldContext, and signal into groupBy.
- Excludes
partial: true datapoints, sums complete hourly buckets per service, and presents
per-service ingestion in the discovered unit. (If the meter lacks a requested attribute,
fall back to a direct count and note that bytes remain meter-only.)
1---2name: signoz-generating-queries3description: Generate, write, or run an ad-hoc query against SigNoz observability data (metrics, logs, or traces) without wrapping it in a dashboard panel or alert. Make sure to use this skill whenever the user asks "show me error rates", "query logs for timeout errors", "what's the p99 latency for the cart service", "how many requests hit the payment endpoint", "find slow traces", "errors in the last hour", or otherwise asks an exploratory question that needs live observability data, even if they don't say "query" or "search" explicitly.4---56# Query Generate78## Prerequisites910This skill calls SigNoz MCP server tools heavily (`signoz_execute_builder_query`,11`signoz_query_metrics`, `signoz_search_logs`, `signoz_search_traces`,12`signoz_aggregate_logs`, `signoz_aggregate_traces`, `signoz_get_field_keys`,13`signoz_get_field_values`, `signoz_list_metrics`, `signoz_list_services`,14`signoz_get_service_top_operations`, `signoz_get_trace_details`). Before15running the workflow, confirm the `signoz_*` tools are available. If they16are not, run `signoz-mcp-setup` first to initialize or repair the MCP connection.17Do not fall back to raw HTTP calls or fabricate query results without the MCP18tools.1920## When to use2122Use this skill when the user asks to:23- Query, search, or look up observability data (traces, logs, metrics)24- Compute aggregations (error rate, p99 latency, request count, throughput)25- Find specific log entries, traces, or metric values26- Investigate patterns (spikes, drops, trends over time)2728Do NOT use when:29- User wants raw ClickHouse SQL for a dashboard panel (custom joins, window30 functions, regex over log bodies); that's a separate dashboard-panel SQL31 workflow, not this skill.32- User needs the Exceptions Explorer as an exception-specific signal: the33 current MCP contract has no exception query tool. Explain that limitation and34 offer an equivalent error-trace or error-log query only if it answers their35 underlying question.3637## Instructions3839### Step 1: Determine the signal type4041Map the user's intent to the right signal:4243| User intent | Signal | Why |44|---|---|---|45| Error rate, latency, throughput, request count | **metrics** (preferred) or **traces** | Metrics are pre-aggregated and fastest. Use traces if the user needs per-request detail or no matching metric exists. |46| p50/p75/p90/p95/p99 latency | **metrics** (histogram) or **traces** (aggregate on `duration_nano`) | Prefer metrics if a histogram metric exists (e.g., `signoz_latency_bucket`). Fall back to trace aggregation. |47| Find specific log entries, error messages, stack traces | **logs** | Text search, pattern matching, severity filtering. |48| Find specific traces, slow requests, error spans | **traces** | Per-request detail, span attributes, duration filtering. |49| Infrastructure metrics (CPU, memory, disk, network) | **metrics** | Always metrics for resource utilization. |50| Ingestion volume (bytes or count), cost, or billing usage | **metrics** with `source=meter` (Cost Meter) | `signoz.meter.*` ingestion metrics (logs/spans/datapoints by count **and** bytes) live only in the meter store; bytes are unavailable on the raw signals. Dollar **cost is not a metric**; derive it from volume × per-unit price (see Step 2). groupBy/filter work like a normal metric, but only over the limited attribute set the meter retains (not arbitrary log/trace fields). For a *count* sliced by an attribute the meter doesn't carry, aggregate logs/traces directly instead. |51| "How many X per Y" (count/rate grouped by dimension) | **traces** or **logs** (aggregate) | Use `signoz_aggregate_traces` or `signoz_aggregate_logs` for grouped counts. |5253Traces have no unqualified full-text search; use `CONTAINS` against a discovered54structured trace field. `searchText`-style body search is logs-only.5556If the signal is genuinely ambiguous, ask the user before proceeding. The57host application decides how the question is surfaced (e.g. a structured58clarification tool or an inline `<assistant_question>` tag); follow the59host's UI rendering rules.6061### Step 2: Discover available data6263**Always discover before querying.** Use only names returned by tools, never64guess from training knowledge.6566Run discovery calls in parallel where possible:6768- **For metrics**: Call `signoz_list_metrics` with a `searchText` substring69 matching the user's intent (e.g., `searchText: "http"`, `searchText: "latency"`).70 The response includes metric type, temporality, and isMonotonic; pass these to71 `signoz_query_metrics` to avoid extra lookups. Before filtering or grouping,72 discover labels with `signoz_get_field_keys(signal: "metrics", metricName:73 <discovered-name>)`; metric labels are not trace/log attributes (`db.system`,74 for example, is a span attribute unless discovery also returns it for metrics).7576 Choose `timeAggregation` from the discovered metric metadata:7778 | Metric type | Valid `timeAggregation` |79 |---|---|80 | gauge | `latest`, `sum`, `avg`, `min`, `max`, `count`, `count_distinct` |81 | monotonic counter/sum | `rate`, `increase` |82 | non-monotonic sum | `avg`, `sum`, `min`, `max`, `count`, `count_distinct`; never `latest` or `rate` |83 | histogram / exponential histogram | omit; aggregation is automatic |84- **For Cost Meter** (ingestion volume, cost, billing): pass `source=meter` to85 `signoz_list_metrics` to discover the metrics (`signoz.meter.*`); they're86 invisible in the default store and the set evolves, so don't hardcode it.87 groupBy/filters/aggregations then work like any metric, with three caveats:88 *bytes exist only here* (count is also available via direct89 `signoz_aggregate_logs`/`_traces`); the meter retains only a *limited90 attribute set*, so discover groupable keys via `signoz_get_field_keys(signal:91 "metrics", source: "meter")`, and fall back to a direct count (no bytes) to92 slice by an attribute it lacks; and **dollar cost is not a meter metric**:93 the store holds only volume, so don't `searchText: "cost"` expecting a hit.94 For a cost question, query the volume metric (bytes for logs/traces, count95 for metric datapoints) and multiply by the per-unit price from Settings →96 Billing; ask the user for the price if you don't have it.97- **For traces**: Call `signoz_list_services` to confirm the service name exists,98 following `pagination.nextOffset` while `pagination.hasMore` is true before99 declaring it missing.100 Optionally call `signoz_get_service_top_operations` for the service to find101 operation names. Before any attribute filter or grouping, call102 `signoz_get_field_keys(signal: "traces")`.103- **For logs**: Before any attribute filter or grouping, call104 `signoz_get_field_keys(signal: "logs")`; use `signoz_get_field_values` only105 after discovery to validate values.106107Field keys are signal-specific: `service.name` may be absent on logs, while108`body` is logs-only. Never carry a key across signals. Skip key discovery only109when live output in this conversation returned it for the same signal, never110for user text or memory. Use returned dot notation verbatim, not camelCase111guesses such as `traceID` or `hostname`. Never assume tenant keys (`org.id`,112`orgId`, `organization_id`, etc.); discover the actual key per signal. Call113`signoz_get_field_keys` before `signoz_get_field_values`; both require `signal`,114and values also require a non-empty discovered `name`.115116### Step 3: Choose the right tool117118**Use the simplest tool that answers the question:**119120| Question type | Tool | When to use |121|---|---|---|122| Metric time series, scalar, ratio, or formula | `signoz_query_metrics` | Ordinary metrics queries, Cost Meter trends/rates, and metric ratios via `formula` + `formulaQueries`. |123| Cost Meter total or grouped total attribution | `signoz_execute_builder_query` | Use the discovered meter metric with raw `timeAggregation: "sum"`; sum complete hourly buckets. Do not use `signoz_query_metrics` for totals. |124| Log search (find matching entries) | `signoz_search_logs` | Finding specific log lines. Use `searchText` for body text, `filter` for field filters, `severity` for level filtering. |125| Trace search (find matching spans) | `signoz_search_traces` | Finding specific traces/spans. Use `service`, `operation`, `error`, `minDuration`/`maxDuration` shortcuts plus `filter` for field filters. |126| Log aggregation (count, avg, percentiles) | `signoz_aggregate_logs` | Plain totals, grouped counts, and top-N by one aggregation. |127| Trace aggregation (count, avg, percentiles) | `signoz_aggregate_traces` | Plain totals, grouped counts, and top-N by one aggregation. |128| Complex log/trace formula or shaping | `signoz_execute_builder_query` | Use when ratios, shaping, ordering, or cardinality control exceed the convenience tools; never hand-build a plain grouped count. |129130For `signoz_aggregate_logs` / `signoz_aggregate_traces`, `aggregation` is one131bare token: `count`, `count_distinct`, `avg`, `sum`, `min`, `max`, `p50`, `p75`,132`p90`, `p95`, `p99`, or `rate`. Never include parentheses or a column; put the133column in `aggregateOn` (`count` and `rate` need none). Omit `orderBy` for the134default aggregation-expression descending order; explicit ordering should use a135`groupBy` key or the aggregation expression. Custom aliases or formulas require136`signoz_execute_builder_query`.137138For every `signoz_execute_builder_query` payload, put a positive `limit` and139non-empty Query Builder v5 `order` on each `builder_query` and140`builder_formula` spec. Raw requests and trace-signal `requestType: trace`141default to 100 rows: traces order by timestamp desc, while raw logs order by142timestamp desc then id desc. Scalar/time-series requests default to 100 groups143ordered by `__result` desc for metrics/formulas or the primary aggregation desc144for logs/traces. Formula results stay at 100, but every `builder_query`145referenced by a formula uses 10000 because each component limit is applied146before formula evaluation; independently top-100 inputs can drop a high-ratio147group. When calculating those input bounds, inspect every formula expression,148including formulas with `disabled: true`, and follow formula references until149all `builder_query` leaves are found. This dependency walk sets bounds only; it150does not prove deterministic formula-to-formula evaluation order, so validate151the complete composite payload. Narrow filters/grouping if input cardinality152can exceed 10000. This wire field is `order`, not dashboard editor `orderBy`.153Time-series top-N ranks groups over the whole window, so a short-lived local154spike may fall outside the returned set.155156**`requestType` decision for aggregations:**157- `scalar` (default): "How many?", "What is the p99?", "Which service has the most?"158- `time_series`: "When did errors spike?", "How did latency change?", "Show trend"159- If the question has ANY temporal component (spike, trend, change), use `time_series`160161Aggregate tools accept only `scalar` or `time_series`. For builder-query162envelopes passed to `signoz_execute_builder_query`, use only:163164| Signal | Valid `requestType` |165|---|---|166| metrics | `time_series`, `scalar` |167| traces | `raw`, `trace`, `scalar`, `time_series` |168| logs | `raw`, `scalar`, `time_series` |169170Never invent `aggregate`, `table`, `timeseries`, or `series`. This matrix does171not apply to PromQL or ClickHouse SQL envelopes.172173### Step 4: Execute the query174175- Always include `searchContext` with the user's original question; it improves176 result relevance.177- Respect the requested range; otherwise use 1h. Search/aggregate log and trace178 tools accept relative `timeRange` strings (`"1h"`, `"24h"`; default `1h`);179 prefer them. Valid Unix-ms `start`/`end` override `timeRange`; malformed explicit180 timestamps return validation guidance pointing to `timeRange`.181 `signoz_execute_builder_query` has no relative option: its outer `query` requires182 absolute `start` and `end` as JSON integer Unix-ms or fails with183 `missing start or end timestamp`.184- Use shortcut parameters (`service`, `severity`, `operation`, `error`) when they185 match the user's filters; they are simpler and less error-prone than building186 `filter` expressions.187- Combine shortcut params with `filter` for additional constraints; they188 are ANDed together.189- For `signoz_query_metrics`, pass `metricType`, `temporality`, and `isMonotonic`190 from the `signoz_list_metrics` response to avoid an extra auto-fetch round trip.191- For a **Cost Meter total or grouped total attribution**, use192 `signoz_execute_builder_query`, not `signoz_query_metrics`. Pass the full tool arguments with193 an outer `query` object, Unix-millisecond `start`/`end`, `requestType: "time_series"`,194 `formatOptions`, and `variables`. The builder spec keeps `signal: "metrics"`,195 `source: "meter"`, the discovered `metricName` and `temporality`, `stepInterval: 3600`,196 and raw `timeAggregation: "sum"` plus `spaceAggregation: "sum"`. For grouped totals,197 discover the meter field with `signoz_get_field_keys` and copy its `name`,198 `fieldDataType`, `fieldContext`, and `signal` into `groupBy` without dropping199 or translating fields. Exclude datapoints marked `partial: true`, then sum the200 complete hourly buckets for each returned group.201- `signoz_query_metrics` remains appropriate for a Cost Meter trend or rate that is not a total202 attribution. Carry `source=meter`, use `stepInterval: 3600`, use203 `timeAggregation: increase` for a volume trend, and `rate` only for a per-second rate.204205### Step 5: Handle results206207**Data returned:**208- Present findings as neutral observations with timestamps and values.209- Include the time range in your response.210- For aggregations with `groupBy`, highlight the top entries and mention total211 group count if truncated by `limit`.212- For search results, summarize patterns rather than listing every entry.213214**No data returned. Apply the three-way distinction:**2151. **Healthy zero**: The query ran successfully but the count is zero. Say so:216 "No errors found for checkout-service in the last hour; error count is zero."2172. **No data in range**: The field/metric exists but no data points fall in the218 time window. Suggest expanding: "No data in the last hour. Try a wider range?"2193. **Missing instrumentation**: The metric, field, or service doesn't exist in220 discovery results. Say what's missing and suggest how to instrument.221222**Drill-down:**223- If an aggregation reveals an interesting pattern (spike, outlier service),224 offer to drill into individual traces or logs for that scope.225- If a trace search returns interesting spans, offer to fetch full trace details226 via `signoz_get_trace_details`.227228## Guardrails229230- **Discovery first**: Never guess metric, field, or service names. A field is231 confirmed only by live output for the same signal in this conversation.232- **Supply required parameters**: Never invoke tools hoping they auto-discover.233 `signoz_aggregate_*` requires `aggregation`; `signoz_query_metrics` requires a234 `metricName` from `signoz_list_metrics`; `signoz_get_trace_details` requires a235 `traceId`; `signoz_get_service_top_operations` requires a `service` from236 `signoz_list_services`. Discover first, then call.237- **Never claim root cause**: Present data patterns and correlations. Write238 "Error rate for checkout increased from 0.2% to 4.1% at 14:05" not "The239 deployment caused the errors."240- **One focused query per question**: Do not scatter-shot multiple queries when241 one precise query answers the question. Use parallel discovery calls, but be242 precise for execution.243- **Respect MCP server rules**: The MCP server enforces rules about resource244 attribute filters, filter operators, and redundant queries. Follow them,245 especially preferring resource attributes in filters for faster queries.246- **No raw ClickHouse SQL**: Always use the Query Builder tools. Never construct247 raw SQL.248- **Scope boundary**: This skill queries data. If the user wants to wrap the249 query into a recurring alert, redirect to `signoz-creating-alerts`.250- **Emit `apply_filter` on the final message.** When the user asks you to251 write, build, generate, or show a query, include an `apply_filter` action252 on your final assistant message with the exact full v5 `query` object you253 passed to a successful `signoz_execute_builder_query` call in this turn. The254 chip carries the entire query-range envelope (`schemaVersion: "v1"`, `start`,255 `end`, `requestType`, `compositeQuery`), not just the inner256 `compositeQuery`, and you must copy it verbatim rather than reconstructing257 it. If you answered via simplified tools (`signoz_search_logs`,258 `signoz_search_traces`, `signoz_aggregate_*`, `signoz_query_metrics`), run259 one validating `signoz_execute_builder_query` with a small `limit` and copy260 that exact query object, or skip the chip. Use the appropriate `signal`261 field (`metrics`, `logs`, or `traces`). This signals to the SigNoz UI that262 the user wants to apply the query to an explorer page. Only emit263 `apply_filter` when the user's primary intent is to obtain a runnable query,264 not when the user is asking a one-shot data question that the analysis text265 already answers. For a Cost Meter query keep `signal: metrics` and ensure the266 copied query spec carries `source: meter`.267268## Examples269270**User:** "Show me the error rate for the checkout service in the last hour"271272**Agent:**2731. Calls `signoz_list_metrics(searchText: "calls", timeRange: "1h")` and274 selects the exact returned request-count metric. In this example discovery275 returns `signoz_calls_total` with `metricType: "sum"`,276 `temporality: "cumulative"`, and `isMonotonic: true`.2772. Calls `signoz_get_field_keys(signal: "metrics", metricName:278 "signoz_calls_total")` to discover both service and error labels, then279 `signoz_get_field_values` for each returned `name` / `fieldContext` with the280 same metric, confirming `checkout-service` and `STATUS_CODE_ERROR`. This281 example's returned names are `service.name` and `status_code`; use whatever282 names live discovery returns.2833. Calls `signoz_query_metrics` with these complete arguments. The primary284 arguments define query A; `formulaQueries` explicitly defines query B with285 a different filter so the denominator includes every checkout request. Both286 filters use the label names returned in Step 2 verbatim:287288 ```json289 {290 "searchContext": "Show me the error rate for the checkout service in the last hour",291 "metricName": "signoz_calls_total",292 "metricType": "sum",293 "isMonotonic": true,294 "temporality": "cumulative",295 "timeAggregation": "increase",296 "spaceAggregation": "sum",297 "filter": "service.name = 'checkout-service' AND status_code = 'STATUS_CODE_ERROR'",298 "timeRange": "1h",299 "requestType": "scalar",300 "formula": "A / B * 100",301 "formulaQueries": [{302 "name": "B",303 "metricName": "signoz_calls_total",304 "metricType": "sum",305 "isMonotonic": true,306 "temporality": "cumulative",307 "timeAggregation": "increase",308 "spaceAggregation": "sum",309 "filter": "service.name = 'checkout-service'"310 }]311 }312 ```313314 Replace every concrete metric, metadata value, field, and field value above315 with the tenant's discovery results; never assume this example exists.3164. Presents: "Error rate for checkout-service: 2.3% over the last hour (14:00–317 15:00 UTC). 47 errors out of 2,041 total requests."3185. Offers drill-down: "Want me to check which operations have the highest error319 rate?"320321---322323**User:** "Find timeout errors in logs"324325**Agent:**3261. Calls `signoz_search_logs(searchText: "timeout", severity: "ERROR",327 timeRange: "1h")`.3282. Presents: "Found 23 timeout errors in the last hour. Most are from329 payment-service (18) and gateway (5). Common pattern: 'context deadline330 exceeded' in gRPC calls to downstream-api."3313. Offers: "Want me to check traces for these services to see where the332 timeouts occur?"333334---335336**User:** "What's the p99 latency for the cart service?"337338**Agent:**3391. Calls `signoz_aggregate_traces(aggregation: "p99",340 aggregateOn: "duration_nano", service: "cart-service",341 requestType: "scalar", timeRange: "1h")`.3422. Presents: "p99 latency for cart-service: 1.2s over the last hour."3433. Offers: "Want me to break this down by operation or show the trend over time?"344345---346347**User:** "When did errors spike for the frontend?"348349**Agent:**3501. Calls `signoz_aggregate_traces(aggregation: "count", error: "true",351 service: "frontend", requestType: "time_series", timeRange: "6h")`.3522. Presents: "Error count for frontend over the last 6 hours. Spike at 11:30 UTC:353 error count jumped from ~5/min to ~45/min, returning to baseline by 12:15."3543. Offers: "Want me to check what error types appeared during the spike?"355356---357358**User:** "How much log data is each service ingesting?"359360**Agent:**3611. Bytes by service → Cost Meter. `signoz_list_metrics(searchText: "log",362 source: "meter")` and selects the returned log-volume metric from its live name and unit.3632. Calls `signoz_execute_builder_query` with the outer `query` wrapper,364 `schemaVersion: "v1"`, integer Unix-ms range,365 `requestType: "time_series"`, `formatOptions`, `variables`, and a builder spec using366 `signal: "metrics"`, `source: "meter"`, the discovered metric name and temporality,367 `stepInterval: 3600`, raw `timeAggregation: "sum"`, `spaceAggregation: "sum"`, and368 the `service.name` field returned by `signoz_get_field_keys`, copying its369 `name`, `fieldDataType`, `fieldContext`, and `signal` into `groupBy`.3703. Excludes `partial: true` datapoints, sums complete hourly buckets per service, and presents371 per-service ingestion in the discovered unit. (If the meter lacks a requested attribute,372 fall back to a direct count and note that bytes remain meter-only.)