developer guide
Bringing Splunk data into the grid
The grid works from exported search results. Export a search as CSV, JSON or NDJSON and it lands in the grid the same way any other file does.
Where the grid starts
The grid works from exported search results. It does not read Splunk's storage directly, so the way in is the export: run the search you want, take the results out as CSV, JSON or NDJSON, and load them.
Exporting a search result is something Splunk already does well, in a shape the grid already reads, and it can be automated so nobody exports anything by hand.
Export a search as CSV, JSON, XML or raw
Three ways to get a search result out of Splunk in a shape the grid reads, all producing the same rows.
From the UI. Run the search, then Export from the results toolbar and choose CSV, XML, JSON or raw. CSV is the plainest match for a grid.
From the CLI. splunk search takes an -output flag naming the same formats:
splunk search "search index=security sourcetype=firewall earliest=-24h" \
-output csv -maxout 0 > firewall-24h.csv
From the REST API. Create a search job, then read its results with output_mode set to
csv, json, or one of Splunk's other output modes, over ordinary HTTPS:
https://<host>:<mport>/services/search/jobs/{search_id}/results?output_mode=csv
The REST route is the one worth automating: a scheduled job that lands a fresh export on a schedule, with no person exporting anything by hand.
Landing an export in the grid
A CSV export goes through grid.import, the same pipeline behind the grid's own "Import rows
from CSV" affordance: parse, infer each column's type, preview the mapping, then apply.
import { createGrid } from '@toclocoinc/lattice-grid';
const grid = createGrid(el, { columns, rowKey: 'id', import: true });
// The CSV a Splunk export produced: from the UI's "Export Results", the CLI's
// -output csv, or the REST results endpoint below. grid.import infers each
// column's type and previews the mapping before anything lands.
const text = await file.text();
grid.import.apply(grid.import.preview(text));
A JSON or NDJSON export goes through createUrlSource, which reads a JSON array whole or
streams an NDJSON file line by line, rendering the first rows before the rest has finished arriving:
import { createGrid, createUrlSource } from '@toclocoinc/lattice-grid';
// A REST results export saved as JSON, or fetched directly:
// GET /services/search/jobs/{search_id}/results?output_mode=json
const grid = createGrid(el, {
columns, rowKey: 'id',
source: createUrlSource('/exports/splunk-results.json'),
});
Routing events to S3, then querying them with DuckDB
Splunk's Ingest Actions can route event data to an S3 (or S3-compatible) destination as it arrives, as raw text, NDJSON or JSON. What lands there is ordinary files in a bucket you control, so the DuckDB adapter reads it directly, the same way it reads any other Parquet, CSV or NDJSON in S3:
import { createGrid, createPushdownSource, duckdbAdapter } from '@toclocoinc/lattice-grid';
import * as compute from '@toclocoinc/lattice-grid';
// Splunk's Ingest Actions can route event data to an S3 destination as raw
// text, NDJSON or JSON, entirely separate from its own indexed buckets. Point
// DuckDB straight at that landing prefix; the grid never touches Splunk.
const grid = createGrid(el, {
columns,
rowKey: 'event_id',
source: createPushdownSource({
adapter: duckdbAdapter({
connection,
from: "read_ndjson_auto('s3://your-bucket/splunk-events/*.json')",
}),
compute,
pageSize: 200,
}),
});
One thing to be clear about: this route works because Ingest Actions writes an open format to a destination you own. Pointing the grid at Splunk's own storage is not something it does.
See a lake queried the same way: bringing the Parquet security logs you already keep in S3 into the grid, and triage a day of security events live. The DuckDB adapter guide covers credentials, pushdown and whole-set statistics in full, and connect your data lists every source and adapter the grid ships.