Skip to content

Integration  ·  IT and security

How to build SaaS security log collection

The investigation needs last Tuesday's sign-ins from the HR system, and the feed stopped in March. The design behind log collection that notices when it goes quiet, the prompts that build it, and what running it takes.

Built with Tray Headless

  1. System Okta
  2. Step Pull on a schedule
  3. Step Map to one shape
  4. Step Watch for silence
  5. System Splunk
Also Slack

Every source has an expected rhythm, so a feed that goes quiet raises an alert instead of leaving a gap nobody finds until an investigation needs it.

The short answer

What is SaaS security log collection?

SaaS security log collection has four parts: an inventory of which apps matter and which of their events detections need, collection that pulls each app's events on a schedule and picks up where it left off, mapping every event to one shape so a sign-in looks the same whichever app it came from, and a watch on each feed that alerts when it goes quiet. The part teams skip is the watch. A feed that stops sends no error, so the gap is found months later, by the investigation that needed it.

Stage 1 of 7: Security log collection. Part of Security operations, end to end : every stage, the systems it runs on and the guide that builds it.

What matters here

  • Start from the detections you want, not from every log an app can produce. Volume costs money and hides the events that matter.
  • Pull from where the last run stopped, not from a fixed window. A fixed window drops events whenever a run is late.
  • Map every event to one shape. A sign-in should look the same in the SIEM whether it came from Okta, Google Workspace or GitHub.
  • Watch every feed for silence. A feed that stops sends no error, and nothing else will tell you.
  • Keep the raw event next to the mapped one. An investigation always needs a field the mapping dropped.

Who this is for

You run security operations or detection engineering. Your company runs on dozens of SaaS apps, and the SIEM sees a fraction of what they record.

How it works in practice

From an event happening in an app to it being searchable next to everything else.

  1. 1

    Each app is listed with the events detections need

    Sign-ins, admin changes, permission grants, data exports and API token creation, per app, with an owner.

  2. 2

    Events are pulled on a schedule from where the last run stopped

    So a late or failed run catches up rather than leaving a gap.

  3. 3

    Every event is mapped to one shape

    Who, what, when, from where, on which app, with the raw event kept alongside.

  4. 4

    Events land in the SIEM within minutes

    Batched for cost, but never held long enough to slow a detection.

  5. 5

    Each feed is watched for silence

    An app that normally sends events every few minutes and has sent none for an hour raises an alert.

  6. 6

    Coverage is reported

    Which apps feed the SIEM, how late each feed runs, and which apps still don't feed it at all.

What log collection is made of

Four parts, and the last one is the one that decides whether the other three can be trusted.

A source inventory

Which apps hold sensitive data or admin power, and which of their events a detection or investigation needs. The list is the scope.

Collection that resumes

Each run starts where the last one stopped and records where it reached. Late runs catch up, and nothing is pulled twice.

One shape for every event

Actor, action, target, time, source address and app, in the same fields for every source, plus the raw event.

A watch on every feed

