Skip to content

Query

Storage Streamer queries select matching events from storage via a distributed architecture that guarantees consistent performance regardless of queried data volume.

Each query executes in two phases:

1. Scan — Identifies which files and byte ranges in storage match the target, time range, and search expression. Search expressions support ==, &&, ||, and includes(), and operate on event raw text or fields set by initializers during indexing (e.g. severity_level, http_code, k8s_namespace, country).

2. Stream — Fetches matching byte ranges and streams selected events, filtered by the search expression and optional JavaScript expressions for fine-grained control.

Query Console

The open source Console executes within your infrastructure and provides a web GUI and CLI for submitting queries via SQS or direct REST, with built-in sample queries, dry run preview, and real-time progress tracking via CloudWatch Logs.

Screenshot of the Query Console web GUI showing a search expression, drop filters, time range and target selectors, SQS queue submission, and export options

View on GitHub

Start the web console to author and submit queries from a browser:

python3 console.py --serve

The GUI runs at http://localhost:8080 and opens the browser automatically. Use --port to change the port, or --no-browser to skip the automatic browser launch:

python3 console.py --serve --port 9090 --no-browser

Submit queries directly from the terminal:

# Search for errors in the last 30 minutes
python3 console.py \
  --search 'severity_level=="ERROR"' --since 30m \
  --bucket my-bucket --queue-url $LOG10X_QUERY_QUEUE_URL --follow
# Dry run — print the JSON payload without sending
python3 console.py \
  --search 'http_code=="500"' --since 1h \
  --bucket my-bucket --dry-run
CLI options
Option Description
--search EXPR Search expression (==, &&, \|\|, includes())
--since TIME Relative time range (30s, 5m, 1h, 2d)
--from / --to Absolute time range in epoch milliseconds
--bucket BUCKET S3 bucket containing log files
--index-bucket BUCKET S3 bucket containing index objects (defaults to --bucket)
--queue-url URL SQS queue URL (or set LOG10X_QUERY_QUEUE_URL env var)
--target PREFIX App/service prefix (default: app)
--processing-time DUR Max processing time (default: 60s)
--result-size SIZE Max result volume (default: 10MB)
--log-levels LEVELS Comma-separated log levels (default: ERROR,INFO,PERF)
--filters EXPR JavaScript filter expressions for in-memory filtering
--no-browser Do not open browser automatically when starting web GUI
--dry-run Print JSON payload without sending
--follow Poll CloudWatch Logs until query completes
--query-id ID Monitor an existing query by ID (skips submission, implies --follow)
--region REGION AWS region (default: us-east-1)
--log-group GROUP CloudWatch Logs group (or set TENX_QUERY_LOG_GROUP, default: /log10x/query)

Submit queries directly via HTTP POST to the streamer endpoint:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-5m\")",
    "to": "now()",
    "search": "severity_level == \"ERROR\""
  }'

The query endpoint returns HTTP 200 with a JSON body containing a queryId field:

{ "queryId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }

Use this ID to track query progress via the Web GUI Monitor tab or the CLI --query-id flag:

python3 console.py --query-id a1b2c3d4-e5f6-7890-abcd-ef1234567890
Request Parameters
Parameter Type Description
from Epoch ms Start of the time range (inclusive). Use now("-5m") for relative time or a literal epoch like 1769076000000.
to Epoch ms End of the time range (exclusive). Use now() for current time.
search String Search expression using enriched field names (e.g., severity_level, http_code, k8s_namespace). Must use enriched fields, NOT raw JSON fields like stream, log, or docker. See Sample Queries for working examples. Supports &&, \|\|, ==, and includes().
filters List Optional JavaScript expressions applied in-memory after the scan phase. Supports all TenX JavaScript functions including drop(), startsWith(), endsWith(), match(), and TenXLookup.get().
processingTime Duration Optional max processing time (e.g., parseDuration("5m")). Defaults to 1 minute.
resultSize Bytes Optional max result volume (e.g., parseBytes("10MB")).

Security

Queries can only be initiated by authenticated users with the appropriate AWS IAM permissions. See security architecture for details.

Requirements
  • Python 3.6+ (no external dependencies for the web GUI)
  • boto3 — required only for SQS submission and CloudWatch Logs polling. Install with pip3 install boto3
  • AWS credentials — configured via aws configure or AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY environment variables

The console is at $TENX_MODULES/apps/streamer/console in your local config, or on GitHub at streamer/console.

Sample Queries

Ready-to-use query templates for common scenarios — copy, adjust the time range, and run.

Incident Management

Production errors with stack traces

During an outage, fragmented single-line log entries add noise. This query captures every ERROR and CRITICAL event and keeps only grouped events — multi-line stack traces that contain complete failure signatures:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-5m\")",
    "to": "now()",
    "search": "severity_level == \"ERROR\" || severity_level == \"CRITICAL\"",
    "filters": ["drop(!isGroup)"]
  }'

