SPLap 2.1.1 · engineering notes
Importing a race into SPLap
SPLap ships with one real session already loaded (2025 Italian Grand Prix, Monza, race window 14:00–14:13:30 UTC, from
OpenF1) plus the labelled synthetic test fixture. Any other historical session can be imported three ways. All three
produce the same canonical events (docs/DATA_SCHEMA.md) in one index (default splap), keyed by an idempotent
import_id, and the Pit Wall reads them through the same backend as the packaged session.
| Path | Where it runs | Needs | Best for |
|---|---|---|---|
| Connect Data wizard | Your browser, inside Splunk Web | Your Splunk role can write via receivers/stream (edit_tcp); browser can reach api.openf1.org |
Trying a session in minutes, no shell |
| Offline race bundle | Browser (folder upload) or CLI | A .zip/folder produced by splap_import.py fetch on any machine with internet |
Air-gapped Splunk, repeatable demos, sharing a dataset |
CLI tools/splap_import.py |
Python 3.9+ on any host | Splunk management port (8089) credentials or a HEC token, via arguments/env only | Larger windows, automation, FastF1 sessions |
No provider key is needed: OpenF1 is open. No credential is ever placed in browser JavaScript, source control or logs.
1. Connect Data wizard (browser)
Open Connect Data → Import Historical Race (/app/splap/connect_data?source=openf1).
- Season – seasons are listed from OpenF1
meetings. - Grand Prix – meetings of that season, newest first.
- Session – Practice/Qualifying/Sprint/Race; Race is preselected.
- Capability preview – the wizard probes
drivers,laps,pit,race_control,weatherand a 10-secondlocation/car_datasample and shows what the provider actually has for this session (counts, sample rate, missing channels). Nothing is written yet. - Profile and window –
- Quick – location (positions on the map) only, no
car_data; smallest. - Engineering – location + car_data (speed, gear, throttle, brake, DRS) for every driver.
- Selected drivers – engineering channels for the drivers you tick.
- The window (UTC
HH:MM:SS, defaults to the race start) bounds the telemetry fetch. Laps, stints, pits, race control, weather, overtakes and positions are always fetched for the whole session; intervals from two minutes before the window. The estimate box shows expected events, ingest volume and provider requests. - Index – type an index name and Check. The wizard tells you whether it exists and whether your role can write.
Create index uses
data/indexesif your role allows it. Indexed events use the app'sprops.conffor timestamps, so the sourcetypes must besplap:*(the wizard enforces this). - Import – the wizard first computes the
import_idand refuses if that id is already in the index (tick force re-import only if you really want duplicates), then fetches at ≤ 2.5 requests/s, derives the circuit geometry and 500 ms replay frames in the browser, and streams NDJSON batches to/services/receivers/stream?index=…&sourcetype=splap:…using your own Splunk Web session and CSRF form key. Each batch is retried up to four times; Cancel stops after the current batch. The log panel lists every provider request and every write. - Verify and open – counts per sourcetype for this
import_idstraight from the index, first/last timestamp, circuit summary, then Open in Pit Wall (pit_wall?index=<index>&session_key=<key>).
Import status events (splap:import_status, phases start/complete/failed) are written alongside the data and
listed at the bottom of Connect Data.
If the browser cannot reach OpenF1
Corporate proxies often block api.openf1.org. Install Doctor → Provider connectivity tells you. Use a bundle or the
CLI instead; the app itself never needs internet.
2. Offline race bundle
Produce a bundle on any machine with internet:
python3 tools/splap_import.py fetch --session 9912 \
--window 2025-09-07T14:00:00 2025-09-07T14:13:30 --profile engineering \
--out bundles/monza_2025 --zip
python3 tools/splap_import.py validate --bundle bundles/monza_2025
The folder (and .zip) contains manifest.json, session.json, drivers.json, laps.ndjson.gz,
telemetry.ndjson.gz, location.ndjson.gz, race_events.ndjson.gz, replay_frames.json.gz, track.geojson,
team_palettes.json, validation.json, ATTRIBUTION.md and checksums.json (SHA-256 of every file; readers refuse a
bundle whose checksums do not match). Format details: docs/DATA_SCHEMA.md § Offline bundle.
Load it either in the browser (Connect Data → Load SPLap race bundle, pick the folder; files are decompressed
with DecompressionStream and verified against checksums.json before anything is written) or with the CLI:
SPLUNK_PASSWORD='…' python3 tools/splap_import.py ingest --bundle bundles/monza_2025.zip \
--splunk https://splunk.example:8089 --user admin --index splap --create-index --verify
The committed bundles/monza_2025_window/ is the exact dataset the packaged demo was built from and is what the unit
tests run against.
3. CLI end to end
python3 tools/splap_import.py seasons # 2023 … 2026
python3 tools/splap_import.py meetings 2025 # meeting_key, name, circuit, dates
python3 tools/splap_import.py sessions --meeting 1268 # session_key 9912 = Race
python3 tools/splap_import.py fetch --session 9912 --window 2025-09-07T14:00:00 2025-09-07T14:13:30 --out bundles/monza_2025
python3 tools/splap_import.py ingest --bundle bundles/monza_2025 --hec https://splunk.example:8088 --index splap
python3 tools/splap_import.py doctor # python version, fastf1 presence, cache, provider reachability
Options: --profile quick|engineering|selected|full, --no-telemetry, --step-ms 250..500 (replay frame period),
--cache DIR (raw OpenF1 responses are cached as JSON so re-runs are offline and deterministic), --force (re-import
an existing import_id), --no-frames (skip splap:replay_frame events — only for analysis-plane use; the Pit Wall needs
replay frames and reports "No replay frames for this session" without them).
Credentials: --password/--token/--hec-token or SPLUNK_PASSWORD / SPLUNK_TOKEN / SPLUNK_HEC_TOKEN. They are
used for the request only and never written anywhere. --verify prints per-sourcetype counts after ingest.
FastF1 (optional)
If the fastf1 package is installed, splapdata.providers_extra.fastf1_fetch(year, gp, session) returns canonical
lap, car_data, location, weather and race_control events from the FastF1 timing feed at 240 ms resolution.
It is a Python-only path (FastF1 has no browser equivalent) and produces no session/driver/position/interval
events itself, so today it is a supplement to an OpenF1 bundle rather than a replacement. See docs/DATA_SOURCES.md.
4. Making a session the packaged demo
fixture writes the three lookups (splap_monza_2025_events/telemetry/frames.csv.gz), the static replay assets under
appserver/static/sessions/<name>/, the registry entry in appserver/static/data/sessions.json, and appends the
transforms.conf lookup stanzas if they are missing:
python3 tools/splap_import.py fixture --session 9912 --window 2025-09-07T14:00:00 2025-09-07T14:13:30 --name monza_2025
Registry entries with "data_mode": "synthetic" must carry SYNTHETIC in their label; the tests enforce it.
5. Idempotence and re-imports
import_id = "imp_" + sha256(json.dumps({"p": provider, "s": str(session_key), "profile": profile, "w": window},
sort_keys=True))[:16]. The browser (importer.js, pure-JS SHA-256 when WebCrypto is unavailable) and the CLI produce
the same id for the same inputs — tests/test_splapdata.py pins imp_789c180679bb8775 for the 14:05–14:08 quick
window. Before any write, both check index=<idx> import_id=<id> sourcetype=splap:session and stop if it exists.
Changing the window or profile is a new import_id, so the same session can coexist at different resolutions; the
Pit Wall's session picker (Look for imported sessions) lists each session_key once (all frames for that session
key are read, so keep one import per session per index unless you use --force deliberately).
To remove an import: | delete on index=splap import_id=<id> (requires the can_delete role) or clean the index.
6. Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "CSRF validation failed" on index check/create | Splunk Web session expired | Reload the page and log in again |
| Index check says "cannot write" | Role lacks edit_tcp |
Ask an admin, or use the CLI with HEC |
| Verify shows fewer events than sent | Indexing lag on a busy host | Re-check counts after a few seconds |
Events land with today's _time |
splap:* sourcetype props not applied (app not installed on the indexer) |
Install the app on indexers/heavy forwarders too, or use HEC on a host with the app |
| Pit Wall shows "TELEMETRY UNAVAILABLE" | Quick profile or provider has no car_data |
Re-import with the engineering profile; the capability preview shows what exists |
| Provider probe fails in Install Doctor | Browser blocked from api.openf1.org |
Use a bundle or the CLI; the app never needs internet itself |