Each source has an expected rhythm. Silence beyond it is an alert with an owner, not a gap found later.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    Set up, then build the source inventory

    Collecting everything costs money and buries the events that matter.

    Headless skills build-workflow

    Use build-workflow. The systems in play are Okta, Office365
    Management, Google Workspace, GitHub, Splunk HTTP Event Collector,
    Slack and AWS S3, or whatever we run in those seats. Before you plan
    anything, tell me which of them are already authenticated in the
    workspace, because I do not want a connector stubbed that I have not
    authenticated.
    
    Start with the inventory, not the pipes. For each app list: what
    sensitive data or admin power it holds, which of its events a detection
    or investigation needs (sign-ins, admin changes, permission grants, data
    exports, new API tokens), how it exposes them, and who owns the app.
    
    Mark the apps that hold sensitive data but expose no events at all.
    That list is worth knowing before anybody claims coverage.
  2. 2

    Pull each source from where the last run stopped

    A fixed time window drops events every time a run is late.

    Headless skills build-workflow

    Use build-workflow. For each source, build a scheduled pull that:
    
      Reads the position where the last successful run stopped
      Requests events from that position, page by page
      Records the new position only after the events have landed
      Catches up in order if a run was missed or failed
    
    Respect each app's rate limits and slow down when it asks. Some apps
    only keep events for a few days, so a feed that falls behind by more
    than that loses them for good. Alert well before that point.
    
    Never use "the last fifteen minutes" as the window. A run that starts
    late by two minutes drops two minutes of events, every time.
  3. 3

    Map every event to one shape, and keep the raw

    A sign-in should look the same whichever app it came from.

    Map every event to the same fields:
    
      Actor: user, email, and whether it is a person or a service account
      Action: sign-in, failed sign-in, admin change, permission grant,
      export, token created
      Target: what was acted on
      Time in UTC, source address, user agent, and app
    
    Send the mapped event to the SIEM with the raw event attached. Every
    investigation eventually needs a field the mapping dropped, and the
    raw event is the only place it still exists.
    
    Keep a copy in cheap storage for as long as policy says. Most SIEMs
    keep data for months, and an investigation sometimes needs a year.
  4. 4

    Watch every feed for silence

    A feed that stops sends no error.

    Headless skills tray-gotchas

    Use tray-gotchas, then learn each source's normal rhythm from two
    weeks of data: how many events per hour, by hour of day and day of
    week.
    
    Alert the source owner in Slack when a feed is silent well beyond its
    rhythm, when its volume drops sharply, or when a run has failed several
    times in a row. Include when the last event arrived and what the last
    error was.
    
    A quiet weekend is normal for some apps and a sign of trouble for
    others. Learn the rhythm per source rather than setting one threshold
    for all of them.

    The silence check is the control. Everything else is plumbing, and plumbing fails without telling anyone.

  5. 5

    Report coverage honestly

    Coverage is a claim auditors and the board will test.

    Report weekly: which apps feed the SIEM, how far behind each feed
    runs, which feeds went quiet and for how long, and which apps in the
    inventory still don't feed it.
    
    Count an app as covered only if its events arrived in the last hour
    and its last silence was resolved. An app connected once and broken
    since is not covered.
  6. 6

    Validate it, then hand the inventory to security ops

    Because the list of apps changes every time somebody buys one.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production. Run it alongside any existing feeds for a week and
    compare event counts per source, so a gap shows up before the old feed
    is turned off.
    
    Then open the same workflow in Tray Build so security operations can
    add sources, change the mapping and tune the silence thresholds in the
    visual canvas.

What it connects to

The events live in each app, and the SIEM needs them in one shape and on time.

Okta

Read sign-in, sign-in method and admin events from the system log.

Reads

Office365 Management

Read sign-in, mailbox and admin activity across Microsoft 365.

Reads

Google Workspace

Read admin, sign-in and Drive sharing events.

Reads

GitHub

Read organization audit events: permission changes, new tokens, repository visibility changes.

Reads

Splunk HTTP Event Collector

Send each mapped event, with its raw original attached, into the SIEM.

Writes

AWS S3

Keep a copy of every raw event for as long as policy says, at storage cost.

Writes

Slack

Tell a source's owner when its feed goes quiet, with the last event time and the last error.

Writes

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Teams, Azure Active Directory or Google Chat.

Connections in this build

Field mapping, templates and common problems for each pairing: Office365 Management + Okta, G-Suite + Okta, Office365 Management + Splunk HTTP Event Collector and Okta + Slack.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

This decides what the SIEM can see. A gap here is a gap in every detection that relies on it.

It runs where production runs, not on a laptop

Every source is pulled on schedule, around the clock, with each run and its position recorded.

Every feed has an owner and a rhythm

Silence beyond the rhythm is an alert to a named person, so a broken feed is a ticket, not a surprise.

Managed credentials, not secrets in a config file

Read access to every app's audit log is powerful. Each is a scoped, read-only authentication in your workspace, rotated on its own.

Security ops own the sources

Sources, mapping and silence thresholds open in Tray Build, owned by the team that relies on the data.

Run it alongside the old feed first

A week of both, with event counts compared per source, before anything is turned off.

Questions people ask

Why not collect every log an app produces?

Because volume costs money and buries the events detections need. Start from the detections and investigations you want, and collect what they use.

Why pull from where the last run stopped?

Because a fixed window drops events whenever a run is late. Recording the position after each successful run means a late or failed run catches up instead.

Why keep the raw event?

Because every investigation eventually needs a field the mapping dropped. The raw event is the only place it still exists.

How do you know a feed has stopped?

By learning each source's normal rhythm and alerting when it goes quiet beyond it. A stopped feed sends no error, so silence is the only signal.

What counts as a covered app?

An app whose events arrived in the last hour and whose last silence was resolved. An app connected once and broken since does not count.

Last reviewed October 2026.