HTTP 500 errors in a namespace, excluding health checks

Isolate server errors in a specific Kubernetes namespace while filtering out noise from health and readiness probes. The scan phase narrows by http_code and k8s_namespace, then endsWith() removes probe endpoints:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-15m\")",
    "to": "now()",
    "search": "http_code == \"500\" && k8s_namespace == \"production\"",
    "filters": ["drop(endsWith(\"/health\"))", "drop(endsWith(\"/ready\"))"]
  }'

Errors by source code origin

After a deployment, narrow errors to a specific container and code module. The symbol_origin field identifies the source file that produced each event, letting you pinpoint regressions to specific code paths:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-15m\")",
    "to": "now()",
    "search": "severity_level == \"ERROR\" && k8s_container == \"order-service\"",
    "filters": ["drop(!includes(symbol_origin, \"Checkout\"))"]
  }'

Deduplicate repeated stack traces

A single crashing code path can emit thousands of identical stack traces per minute. This query uses TenXCounter to pass only the first 3 occurrences of each unique message_pattern per 5-minute window:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-30m\")",
    "to": "now()",
    "search": "severity_level == \"CRITICAL\" && isGroup == true",
    "filters": ["drop(TenXCounter.inc(concat(\"trace_\", message_pattern), 1, \"5m\") > 3)"]
  }'

Auditing & Compliance

Failed access attempts with geographic context

SOC 2 and ISO 27001 require logging unauthorized access attempts. This query surfaces all HTTP 401/403 responses, automatically enriched with the originating country via GeoIP lookup on the source IP address:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-24h\")",
    "to": "now()",
    "search": "http_code == \"401\" || http_code == \"403\""
  }'

Admin actions from unexpected regions

Surface admin-level events originating from outside expected geographies. The drop() filter inverts an allow-list — dropping events from known countries so only anomalous origins remain:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-24h\")",
    "to": "now()",
    "search": "k8s_container == \"admin-api\" && (severity_level == \"WARN\" || severity_level == \"ERROR\")",
    "filters": ["drop(country == \"US\" || country == \"DE\" || country == \"GB\")"]
  }'

Configuration changes outside approved windows

Change management requires every modification to be traceable to an approved window. This query finds config-related events in the infra namespace, then cross-references each pod against a lookup table of approved changes — dropping approved events so only unauthorized modifications surface:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-48h\")",
    "to": "now()",
    "search": "k8s_namespace == \"infra\" && includes(text, \"config\")",
    "filters": ["drop(TenXLookup.get(\"change_windows\", k8s_pod, \"pod\", \"approved\") == \"true\")"]
  }'

Information Security

Brute force detection by country

Credential stuffing attacks generate high volumes of authentication failures from narrow geographic origins. This query uses TenXCounter to count HTTP 401 events per country in 3-minute rolling windows, surfacing only countries exceeding 50 failures:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-1h\")",
    "to": "now()",
    "search": "http_code == \"401\"",
    "filters": ["drop(TenXCounter.inc(concat(\"authfail_\", country), 1, \"3m\") < 50)"]
  }'

SQL injection pattern detection

Scan HTTP 400 and 500 responses for common SQL injection patterns using regex matching. Events not matching the pattern are dropped, leaving only those containing suspicious SQL keywords:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-12h\")",
    "to": "now()",
    "search": "http_code == \"400\" || http_code == \"500\"",
    "filters": ["drop(!match(text, \"(?i)(SELECT|UNION|DROP|INSERT|DELETE).*(FROM|WHERE|TABLE)\"))"]
  }'

