Skip to main content

ServiceRadar Query Language (SRQL) - Language Reference

Overview

ServiceRadar Query Language (SRQL) now uses a key:value syntax that is parsed and executed by the Rust-based SRQL service (rust/srql). The engine plans queries against our OCSF-aligned streaming schema defined in pkg/db/migrations, translates them to CNPG SQL via Diesel, and returns consistently shaped results. SRQL keeps its readable style while gaining better alignment with the Open Cybersecurity Schema Framework (OCSF) entities that underpin ServiceRadar.

Use SRQL to:

  • Select one or more OCSF data domains with in:<entity>
  • Filter using key:value pairs and nested attribute groups
  • Control result shape with sorting, limiting, aggregation statistics, and windowing
  • Switch between point-in-time results and streaming updates

Target Entities and OCSF Alignment

Target data with the in: selector. Each logical entity routes to one or more OCSF tables or streams introduced in the 00000000000002_* through 00000000000005_* migrations.

SRQL EntityDescriptionPrimary OCSF Source
in:devicesDevice inventory and current state (includes discovery metadata and observables)ocsf_device_inventory, ocsf_devices_current
in:activityNormalized activity & network telemetry. Alias for events and maps to connection/flow classes.ocsf_network_activity, ocsf_system_activity
in:flowsFlow-level telemetry aligned to OCSF network activity class 4001ocsf_network_activity
in:connectionsConnection state and summaries with endpoint metadataconnections, ocsf_network_activity
in:servicesObserved network/application services and their availabilityservices materialized view
in:interfacesDiscovered interfaces with OCSF endpoint metadatadiscovered_interfaces
in:logsApplication and system logs normalized to OCSF logging classeslogs, ocsf_system_activity
in:pollersPoller/agent operational telemetrypollers
in:cpu_metrics / in:disk_metrics / in:memory_metrics / in:process_metrics / in:snmp_metricsTime-series metrics aligned with OCSF telemetry categoriescpu_metrics, disk_metrics, memory_metrics, process_metrics, timeseries_metrics
in:otel_tracesOpenTelemetry spans & summariesotel_trace_summaries_final, otel_spans_enriched

in: accepts comma-separated targets (e.g. in:devices,services). SRQL resolves friendly field names to the correct OCSF column names via the Diesel query builders in rust/srql/src/query; for example device.os.name maps to device_os_name and boundary is normalized to partition.

The migrations in 00000000000003_ocsf_entity_state_streams.up.sql and 00000000000005_ocsf_materialized_views.up.sql also provision current-state streams for users, vulnerabilities, and other OCSF classes. As those entities are surfaced through SRQL aliases they inherit the same key:value syntax described below—no query changes are required beyond swapping the in: target.

Filters and Field References

Key:Value Filters

  • Basic comparisons use field:value, e.g. hostname:%cam% or severity_id:2.
  • Values are case-sensitive unless the underlying column is normalized. Use quotes for values with spaces: device.location:"Building A".
  • SRQL maps lists with commas to SQL IN/NOT IN: device_type_id:(1,7).

Range Queries

  • Use standard comparison operators for numeric fields: usage_percent:>80, latency_ms:>=500.
  • Supported operators: >, >=, <, <=.
  • Combine multiple filters for ranges: usage_percent:>80 usage_percent:<90.

Nested Attributes

Wrap a nested group in parentheses to drill into OCSF objects:

in:activity connection:(src_endpoint_ip:10.0.0.% dst_endpoint_port:(22,2222))

Nested keys concatenate with dots internally (connection.src_endpoint_ip).

Arrays and Observables

  • Repeating the same key expresses “contains all” semantics for arrays: discovery_sources:(sweep) discovery_sources:(armis).
  • Use observable shortcuts created in the migrations: observable:ip scans across observables_ip collections. Combine with value: to match against a specific observable value.

Negation and Wildcards

  • Prefix a key with ! to invert it: !device.status:deleted, !hostname:%test%.
  • % acts as a wildcard for string comparisons and emits LIKE/NOT LIKE SQL as appropriate.

Time Scoping

