Axiom
by Axiom · HTTP
Axiom by Axiom — connect via http to access its tools through your RouterMCP gateway.
Overview
Tools (17)
listDatasets
List all available datasets. The "kind" column determines which tools to use next: - events / otel.traces / other: use queryDataset() (APL) and getDatasetFields() - otel-metrics-v1: use listMetrics(), queryMetrics(), searchMetrics(), listMetricTags(), getMetricTagValues() — do NOT use queryDataset() or getDatasetFields() for these
schema
getDatasetFields
List all fields in an events or traces dataset (kind `events`, `otel.traces`, etc.). For metrics datasets (kind `otel-metrics-v1`), use `listMetrics()` and `listMetricTags()` instead — field schemas are not meaningful for that dataset type.
schema
queryDataset
# Instructions 1. Query Axiom datasets using Axiom Processing Language (APL). The query must be a valid APL query string. **Only use this for `events`, `otel.traces`, and similar datasets. Do NOT use for `otel-metrics-v1` datasets — use `queryMetrics()` instead.** 2. ALWAYS understand schema before substantive queries—do not guess column names or types. Prefer `getDatasetFields()` or APL `| where _time > ago(5m) | getschema` on a narrow window (use dataset names from `listDatasets`); use `take 1` or project specific columns for sample values. Before you `where` or `summarize` by a field, estimate cardinality on recent data: `| where _time > ago(5m) | summarize count() by <field> | top 10 by count_`. Avoid `project *` or projecting all fields on very wide datasets unless deliberately mapping shape (see item 5). Skipping probes causes wrong field names, bad types, and expensive re-runs. 3. Keep in mind that there's a maximum row limit of 65000 rows per query. 4. Prefer aggregations over non aggregating queries when possible to reduce the amount of data returned. 5. Be selective in what you project in each query (unless otherwise needed, like for discovering the schema). It's expensive to project all fields. 6. ALWAYS restrict `startTime`/`endTime` to the narrowest window that answers the question—every query scans data and consumes resources. Prefer the smallest APL per step; widen time or complexity only after probing (item 2). 7. When filtering for a specific term or value, put it on the right field—use `has`/`has_cs`/`contains` there after item 2. See **Avoid `search`** under Query performance rules. 8. **`map[string]` columns (e.g. `attributes`, `attributes.custom`, `resource` in OTel-style data)** — `getDatasetFields` and in-query `getschema` show the type but **not** the keys inside the map. You must **sample** (`take`, `project` the map column, or `mv-expand` + `summarize` to list keys) to learn the structure, then use bracket access (e.g. `['attributes']['http.method']`, `['attributes.custom']['http.response.status_code']`). Do not assume key names across services or SDK versions. ### Query performance rules 1. **Narrow `startTime`/`endTime`** — These bound how much data is scanned. Do not rely on in-query `_time` filters alone; keep the API window as tight as your question allows. 2. **`_time` first in APL** — When you filter on `_time` in the query text, put `where _time between (...)` before other filters. This keeps extra in-query narrowing fast. 3. **Most selective `where` first** — Axiom does not reorder predicates; put the filter that removes the most rows earliest. 4. **`project` early and narrowly** — Avoid pulling all columns from very wide datasets (expensive payloads; risk of failures on huge rows). 5. **Prefer fast string ops** — Use `_cs` (case-sensitive) variants when possible; prefer `startswith`/`endswith` over `contains` when applicable; `matches regex` only as a last resort. 6. **Use `has`/`has_cs` for unique-looking strings** — IDs, UUIDs, trace IDs, error codes, session tokens. `has` leverages full-text indexes when available and is much faster than `contains` for high-entropy terms. Use `contains` only when you need true substring matching (e.g., partial paths). 7. **Duration literals** — e.g. `duration > 10s`, not manual conversion. 8. **Avoid search** — scans ALL fields. Use `has`/`has_cs`/`contains` on specific fields. 9. **Avoid heavy `parse_json()` in hot paths** — Filter/narrow first when possible. 10. **Avoid pack(*)** — creates dict of ALL fields per row. Use pack with named fields only. 11. Limit results—use take 10 or top 20 instead of default 1000 when exploring. 12. **Field quoting**—quote identifiers with dots/dashes/spaces: ['geo.country']. For map field keys, use index notation: ['attributes.custom']['http.protocol']. # Examples Basic: - Filter: ['logs'] | where ['severity'] == "error" or ['duration'] > 500ms - Time range: ['logs'] | where ['_time'] > ago(2h) and ['_time'] < now() - Project rename: ['logs'] | project-rename responseTime=['duration'], path=['url'] Aggregations: - Count by: ['logs'] | summarize count() by bin(['_time'], 5m), ['status'] - Multiple aggs: ['logs'] | summarize count(), avg(['duration']), max(['duration']), p95=percentile(['duration'], 95) by ['endpoint'] - Dimensional: ['logs'] | summarize dimensional_analysis(['isError'], pack_array(['endpoint'], ['status'])) - Histograms: ['logs'] | summarize histogram(['responseTime'], 100) by ['endpoint'] - Distinct: ['logs'] | summarize dcount(['userId']) by bin_auto(['_time']) Text matching & Parse: - Match on known fields (avoid full-row `search`): ['logs'] | where ['message'] has_cs "error" or ['message'] has_cs "exception" - Parse logs: ['logs'] | parse-kv ['message'] as (duration:long, error:string) with (pair_delimiter=",") - Regex extract: ['logs'] | extend errorCode = extract("error code ([0-9]+)", 1, ['message']) - Contains ops: ['logs'] | where ['message'] contains_cs "ERROR" or ['message'] startswith "FATAL" Data Shaping: - Extend & Calculate: ['logs'] | extend duration_s = ['duration']/1000, success = ['status'] < 400 - Dynamic: ['logs'] | extend props = parse_json(['properties']) | where ['props.level'] == "error" - Pack/Unpack: ['logs'] | extend fields = pack("status", ['status'], "duration", ['duration']) - Arrays: ['logs'] | where ['url'] in ("login", "logout", "home") | where array_length(['tags']) > 0 Advanced: - Union: union ['logs-app*'] | where ['severity'] == "error" - Case: ['logs'] | extend level = case(['status'] >= 500, "error", ['status'] >= 400, "warn", "info") Time Operations: - Bin & Range: ['logs'] | where ['_time'] between(datetime(2024-01-01)..now()) - Multiple time bins: ['logs'] | summarize count() by bin(['_time'], 1h), bin(['_time'], 1d) - Time shifts: ['logs'] | extend prev_hour = ['_time'] - 1h String Operations: - String funcs: ['logs'] | extend domain = tolower(extract("://([^/]+)", 1, ['url'])) - Concat: ['logs'] | extend full_msg = strcat(['level'], ": ", ['message']) - Replace: ['logs'] | extend clean_msg = replace_regex("(password=)[^&]*", "\1***", ['message']) Common Patterns: - Error analysis: ['logs'] | where ['severity'] == "error" | summarize error_count=count() by ['error_code'], ['service'] - Status codes: ['logs'] | summarize requests=count() by ['status'], bin_auto(['_time']) | where ['status'] >= 500 - Latency tracking: ['logs'] | summarize p50=percentile(['duration'], 50), p90=percentile(['duration'], 90) by ['endpoint'] - User activity: ['logs'] | summarize user_actions=count() by ['userId'], ['action'], bin(['_time'], 1h)
schema
getSavedQueries
Retrieve saved/starred queries from Axiom - shows APL queries that users have bookmarked for reuse
schema
listDashboards
List all available dashboards. Shows user-created dashboards with their metadata.
schema
getDashboard
Get detailed information about a specific dashboard by UID.
schema
exportDashboard
Export a dashboard as JSON by its UID. Returns the full dashboard document that can be used to create or update dashboards via the API.
schema
createDashboard
Create a new dashboard from a JSON document. The dashboard JSON must include required fields: name, owner, charts, layout, refreshTime, schemaVersion (2), timeWindowStart, timeWindowEnd. Set owner to "X-AXIOM-EVERYONE" to make it visible to all org members.
schema
updateDashboard
Update an existing dashboard by UID. Provide the full dashboard JSON document. Use overwrite=true to skip version conflict checks (last-write-wins), or provide the current version number for optimistic concurrency control.
schema
deleteDashboard
Delete a dashboard by its UID. This action is irreversible.
schema
getMonitorHistory
Get recent check history of monitor. Use the checkMonitors() tool to list all the monitors.
schema
checkMonitors
Check all monitors and their statuses.
schema
queryMetrics
# Instructions 1. Query OpenTelemetry metrics stored in Axiom using MPL (Metrics Processing Language). NOT APL. 2. The query targets a metrics dataset (kind "otel-metrics-v1"). 3. Use listMetrics() to discover available metric names in a dataset before querying. 4. Use listMetricTags() and getMetricTagValues() to discover filtering dimensions. 5. ALWAYS restrict the time range to the smallest possible range that meets your needs. 6. NEVER guess metric names or tag values. Always discover them first. # MPL Query Syntax A query has three parts: source, filtering, and transformation. Filters must appear before transformations. ## Source ``` <dataset>:<metric> ``` Backtick-escape identifiers containing special characters: ``my-dataset``:``http.server.duration`` ## Filtering (where) Chain filters with `|`. Use `where` (not `filter`, which is deprecated). ``` | where <tag> <op> <value> ``` Operators: ==, !=, >, <, >=, <= Values: "string", 42, 42.0, true, /regexp/ Combine with: and, or, not, parentheses ## Transformations ### Aggregation (align) — aggregate data over time windows ``` | align to <interval> using <function> ``` Functions: avg, sum, min, max, count, last Intervals: 5m, 1h, 1d, etc. ### Grouping (group) — group series by tags ``` | group by <tag1>, <tag2> using <function> ``` Functions: avg, sum, min, max, count Without `by`: combines all series: `| group using sum` ### Mapping (map) — transform values in place ``` | map rate // per-second rate of change | map increase // increase between datapoints | map + 5 // arithmetic: +, -, *, / | map abs // absolute value | map fill::prev // fill gaps with previous value | map fill::const(0) // fill gaps with constant | map filter::lt(0.4) // remove datapoints >= 0.4 | map filter::gt(100) // remove datapoints <= 100 | map is::gte(0.5) // set to 1.0 if >= 0.5, else 0.0 ``` ### Computation (compute) — combine two metrics ``` ( `dataset`:`errors_total` | group using sum, `dataset`:`requests_total` | group using sum; ) | compute error_rate using / ``` Functions: +, -, *, /, min, max, avg ### Bucketing (bucket) — for histograms ``` | bucket by method, path to 5m using histogram(count, 0.5, 0.9, 0.99) | bucket by method to 5m using interpolate_delta_histogram(0.90, 0.99) | bucket by method to 5m using interpolate_cumulative_histogram(rate, 0.90, 0.99) ``` ### Prometheus compatibility ``` | align to 5m using prom::rate // Prometheus-style rate ``` ## Identifiers Use backticks for names with special characters: ``my-dataset``, ``service.name``, ``http.request.duration`` # Examples Basic query: `my-metrics`:`http.server.duration` | align to 5m using avg Filtered: `my-metrics`:`http.server.duration` | where `service.name` == "frontend" | align to 5m using avg Grouped: `my-metrics`:`http.server.duration` | align to 5m using avg | group by endpoint using sum Rate: `my-metrics`:`http.requests.total` | align to 5m using prom::rate | group by method, path, code using sum Error rate (compute): ( `my-metrics`:`http.requests.total` | where code >= 400 | group by method, path using sum, `my-metrics`:`http.requests.total` | group by method, path using sum; ) | compute error_rate using / | align to 5m using avg SLI (error budget): ( `my-metrics`:`http.requests.total` | where code >= 500 | align to 1h using prom::rate | group using sum, `my-metrics`:`http.requests.total` | align to 1h using prom::rate | group using sum; ) | compute error_rate using / | map is::lt(0.2) | align to 7d using avg Histogram percentiles: `my-metrics`:`http.request.duration.seconds.bucket` | bucket by method, path to 5m using interpolate_delta_histogram(0.90, 0.99) Fill gaps: `my-metrics`:`cpu.usage` | map fill::prev | align to 1m using avg
schema
listMetrics
List all available metrics in a metrics dataset (kind "otel-metrics-v1"). Use this to discover metric names before querying.
schema
listMetricTags
List all available tags (dimensions) in a metrics dataset (kind `otel-metrics-v1`). Tags can be used to filter and group metrics queries.
schema
searchMetrics
Start here when the user mentions a specific service, host, or entity name and you need to work with metrics data. Searches tag values across all metrics in a dataset and returns the metric names that are associated with the given entity. This is the fastest way to go from a known entity name (e.g. "checkout-service", "api-gateway", "us-east-1") to a concrete list of metric names you can actually query. Returns a map of metric name → list of matched tag dimensions, e.g.: { "http.server.duration": ["service.name"], "http.requests.total": ["service.name", "host"] } **Time range:** Use a window of at least 3 hours. Recently-ingested data can take up to 2 hours to become searchable here, so narrow windows may return empty results even when data exists. For recent data, default to `now-3h` / `now`. For historical data, use whatever window covers the period you care about — e.g. `now-14d` / `now-7d` is valid. **Workflow:** 1. Call this tool with the entity name to get relevant metric names. 2. Use listMetricTags() / getMetricTagValues() to discover filter dimensions for those metrics. 3. Call queryMetrics() with an MPL query targeting the specific metric and filters. Use listMetrics() instead when you have no entity name to search by and need a full catalogue of what's in the dataset.
schema
getMetricTagValues
List all values for a specific tag in a metrics dataset (kind `otel-metrics-v1`). Useful for discovering filter values before querying.