Geographic anomalies in production access

Threat hunting for access from outside expected regions. This query finds successful requests to the production namespace and drops events from North America and Europe, surfacing access from any other continent for investigation:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-6h\")",
    "to": "now()",
    "search": "k8s_namespace == \"production\" && http_code == \"200\"",
    "filters": ["drop(continent == \"NA\" || continent == \"EU\")"]
  }'

Large response payload detection

Data exfiltration often manifests as requests returning abnormally large responses. This query targets a sensitive container, uses regex to extract the response size, and parses it to keep only responses exceeding 50 MB:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-4h\")",
    "to": "now()",
    "search": "k8s_container == \"reporting-api\" && http_code == \"200\"",
    "filters": ["drop(TenXMath.parseInt(match(text, \"bytes_sent=([0-9]+)\")) < 52428800)"]
  }'

Metric Aggregation

Error count by k8s container

Build a live error leaderboard by counting errors per k8s_container in rolling 5-minute windows. TenXCounter tracks each container independently, and the query surfaces only containers with 10 or more errors:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-1h\")",
    "to": "now()",
    "search": "severity_level == \"ERROR\" || severity_level == \"CRITICAL\"",
    "filters": ["drop(TenXCounter.inc(concat(\"err_\", k8s_container), 1, \"5m\") < 10)"]
  }'

Traffic volume by continent

Aggregate request volume by continent in hourly windows for capacity planning and CDN configuration. Continents with fewer than 100 requests are dropped, leaving only statistically meaningful traffic segments:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-24h\")",
    "to": "now()",
    "search": "http_code == \"200\" || http_code == \"201\"",
    "filters": ["drop(TenXCounter.inc(concat(\"continent_\", continent), 1, \"1h\") < 100)"]
  }'

Recurring error pattern frequency

Identify which error types dominate by counting each unique message_pattern in a 30-minute window. Patterns appearing fewer than 25 times are dropped, surfacing only the most frequent error signatures:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-30m\")",
    "to": "now()",
    "search": "severity_level == \"ERROR\" || severity_level == \"WARN\"",
    "filters": ["drop(TenXCounter.inc(concat(\"pat_\", message_pattern), 1, \"30m\") < 25)"]
  }'

Dynamic Regulation

Drop low-severity noise

During incidents, TRACE and DEBUG events add noise without actionable signal. This filter drops them to focus on events at WARN and above, using the severity_level field set at index time:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-5m\")",
    "to": "now()",
    "search": "severity_level == \"INFO\" || severity_level == \"WARN\" || severity_level == \"ERROR\" || severity_level == \"CRITICAL\"",
    "filters": ["drop(severity_level == \"TRACE\" || severity_level == \"DEBUG\")"]
  }'

Region-focused monitoring

A regional operations team can restrict query results to a specific continent, dropping all events from other geographies to focus dashboards on local traffic:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-30m\")",
    "to": "now()",
    "search": "severity_level == \"ERROR\"",
    "filters": ["drop(continent != \"EU\")"]
  }'

Health check and readiness probe removal

Kubernetes health and readiness probes generate high-volume INFO events that obscure application-level logs. Multiple drop() filters remove these known patterns using endsWith() and includes() from the TenX JavaScript API:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-30m\")",
    "to": "now()",
    "search": "severity_level == \"INFO\"",
    "filters": ["drop(endsWith(\"/health\"))", "drop(endsWith(\"/ready\"))", "drop(includes(text, \"kube-probe\"))"]
  }'

Stack trace flood control

Rate-limit repeated stack traces during an outage. TenXCounter tracks each unique combination of message_pattern and symbol_origin in 10-minute windows, passing only the first 5 occurrences and dropping the rest:

curl -X POST http://localhost:8080/streamer/query \
  -H "Content-Type: application/json" \
  -d '{
    "from": "now(\"-1h\")",
    "to": "now()",
    "search": "isGroup == true && (severity_level == \"ERROR\" || severity_level == \"CRITICAL\")",
    "filters": ["drop(TenXCounter.inc(concat(\"flood_\", message_pattern, \"_\", symbol_origin), 1, \"10m\") > 5)"]
  }'