Control temporal filters with time: or timeFrame: keys.

  • Relative windows: time:last_24h, time:last_7d, time:last_30m.
  • Human phrases convert automatically: timeFrame:"7 Days"time:last_7d.
  • Absolute ranges: time:[2024-06-01T00:00:00Z,2024-06-02T00:00:00Z]. Leave one side blank to create open-ended ranges.
  • Shortcuts time:today and time:yesterday apply date equality on the entity’s timestamp field (see entity_mapping.ml).

If no time filter is supplied, the engine injects the default window configured by the API (commonly the last 24 hours).

Sorting, Limiting, and Result Shape

  • limit:<n> caps the number of rows returned.
  • sort:field[:direction] applies ordering. Specify multiple sort keys separated by commas: sort:time:desc,traffic_bytes_out.
  • stream:true or mode:stream returns a streaming cursor when the backend supports it.

Aggregations, Windows, and Having

SRQL supports lightweight analytics without writing raw SQL:

  • stats:"count() by device.type_id" emits SELECT count() ... GROUP BY device_type_id.
  • window:5m buckets results when paired with stats to create tumbling window aggregations.
  • having:"count()>10" filters aggregated results after grouping.

Use these constructs together:

in:activity time:last_24h stats:"count() as total_flows by connection.src_endpoint_ip" sort:total_flows:desc having:"total_flows>100" limit:20

The planner converts aggregations into valid CNPG SQL, handling count_distinct, percentile helpers (p95(bytes)), and alias propagation.

Streaming Queries

Set stream:true to subscribe to entity streams such as ocsf_network_activity. Combine with window for sliding analytics or leave window unset for raw event feed semantics. stats + stream:true produces continuously updating grouped results with the backend’s incremental materialized view engine.

Example Queries

  • Devices discovered by multiple sources in the past week: in:devices discovery_sources:(sweep) discovery_sources:(armis) time:last_7d sort:last_seen:desc

  • High-volume web activity from a private network block: in:activity time:last_24h src_endpoint_ip:10.0.% dst_endpoint_port:(80,443) stats:"sum(traffic_bytes_out) as bytes_out by src_endpoint_ip" window:1h sort:bytes_out:desc having:"bytes_out>100000000"

  • Detect devices with elevated CPU usage during the last hour: in:cpu_metrics time:last_1h stats:"avg(usage_percent) as avg_cpu by device_id" having:"avg_cpu>85" sort:avg_cpu:desc

  • Track SSH or SFTP services discovered in the last two weeks: in:services service_type:(ssh,sftp) timeFrame:"14 Days" sort:timestamp:desc

  • OpenTelemetry traces exceeding latency SLO: in:otel_traces service.name:"serviceradar-poller" stats:"p95(duration_ms) as p95_latency by service.name" window:5m having:"p95_latency>1000"

Best Practices

  • Anchor every query with in: and an explicit time window to constrain scans.
  • Prefer SRQL field aliases (e.g. device.os.name, connection.dst_endpoint_ip) over raw column names; the engine keeps them aligned with the OCSF migrations.
  • Use repeated keys for array containment checks and comma lists for scalar IN comparisons.
  • Inspect new OCSF columns in pkg/db/migrations before adding filters so names stay consistent with upstream schema revisions.
  • Validate complex queries with the srql.validate MCP tool or the SRQL CLI under rust/srql.

Supported Filter Fields by Entity

Each entity supports a specific set of filter fields. Using an unsupported field will return an error indicating the invalid field name.

devices

FieldDescription
device_idUnique device identifier
hostnameDevice hostname (supports wildcards)
ipIP address (supports wildcards)
macMAC address (supports wildcards)
poller_idAssociated poller ID
agent_idAssociated agent ID
is_availableAvailability status (true/false)
device_typeType of device
service_typeType of service
service_statusService status
discovery_sourcesSources that discovered this device (array containment)

events

FieldDescription
idEvent identifier
typeEvent type
sourceEvent source
subjectEvent subject
datacontenttypeContent type of event data
remote_addrRemote address
hostHost name
specversionCloudEvents spec version
severitySeverity level
short_messageShort message text
versionVersion string
levelNumeric level

logs

