Skip to main content
Version: 0.5

Concepts

Key concepts for understanding how ROSQL works and how to get the most out of it.


SHOW vs FROM

ROSQL has two types of queries: data queries (FROM) and diagnostic commands (SHOW).

FROM — query telemetry data

FROM queries retrieve and aggregate raw telemetry: spans, logs, metrics, topic messages, or recording metadata. They support all SQL-like clauses (WHERE, FACET, SINCE, ORDER BY, LIMIT) and return rows.

FROM traces WHERE status = 'ERROR' SINCE 1 hour ago
SELECT AVG(duration) FROM traces FACET robot_id
FROM logs WHERE severity = 'FATAL'

Use FROM when you want to explore, aggregate, or trend data.

SHOW — diagnostic snapshots

SHOW commands return structured diagnostic snapshots — not raw rows, but pre-shaped information about your system's current state. They are compound commands with fixed schemas:

SHOW SPAN SUMMARY FOR ROBOT 'robot_42' SINCE 1 hour ago
SHOW DEPLOYMENTS SINCE 7 days ago
SHOW TOPICS FOR ROBOT 'robot_42'
SHOW NODES FOR ROBOT 'robot_42'
SHOW NODE GRAPH
SHOW JOINTS FOR ROBOT 'arm_01'
SHOW PLANS FOR TRACE 'abc123'

Use SHOW when you want a snapshot of system topology, configuration, or performance summary. SHOW commands are not pipeable, but they support FOR scoping and SINCE time ranges.

When to use which

GoalUse
Find slow action spansFROM traces WHERE action_name = '...' ORDER BY duration DESC
See which nodes are slowestSHOW SPAN SUMMARY
Watch error rate over timeFROM traces TIMESERIES 5 min
See the topology of a topicMESSAGE FLOW FROM TOPIC '/cmd_vel'
Inspect available topicsSHOW TOPICS
Get a span tree for a traceTRACE 'id' (this is neither FROM nor SHOW — it's its own compound)

Scoping with FOR

The FOR clause scopes any query to a specific robot, version, environment, or session. All FOR dimensions can be combined:

FOR ROBOT 'robot_42' FROM traces WHERE status = 'ERROR'
FOR VERSION '2.3.1' FROM traces TIMESERIES 5 min
FOR ENVIRONMENT 'production' FOR ROBOT 'robot_42' FROM logs
FOR SESSION 'delivery_042' FROM traces SINCE 1 hour ago

How scoping works

Each FOR clause adds a filter on the resource_attributes JSONB column:

FOR clauseCompiled as
FOR ROBOT 'robot_42'resource_attributes->>'robot.id' = 'robot_42'
FOR VERSION '2.3.1'resource_attributes->>'service.version' = '2.3.1'
FOR ENVIRONMENT 'production'resource_attributes->>'deployment.environment' = 'production'
FOR SESSION 'sess_abc'resource_attributes->>'ros.session.id' = 'sess_abc'

Scoping applies to FROM queries, SHOW commands, compound queries (TRACE, MESSAGE FLOW, HEALTH), and deviation queries.

Compound scoping example

FOR ROBOT 'robot_42' FOR ENVIRONMENT 'production' FROM traces
WHERE action_name = '/navigate_to_pose' AND status = 'ERROR'
SINCE 1 hour ago

Joint state array indexing

ROS2 sensor_msgs/JointState messages store joint positions, velocities, and efforts as arrays. The index of each joint corresponds to its position in the name[] array — which is defined by the URDF.

Position by index

-- Joint 0 position
FROM joint_states WHERE fields['position[0]'] > 1.5 FOR ROBOT 'arm_01'

-- Joint 2 position error in JOINT DEVIATION
JOINT DEVIATION FOR ROBOT 'arm_01' SINCE 1 hour ago

fields['position[0]'] compiles to "fields"->'position'->>0 in SQL.

What does position[0] mean?

The index is meaningless without the joint map. For example, for a 6-DOF arm:

IndexJoint nameTypeRange
0shoulder_panrevolute±3.14 rad
1shoulder_liftrevolute±1.57 rad
2elbow_flexrevolute0..2.27 rad
3wrist_1revolute±3.14 rad
4wrist_2revolute±3.14 rad
5wrist_3revolute±3.14 rad

Inspect the joint map for any robot with:

SHOW JOINTS FOR ROBOT 'arm_01'

Path to named joint access

Named joint access (e.g. shoulder_pan instead of position[0]) is planned but requires FOR ROBOT scope to resolve the joint map at query time. See #65 for progress.

Until then: use SHOW JOINTS to look up the index, then query by index.


ANOMALY and the FACET requirement

ANOMALY(field) COMPARED TO <baseline> computes per-group z-scores by comparing a current window to a baseline. Without FACET, it compares all spans together — mixing /navigate_to_pose spans, heartbeats, diagnostics, and anything else in otel_traces. This produces a statistically incoherent distribution.

Why FACET matters

Imagine your navigation actions take ~2 seconds and your heartbeats take ~5 ms. Without FACET:

  • Mean ≈ 200 ms (dominated by volume of small spans)
  • A 3-second navigation span has z_score ≈ 1.4 — not anomalous
  • A 500 ms heartbeat has z_score ≈ 1.6 — "more anomalous" than the slow navigation

This is the apples-and-oranges problem. With FACET action_name:

  • The /navigate_to_pose distribution is compared only to other /navigate_to_pose spans
  • A 3-second navigation span is correctly flagged as anomalous against its own baseline

Use FACET

-- Good: compares like-for-like spans
ANOMALY(duration) COMPARED TO last week FACET action_name

-- Good: per-robot anomaly detection
ANOMALY(duration) COMPARED TO fleet FACET robot_id

-- Avoid: mixes all span types
ANOMALY(duration) COMPARED TO last week

ROSQL will emit a ANOMALY_NO_FACET warning (not an error) if you omit FACET, but the query will still run — just with potentially misleading results.