Skip to content

SOQL-polled objects

sources.eventlog_objects polls any queryable sObject via SOQL on a timestamp watermark — standard EventLog objects (LoginEvent, ApiEvent), standard security objects (LoginHistory, SetupAuditTrail), or your own custom objects (e.g. MyAudit__c). Point it at an object plus a datetime field that only ever increases, and it becomes a watermarked log feed.

sources:
  eventlog_objects:
    enabled: true
    objects:
      - name: LoginHistory
        timestamp_field: LoginTime
        poll_interval: 5m
        lookback: 1h

How it works

Each configured object is queried every poll_interval as:

SELECT FIELDS(ALL) FROM <name>
WHERE <timestamp_field> >= <watermark>
ORDER BY <timestamp_field> ASC
LIMIT 200

FIELDS(ALL) selects every field without hand-listing columns, but Salesforce requires LIMIT <= 200 with it — hardcoded by the source, not configurable. Throughput isn't capped at 200/interval, though: a full page triggers follow-up queries within the same cycle (drain-until-short-page), so backlogs catch up in one poll.

The cursor is >= (not >) with a rolling record-Id dedup window, so records sharing the exact boundary timestamp are never skipped. The watermark is the previous record's timestamp_field value, persisted per-object under state key eventlog_objects:<name> as {"last_ts": ..., "ids": [...]} (the Id list is the boundary dedup window) — a crash mid-poll re-queries from the last committed watermark, so recovery is a gap-free re-fetch, never a gap in coverage. Records whose timestamp_field comes back null/unparseable are still shipped but never advance the watermark, and a garbage stored watermark falls back to lookback with a warning — a bad value can't wedge the source in a malformed-query loop.

Config keys (EventLogObjectConfig, per object)

Key Default Notes
name required The sObject API name — standard or custom (e.g. MyAudit__c). Must be a bare identifier.
timestamp_field EventDate Must be set to a real field on a custom object; EventDate only exists on EventLog objects.
poll_interval 5m Duration shorthand (5m, 1h30m), ISO-8601 (PT5M), or plain seconds.
lookback 1h Initial query window when no checkpoint exists yet (first run, or after a watermark reset).
big_object false See Big Objects below.
max_catchup_records 200000 Cap on records buffered per big_object DESC drain cycle; 0 = unbounded. Ignored on the ASC path.
sample 1.0 Keep-fraction, deterministic by record Id. See PII Redaction & Sampling.

Requirements: the object must be API-queryable via SOQL, and the integration user (the one authenticated via JWT bearer / client_credentials) needs read access to it and to timestamp_field.

eventlog_objects has no per-object structured-metadata override — it always routes fields via the global sink.loki.structured_metadata_fields list, so add a custom object's high-cardinality fields there if you want them filterable rather than buried only in the JSON line.

Big Objects: descending drain

The stored RTEM event family (LoginEvent, ApiEvent, FileEventStore, Threat-Detection *EventStore, …) are Salesforce Big Objects. Big Objects have restrictive SOQL: they reject ORDER BY ASC (the index is DESC-only), expose no nextRecordsUrl pagination, and reject COUNT()/aggregates. FIELDS(ALL) itself still works — only ascending order is the problem.

big_object: true

Set big_object: true on any object entry backed by a Big Object. Leave it unset (the default) for standard/custom objects (LoginHistory, MyAudit__c, SetupAuditTrail), which use the plain ASC path.

With the flag set, eventlog_objects_source._drain_big_object pages newest-first (ORDER BY <timestamp_field> DESC) with a ratcheting <= upper bound, dedups within the drain and against the checkpoint's Id-window, then re-sorts each cycle's window ascending before emitting — so watermark/dedup/checkpoint semantics match the ASC path exactly from the pipeline's point of view. max_catchup_records bounds how much a single cycle buffers in memory to do that re-sort; when a post-outage catch-up spans a large gap, the drain emits the sorted segment it has and ratchets its upper bound down so catch-up proceeds in bounded chunks across cycles instead of buffering unbounded history. Historical backfill beyond the poll window is a deferred follow-up, not this path.

sources:
  eventlog_objects:
    enabled: true
    objects:
      - name: LoginEvent
        timestamp_field: EventDate
        poll_interval: 5m
        lookback: 1h
        big_object: true

See examples/presets/event-log-objects.yaml.

Login/audit categories via this source

LoginEvent, LoginHistory, and the ELF Login type all cover the same login activity — enable exactly one per the either/or overlap guard. LoginHistory and SetupAuditTrail are standard objects, available without a Shield / Event Monitoring entitlement; LoginEvent is a Big Object that typically requires one.