FieldAliasesDescription
trace_idOpenTelemetry trace ID
span_idOpenTelemetry span ID
service_nameName of the service
service_versionService version
service_instanceService instance identifier
scope_nameInstrumentation scope name
scope_versionInstrumentation scope version
severity_textseverity, levelText representation of severity
bodyLog message body
severity_numberNumeric severity level

traces (otel_traces)

FieldAliasesDescription
trace_idOpenTelemetry trace ID
span_idSpan identifier
parent_span_idParent span identifier
service_nameName of the service
service_versionService version
service_instanceService instance identifier
scope_nameInstrumentation scope name
scope_versionInstrumentation scope version
namespan_nameSpan name
status_messageStatus message
status_codeNumeric status code
kindspan_kindSpan kind (integer)

services

FieldAliasesDescription
service_namenameName of the service
service_typetypeType of service
poller_idAssociated poller ID
agent_idAssociated agent ID
partitionPartition identifier
messageStatus message
availableAvailability status (true/false)

pollers

FieldDescription
poller_idPoller identifier
statusPoller status
component_idComponent identifier
registration_sourceRegistration source
spiffe_identitySPIFFE identity
created_byCreator identifier
is_healthyHealth status (true/false)

otel_metrics

FieldAliasesDescription
trace_idOpenTelemetry trace ID
span_idSpan identifier
service_nameserviceName of the service
span_nameSpan name
span_kindSpan kind
metric_typetypeType of metric
componentComponent name
levelLevel
http_methodHTTP method
http_routeHTTP route
http_status_codeHTTP status code
grpc_servicegRPC service name
grpc_methodgRPC method name
grpc_status_codegRPC status code
is_slowSlow request flag (true/false)

cpu_metrics

FieldDescription
poller_idAssociated poller ID
agent_idAssociated agent ID
host_idHost identifier
device_idDevice identifier
partitionPartition identifier
clusterCluster name
labelLabel
core_idCPU core identifier
usage_percentCPU usage percentage
frequency_hzCPU frequency in Hz

memory_metrics

FieldDescription
poller_idAssociated poller ID
agent_idAssociated agent ID
host_idHost identifier
device_idDevice identifier
partitionPartition identifier
usage_percentMemory usage percentage
total_bytesTotal memory in bytes
used_bytesUsed memory in bytes
available_bytesAvailable memory in bytes

disk_metrics

FieldDescription
poller_idAssociated poller ID
agent_idAssociated agent ID
host_idHost identifier
device_idDevice identifier
partitionPartition identifier
mount_pointFilesystem mount point
device_nameDevice name
usage_percentDisk usage percentage
total_bytesTotal disk space in bytes
used_bytesUsed disk space in bytes
available_bytesAvailable disk space in bytes

timeseries_metrics

FieldDescription
poller_idAssociated poller ID
agent_idAssociated agent ID
metric_nameName of the metric
metric_typeType of metric
device_idDevice identifier
target_device_ipTarget device IP address
partitionPartition identifier
if_indexInterface index
valueMetric value

interfaces

FieldAliasesDescription
device_idDevice identifier
device_ipipDevice IP address
poller_idAssociated poller ID
agent_idAssociated agent ID
if_nameInterface name
if_descrdescriptionInterface description
if_aliasInterface alias
if_phys_addressmacPhysical (MAC) address
if_admin_statusAdministrative status
if_oper_statusstatusOperational status
if_speedspeedInterface speed
ip_addressesip_addressIP addresses assigned to interface

Error Handling

Common issues and suggested fixes:

  • Unsupported filter field – The field name is not valid for the specified entity. Check the Supported Filter Fields section above for valid fields.
  • Unknown field – The key cannot be mapped via entity_mapping. Check the OCSF migration files or use the CLI's schema inspection.
  • Missing target entity – Add in:<entity> to specify which OCSF domain to query.
  • Invalid time range – Ensure time: ranges are well-formed (last_<number><unit> or [start,end]).
  • Aggregation conflicts – When using stats, ensure grouped fields appear inside the by clause and reference aliases correctly in having.
  • Unsupported negation form – Negation applies to the key (!key:value) rather than the value (key:!value).

SRQL is designed to evolve with the OCSF schema. As additional migrations add classes or fields, extend your queries by following the same key:value conventions and the alignment guidance above.