Ship logs to Datadog
Use this guide to stream your Audit Logs to Datadog Log Management.
Step 1: Create a Datadog API key
In Datadog, go to Organization Settings → API Keys and create an API key
with log ingestion permission for Firezone to use. Also note your Datadog
site. It's shown under Organization Settings, and it's the domain you use
to access Datadog, for example datadoghq.com, us5.datadoghq.com, or
datadoghq.eu.
Step 2: Create the Log Sink in Firezone
In the admin portal, go to SettingsLog Sinks, click Add, and select Datadog. Configure the sink:
| Field | Description |
|---|---|
| Name | A name to identify this log sink. |
| Site | Your Datadog site: US1, US3, US5, EU1, AP1, AP2, or US1-FED. |
| API Key | A Datadog API key with log ingestion permission. |
| Tags | Optional. Comma-separated tags added to every event, such as env:prod,team:secops. A stream:<stream> tag is always included. |
Tags must start with a letter, may contain letters, digits, _, -, :,
., and /, and are limited to 200 characters each.
Then choose which Log streams to deliver, all four of which are enabled by default, and optionally check Deliver existing logs to backfill logs recorded before the sink was created.
Deliver existing logs can only be selected when you create the sink. It can't be turned on later for an existing sink.
Click Create. Deliveries begin within about a minute.
Delivery format
Firezone POSTs JSON arrays to https://http-intake.logs.<site>/api/v2/logs.
Each event sets ddsource to firezone, so you can filter Firezone events in
Log Explorer with source:firezone, and carries a stream:<stream> tag plus
any tags you configured. The full event is under the firezone attribute,
and timestamp is epoch milliseconds.
{
"ddsource": "firezone",
"ddtags": "stream:change,env:prod,team:secops",
"service": "firezone",
"timestamp": 1784021191114,
"message": "firezone change c0654d20aa1b4a0000000002",
"firezone": {
"type": "change",
"log_id": "c0654d20aa1b4a0000000002",
"timestamp": "2026-07-14T09:26:31.114213Z",
"object": "policies",
"operation": "update",
"before": { "id": "0a83588e-…", "description": "Engineering → GitLab" },
"after": {
"id": "0a83588e-…",
"description": "Engineering → GitLab (MFA required)"
},
"subject": {
"actor_id": "e2f6a9c4-…",
"actor_name": "Jamie Admin",
"actor_email": "jamie@company.com",
"actor_type": "account_admin_user",
"auth_provider_id": "9d0c2f4e-…",
"ip": "203.0.113.44",
"ip_region": "US",
"ip_city": "San Francisco",
"ip_lat": 37.7749,
"ip_lon": -122.4194,
"user_agent": "Mozilla/5.0 …"
}
}
}
{
"ddsource": "firezone",
"ddtags": "stream:session,env:prod,team:secops",
"service": "firezone",
"timestamp": 1784021191114,
"message": "firezone session 53f2c8a91b7e4d20a6c19e04",
"firezone": {
"type": "session",
"log_id": "53f2c8a91b7e4d20a6c19e04",
"timestamp": "2026-07-14T09:26:31.114213Z",
"context": "client",
"subject": {
"actor_id": "7a1d9e3c-…",
"actor_name": "Riley Engineer",
"actor_email": "riley@company.com",
"actor_type": "account_user",
"auth_provider_id": "9d0c2f4e-…",
"device_id": "2b4d6f8a-…",
"token_id": "c4e6a8b0-…",
"ip": "203.0.113.44",
"ip_region": "US",
"ip_city": "San Francisco",
"ip_lat": 37.7749,
"ip_lon": -122.4194,
"user_agent": "Firezone/1.4.0 (macOS 15.5; arm64)"
}
}
}
{
"ddsource": "firezone",
"ddtags": "stream:api_request,env:prod,team:secops",
"service": "firezone",
"timestamp": 1784021191114,
"message": "firezone api_request a7b3e91c4d208f5a6e1b2c3d",
"firezone": {
"type": "api_request",
"log_id": "a7b3e91c4d208f5a6e1b2c3d",
"timestamp": "2026-07-14T09:26:31.114213Z",
"actor_id": "b8e0c2a4-…",
"api_token_id": "d0f2a4c6-…",
"method": "GET",
"path": "/policies",
"content_length": 0,
"request_id": "F8nMlbf6MUyJZUUABBzB9-yT",
"user_agent": "terraform-provider-firezone/0.4.1",
"ip": "203.0.113.44",
"ip_region": "US",
"ip_city": "San Francisco",
"ip_lat": 37.7749,
"ip_lon": -122.4194
}
}
Each flow is delivered as two events sharing its log_id. The start event
is suffixed with -s and carries no counters, while the end event is
suffixed with -e and carries the final totals:
{
"ddsource": "firezone",
"ddtags": "stream:flow,env:prod,team:secops",
"service": "firezone",
"timestamp": 1784021161000,
"message": "firezone flow f4e8a2c61b09d735e2a48b17-e",
"firezone": {
"type": "flow",
"log_id": "f4e8a2c61b09d735e2a48b17-e",
"timestamp": "2026-07-14T09:26:01.000000Z",
"flow_start": "2026-07-14T09:25:31.000000Z",
"flow_end": "2026-07-14T09:26:01.000000Z",
"last_packet": "2026-07-14T09:26:01.000000Z",
"device_id": "2b4d6f8a-…",
"role": "initiator",
"policy_authorization_id": "6c8e0a2b-…",
"policy_id": "0a83588e-…",
"resource_id": "5c8f6f6e-…",
"resource_name": "GitLab",
"resource_address": "gitlab.company.com",
"actor_id": "7a1d9e3c-…",
"actor_email": "riley@company.com",
"actor_name": "Riley Engineer",
"client_version": "1.4.0",
"device_os_name": "iOS",
"device_os_version": "17.4",
"protocol": "tcp",
"inner_src_ip": "100.64.0.1",
"inner_src_port": 54321,
"inner_dst_ip": "10.0.0.5",
"inner_dst_port": 443,
"outer_src_ip": "203.0.113.10",
"outer_src_port": 51820,
"outer_dst_ip": "198.51.100.5",
"outer_dst_port": 51820,
"domain": "gitlab.company.com",
"rx_packets": 100,
"tx_packets": 80,
"rx_bytes": 102400,
"tx_bytes": 20480
}
}
How Firezone responds to HTTP status codes
| Response | Behavior |
|---|---|
202 | The batch is accepted and delivery advances. |
429, 5xx | Retried every minute. If failures persist for 24 hours, the sink is disabled and account admins are emailed. |
413 | The batch is split in half and retried to isolate an oversized event. |
Other 4xx | Treated as a configuration error, for example 403 for an invalid API key: the sink is disabled immediately. |
Duplicates and redelivery
Firezone guarantees at-least-once delivery, retrying any batch that isn't
acknowledged rather than risk losing data, so Datadog can occasionally
receive the same event twice. When it does, deduplicate on
@firezone.log_id: flow start and end events are already suffixed with -s
and -e, which makes the log_id a unique key across all streams.
Recovering a failed sink
A sink showing Warning is retrying automatically, so unless the failures continue there's nothing you need to do. A sink showing Error has stopped delivering and needs attention: fix the cause , commonly a revoked API key or the wrong site, then open the sink, click Edit, and click Save to re-enable it. Delivery picks up right where it left off, from the last acknowledged entry, and Deliver Now triggers a delivery immediately if you don't want to wait for the next cycle.
Deleting the sink deletes its delivery state along with it, so re-creating it starts fresh: the new sink delivers logs recorded from its creation onward, plus a full backfill if Deliver existing logs is selected, which re-sends events Datadog may already have.
Need help? See all support options.