Linux Telemetry Schema
This page documents the complete schema for all telemetry event types collected by Workshop from Santa agents on Linux.
Each event type below is also the table name in SQL queries, prefixed with linux_: exec fields live in linux_exec_2026, linux_exec_202603, or linux_exec_20260315 (see table naming).
The prefix exists because fork and exit are collected on macOS too, with entirely different columns.
Columns drift across Santa versions, so DESCRIBE linux_exec_20260315 on your own data is the authoritative list.
Nothing on this page is shared with the macOS schema, including the base fields. A field with the same name on both platforms does not necessarily mean the same thing, and a query written against one platform will not run against the other.
Base Fields
| Field | Type | Description |
|---|---|---|
| EventID | text | Unique identifier for the event |
| MachineID | text | The unique machine ID (host UUID) |
| Hostname | text | The hostname of the machine at the time of the event |
| BootID | text | The kernel’s boot identifier, stable for the lifetime of one boot |
| EventTime | timestamp | When the event occurred |
| ProcessedTime | timestamp | When Workshop processed the event |
| OperatingSystem | text | The platform the telemetry came from, always linux in these tables |
Process Events
These are the events that make up the lifecycle of a process: it is created by linux_fork, replaces itself with a new program by linux_exec, and ends by linux_exit.
linux_fork
A process creating another process.
SharedThreadGroup is what separates a new thread of the same program from a genuinely independent process, and it decides that on its own.
SharedMm and SharedFiles each report one resource shared independently of that: a thread commonly shares both, but neither is required for thread-group membership, and either can be shared by a task that is a separate process.
| Field | Type | Description |
|---|---|---|
| Subject | Lineage | The process performing the creation, with the process that started it |
| Object | Process | The newly created process |
| SharedThreadGroup | boolean | Whether the new task joined its creator’s thread group, making it a thread of the same program |
| SharedMm | boolean | Whether the new task shares its creator’s address space |
| SharedFiles | boolean | Whether the new task shares its creator’s file descriptor table |
| Container | Container | The container the subject ran in. Absent when it ran directly on the host |
linux_exec
A process replacing itself with a new program.
| Field | Type | Description |
|---|---|---|
| Subject | Lineage | The process performing the execution and the process that started it, as they are after the change took effect |
| Comm | text | The short name the new program will be known by, at most 16 characters. Chosen by the program, so not evidence of what ran |
| Executable | File | The canonical path of the executable image that actually ran |
| Invoked | File | What was asked for. For a script this is the script, where Executable is the interpreter |
| Interpreted | boolean | Whether Invoked and Executable differ because an interpreter handled the request |
| WorkingDirectory | File | The working directory, needed to make sense of any relative path in Args. Only Path and Type are populated |
| Root | File | The process’s root directory, which is how a process confined to a subtree becomes visible. Only Path and Type are populated |
| FileDescriptors | FileDescriptor array | The standard descriptors the program inherited |
| Tty | Tty | The terminal the process is attached to |
| Args | text array | Command-line arguments |
| Envs | text array | Environment variables |
| Argc | number | An upper bound on how many entries Args holds, not a guarantee |
| ArgvEnvpCopied | number | Bytes of arguments and environment captured. Zero when capture failed outright |
| ArgvEnvpTruncated | boolean | When set, the absence of an expected argument means nothing |
| Container | Container | The container the subject ran in. Absent when it ran directly on the host |
linux_exit
A process terminating.
Signal is meaningful only when ExitFromSignal is set, and ExitStatus only when it is not.
ExitCode is retained so nothing is lost, but it cannot be interpreted without ExitFromSignal; read the decoded fields instead.
| Field | Type | Description |
|---|---|---|
| Subject | Lineage | The terminating process, with the process that started it |
| ExitCode | number | The raw packed status value a waiting parent receives |
| ExitFromSignal | boolean | Whether the process was killed by a signal rather than ending on its own |
| Signal | number | The signal that killed the process |
| ExitStatus | number | The status the process chose to end with |
| CoreDumped | boolean | Whether a memory dump was started, not that one was completed or written anywhere |
| GroupDead | boolean | Whether a whole program ended, as opposed to one thread of a still-running program |
| Container | Container | The container the subject ran in. Absent when it ran directly on the host |
Common Nested Types
The following types are used throughout the Linux telemetry schema to represent shared data structures.
Credentials
The identity a process runs as. Two sets are carried on every process: the real set records who started it, the effective set is what permission checks are made against, so a program that has changed identity is still attributable to whoever launched it.
| Field | Type | Description |
|---|---|---|
| UID | number | The real owner of the process, and who is able to signal it |
| GID | number | The real group of the process |
| SUID | number | Saved user ID, which a process that has dropped privilege can return to |
| SGID | number | Saved group ID, the group equivalent of SUID |
| EUID | number | The process’s privileges for most non-filesystem access |
| EGID | number | The group equivalent of EUID |
| FSUID | number | The identity used when accessing filesystem objects |
| FSGID | number | The group equivalent of FSUID |
| CapInheritable | number | Inheritable capability set, as a bitmask |
| CapPermitted | number | Permitted capability set, as a bitmask |
| CapEffective | number | Effective capability set, as a bitmask |
| CapBounding | number | Bounding capability set, as a bitmask |
| CapAmbient | number | Ambient capability set, as a bitmask |
| Securebits | number | The securebits flags in force for the process |
Namespaces
The isolated views of system resources a process sits in. Each value identifies one view: two processes sharing a value share that resource, and differing values are the clearest signal that a process is isolated from the host, whether by a container runtime, a sandbox, or a program that has isolated itself.
These are operating system namespaces and have nothing to do with the Kubernetes namespace on KubernetesPod.
| Field | Type | Description |
|---|---|---|
| UTS | number | Hostname and domain name |
| IPC | number | Shared memory, semaphores and message queues |
| Mnt | number | Which filesystems are mounted, and where |
| PID | number | Which other processes are visible, and under what numbers |
| PIDForChildren | number | The view processes started from here will be placed in. Differs from PID only between requesting a new view and starting the first child |
| Net | number | Network interfaces, addresses, routes and ports |
| Time | number | The system clock offsets a process observes |
| TimeForChildren | number | Same requester-versus-children distinction as PIDForChildren |
| Cgroup | number | How much of the resource-control hierarchy is visible from here |
| User | number | How user and group identities map to those on the host, which is how an unprivileged user can appear as an administrator inside a container |
| CgroupID | number | The specific resource-control group the process belongs to, as opposed to Cgroup, which describes only what it can see. The primary key for attributing a process to a container |
Process
A running program, or one thread of it.
PID alone does not identify a process over time because process numbers are recycled; PID together with StartBoottime does, within one boot of the host.
Build identity on StartBoottime rather than StartTime, which is derived from the wall clock and inherits its error.
| Field | Type | Description |
|---|---|---|
| PID | number | Process ID as seen from the host |
| NSPID | number | Process ID as seen inside the process’s own PID namespace |
| TGID | number | Thread group ID, the ID of the program this thread belongs to |
| NSTGID | number | Thread group ID as seen inside the process’s own PID namespace |
| StartBoottime | number | Nanoseconds since boot at which the process started |
| StartTime | timestamp | Wall-clock time the process started |
| PGID | number | Process group ID |
| SID | number | Session ID |
| LoginUID | number | The user who logged in, surviving later changes of identity. 4294967295 when unset |
| SessionID | number | An identifier for that login. 4294967295 when unset |
| RealCredentials | Credentials | The identity the process was started with |
| Credentials | Credentials | The identity the process runs as now |
| Namespaces | Namespaces | The kernel namespaces the process sits in |
| Executable | File | The running program. Only Identity is populated here |
| NoNewPrivs | boolean | Whether the process is barred from gaining privileges through exec |
Lineage
A process together with the process that started it, captured at the same moment so the pair is internally consistent.
| Field | Type | Description |
|---|---|---|
| Task | Process | The process itself |
| Parent | Process | The process that started it |
Filesystem
The filesystem a file resides on. Where a file lives is often as telling as what it contains: an executable on an in-memory or layered filesystem did not come from the host’s own installation.
| Field | Type | Description |
|---|---|---|
| Type | text | Coarse filesystem type, e.g. FILESYSTEM_TYPE_OVERLAYFS, FILESYSTEM_TYPE_TMPFS |
| Magic | number | The exact filesystem magic value the kernel reported, set even when Type is unknown |
FileIdentity
What distinguishes one file from another independently of the name it is reached by.
Two observations agreeing on Dev and Ino describe the same file even under different paths; agreeing on Size and Mtime as well means it has not changed in between.
| Field | Type | Description |
|---|---|---|
| Dev | number | Device ID |
| Ino | number | Inode number |
| Size | number | File size in bytes |
| Atime | timestamp | Last access time |
| Mtime | timestamp | Last modification time |
| Ctime | timestamp | Last status change time |
Digest
A measurement of a file’s contents, which is what allows the same binary to be recognised wherever it appears and however it is named.
| Field | Type | Description |
|---|---|---|
| Algorithm | text | Digest algorithm, e.g. HASH_ALGORITHM_SHA256 |
| Value | text | Hex-encoded digest value |
| Valid | boolean | False when no measurement was available, in which case the other fields are meaningless |
File
Everything known about a single file. Any observation populates the subset it actually has, so an absent field means “not observed”, never “observed to be empty”.
| Field | Type | Description |
|---|---|---|
| Path | text | File path |
| Identity | FileIdentity | Device, inode, size and timestamps |
| Type | text | The kind of file, e.g. FILE_TYPE_REGULAR |
| Filesystem | Filesystem | The filesystem the file resides on |
| Digest | Digest | Measurement of the file’s contents |
| Deleted | boolean | Whether the file had already been removed when it was observed. Null when the file itself was not inspected |
| PathTruncated | boolean | Whether Path ran out of room before it was complete. Null exactly where Path was not observed |
FileDescriptor
A numbered channel a program inherited when it started. Only 0, 1 and 2 are reported. A pipe or socket where a terminal is expected is a strong indication that a program’s output is being captured.
| Field | Type | Description |
|---|---|---|
| FD | number | File descriptor number |
| File | File | What the descriptor refers to |
Tty
The terminal a process is attached to.
| Field | Type | Description |
|---|---|---|
| Major | number | Major device number |
| Minor | number | Minor device number |
| Name | text | Terminal device name |
| Present | boolean | False for a service, which has no terminal; the other fields then carry nothing |
Image
The image a container was created from.
| Field | Type | Description |
|---|---|---|
| Reference | text | The image reference, which is mutable and reusable |
| Digest | text | The image digest, which is stable and always means one image |
WorkloadOwner
What ultimately created and owns a pod. A pod’s own name is generated and replaced every time it is rescheduled, so this is the durable identity to attribute activity to.
| Field | Type | Description |
|---|---|---|
| Kind | text | Controller kind, e.g. Deployment. Clusters routinely add their own kinds |
| Name | text | Controller name |
KubernetesPod
Where a container sits within an orchestrator, populated only when the host is managed by one.
Namespace here is a Kubernetes namespace, a tenancy boundary within a cluster, which is a wholly different concept to the kernel Namespaces on a process.
Nothing relates the two.
| Field | Type | Description |
|---|---|---|
| Name | text | Pod name, regenerated whenever the pod is rescheduled |
| Namespace | text | Kubernetes namespace the pod runs in |
| UID | text | Pod UID |
| ContainerName | text | Name of the container within the pod |
| Owner | WorkloadOwner | The controller that owns the pod |
| ServiceAccount | text | The identity the pod’s processes present to the cluster |
Container
The container an event occurred inside.
CgroupPath is observed directly and is present whenever the activity happened inside any resource-control group.
Everything below it is resolved against the local container runtime and is absent when the runtime is unknown or unreachable, or when the activity did not happen inside a container at all.
| Field | Type | Description |
|---|---|---|
| CgroupPath | text | The cgroup path the activity happened in |
| Runtime | text | The container runtime, e.g. CONTAINER_RUNTIME_DOCKER |
| ID | text | Container ID |
| Name | text | Container name |
| Image | Image | The image the container was created from |
| Labels | map(text, text) | Labels attached at creation, carried whole |
| Pod | KubernetesPod | Orchestrator attribution, when the host is managed by one |