Skip to content

Latest commit

 

History

History
346 lines (277 loc) · 15.6 KB

File metadata and controls

346 lines (277 loc) · 15.6 KB
title Logging
sidebarTitle Overview
description Access raw request logs via API or dashboard with a 3 day log retention policy.

bunny.net provides raw request logs for all Pull Zones with Logging Enabled. Logs appear in near real-time and they're retained for 3 days.

For longer retention, use Permanent Log Storage to automatically archive logs to Edge Storage.

We expose two HTTP APIs for accessing logs:

  • Logging API v2 - recommended. Structured JSON, rich filtering, pagination, and per-field search.
  • Logging API v1 - legacy. Streams a raw pipe-delimited file for a given day; preserved for existing integrations.

Privacy & GDPR

IP addresses are anonymized by default. To enable full IP logging, sign the Data Processing Agreement (DPA) in your account settings, then disable anonymization in your Pull Zone logging settings.

When anonymization is enabled, anonymized IPs are returned by the API in one of two forms depending on your Pull Zone setting:

  • Remove last octet - IPv4 is masked to a /24 (e.g. 163.172.53.0); IPv6 is masked to a /64 (e.g. 2001:7d0:700d:db04::).
  • Drop all - IPv4 becomes 0.0.0.0 and IPv6 becomes ::.

Anonymization applies on read at the API boundary. Filtering by remoteIp adapts to the same mask width, so the filter can never reveal information beyond what the response shows.

Logging API v2

GET https://logging.bunnycdn.com/v2/pullzones/{pullZoneId}/logs

Authenticate with your account API key or a bearer JWT:

AccessKey: your-api-key
# or
Authorization: Bearer <jwt>

Logs are retained for the past 3 days. Both from and the range to - from must fall within that window.

Example

curl -H "AccessKey: your-api-key" \
     "https://logging.bunnycdn.com/v2/pullzones/1337/logs?from=2026-05-08T00:00:00Z&to=2026-05-09T00:00:00Z&status=4xx,5xx&limit=50"

Query parameters

Parameter Type Description
from ISO 8601 UTC Inclusive start of the time range. Defaults to to - 24h. Must fall within the 3-day retention window.
to ISO 8601 UTC Exclusive end of the time range. Defaults to now.
status comma list HTTP status filter. Each entry is either an exact code (200, 404) or a class (2xx, 5xx). Multiple entries are OR-ed.
cacheStatus comma list Cache statuses to match exactly (e.g. HIT,MISS,EXPIRED).
country comma list ISO 3166 alpha-2 country codes (e.g. EE,DE).
edgeLocation string Edge location / server zone, exact match.
remoteIp IPv4 or IPv6 Filter by client IP. The match width adapts to the zone's anonymization setting: exact when anonymization is disabled, /24 (IPv4) or /64 (IPv6) under last-octet anonymization, and ignored under full anonymization.
urlContains string Case-insensitive substring match against host + path.
userAgentContains string Case-insensitive substring match against the User-Agent header.
refererContains string Case-insensitive substring match against the Referer header.
search space-separated Free-text token search. A row matches if ANY token appears in ANY searched column (cache status, request ID, edge location, host, path, user agent, referer, and content range for extended-logging zones). Max 16 tokens of up to 128 characters each.
includeOriginShield boolean Include origin-shield (edge → shield) requests. Defaults to false.
limit integer Maximum entries per page. Defaults to 100, capped at 10000.
offset integer Number of entries to skip. Defaults to 0.
order string Sort by timestamp: asc or desc (default).
requestId UUID Exact request ID lookup. Accepts standard UUID format (with or without hyphens).
Country code, the encrypted-at-rest authorization header, and the raw client IP are not matched by the free-text `search` parameter. Use `country`, `remoteIp`, and the dedicated header filters for those.

Response

200 OK returns a JSON envelope with the page of entries, pagination state, and an echoed query summary:

{
  "data": [
    {
      "timestamp": "2026-05-08T14:32:11.265Z",
      "pullZoneId": 1337,
      "requestId": "648fd832dbc1b102134949e15a9fdb2d",
      "cacheStatus": "MISS",
      "statusCode": 404,
      "bytesSent": 1095,
      "remoteIp": "163.172.53.0",
      "countryCode": "FI",
      "edgeLocation": "WA",
      "scheme": "https",
      "host": "example.b-cdn.net",
      "path": "/video.mp4",
      "url": "https://example.b-cdn.net/video.mp4",
      "userAgent": "Mozilla/5.0 ...",
      "referer": null,
      "ja4Fingerprint": "t13d1513h2_8daaf6152771_1eb89897b454",
      "asn": 15169,
      "asnOrganization": "Google LLC"
    }
  ],
  "pagination": {
    "offset": 0,
    "limit": 100,
    "returned": 1,
    "hasMore": false
  },
  "query": {
    "pullZoneId": 1337,
    "from": "2026-05-08T00:00:00Z",
    "to": "2026-05-09T00:00:00Z",
    "order": "desc"
  }
}

Log entry fields

Field Type Description
timestamp ISO 8601 UTC Time the request was received at the edge (millisecond precision).
pullZoneId integer Pull Zone identifier the request was served from.
requestId string 32-character hex unique request identifier.
cacheStatus string Cache result (see cache status values below).
statusCode integer HTTP response status code.
bytesSent integer Total bytes sent in the response (headers + body).
remoteIp string | null Client IP, possibly anonymized; null when no IP was recorded.
countryCode string | null ISO 3166 alpha-2 country code derived from the client IP; null if unknown.
edgeLocation string POP code that served the request.
scheme string http or https.
host string Request Host header.
path string Request URI path (with query string if present).
url string Fully composed URL: {scheme}://{host}{path}.
userAgent string | null User-Agent header; null when absent.
referer string | null Referer header; null when absent.
ja4Fingerprint string | null JA4 TLS client fingerprint; null when absent.
asn integer | null Autonomous System Number derived from the client IP; null if unknown.
asnOrganization string | null Organization that owns the AS; null if unknown.

Extended logging fields

When extended logging is enabled for the Pull Zone (contact support), entries also include:

Field Type Description
bodyBytesSent integer Response body bytes, excluding headers.
contentRange string | null HTTP Content-Range header.
authorizationHeader string | null Decrypted Authorization header value (encrypted at rest).

Null fields are omitted from the JSON response.

Cache status values

Value Meaning
HIT Response served directly from cache.
MISS Response not in cache; fetched from origin.
BYPASS Cache was skipped (e.g. due to request headers, cookies, or configuration).
REVALIDATED Cached response was validated with origin (e.g. via ETag / Last-Modified) and reused.
STALE Stale cached response served (typically due to origin being unavailable or slow).
UPDATING Stale content served while a background cache update is in progress.
- No cache interaction (e.g. non-cacheable methods like POST).

Pagination

The response sets pagination.hasMore to true when more results are available beyond the current page. To fetch the next page, repeat the request with offset advanced by limit:

curl -H "AccessKey: your-api-key" \
     "https://logging.bunnycdn.com/v2/pullzones/1337/logs?from=...&to=...&limit=100&offset=100"

Error responses

Errors return a structured JSON envelope:

{
  "error": {
    "code": "invalid_request",
    "message": "One or more query parameters are invalid.",
    "details": [
      "Time range cannot exceed 3 days (log retention window).",
      "limit must be between 1 and 10000."
    ]
  }
}
HTTP status error.code Meaning
400 invalid_request One or more query parameters failed validation. See details.
401 unauthorized Neither Authorization nor AccessKey header was provided.
403 forbidden Credentials are invalid, or the Pull Zone is suspended/disabled.
404 logging_disabled Logging is not enabled for this Pull Zone.
429 rate_limited Per-Pull-Zone rate limit exceeded (30 requests / 10 seconds).
500 internal_error Unexpected server error.

Logging API v1 (Legacy)

The v1 API is preserved for existing integrations. New work should use [Logging API v2](#logging-api-v2), which returns structured JSON, supports rich filtering and pagination, and avoids the pipe-injection issues inherent to the v1 format.

Download raw log files from the logging API:

GET https://logging.bunnycdn.com/{MM}-{DD}-{YY}/{pull_zone_id}.log

Authenticate with your account API key:

AccessKey: your-api-key

Use gzip compression to reduce download size:

Accept-Encoding: gzip

Example:

curl -H "AccessKey: your-api-key" \
     -H "Accept-Encoding: gzip" \
     "https://logging.bunnycdn.com/03-07-26/1337.log"

Query parameters

Parameter Description
start Number of log lines to skip from the beginning
end End index of log lines to return
sort Sort order: asc or desc (default)
status Filter by status codes: 2, 3, 4, 5 (e.g. 2,3,4,5 (default) or 2)
search Filter log lines by string match
download Whether to return logs as a downloadable file (default: true)

Log format

Each request is stored as a pipe-separated line:

HIT|200|1507167062421|412|390|163.172.53.0|-|https://example.b-cdn.net/video.mp4|WA|Mozilla/5.0...|322b688bd63fb63f2babe9de30a5d262|DE
Field Description
Cache Status Cache result for the request. See cache status values.
Status Code HTTP response code
Timestamp UTC UNIX timestamp (milliseconds)
Bytes Sent Total bytes sent to client
Pull Zone ID ID of the Pull Zone
Remote IP Client IP (anonymized by default)
Referer Referer header value
URL Requested URL
Edge Location POP code that served the request
User Agent Client user agent
Request ID Unique request identifier
Country Code Two-letter ISO country code
Pipe (`|`) characters in user-controllable fields (Referer, URL, User-Agent, Content-Range, Authorization) are stripped from the v1 output to keep the delimiter unambiguous. If you need the original byte sequence, use v2.

Extended logging

Extended logging adds three additional fields (contact support to enable):

Field Description
Body Bytes Sent Response body bytes (excluding headers)
Range Header HTTP Range header value
Authorization Header Authorization header value (Encrypted at rest)

HTTP status codes

These codes apply to logged responses served by the CDN edge and are surfaced via both API versions.

2XX Success

Code Description Explanation
200 OK Request successful, content served
201 Created Request successful, new resource created
204 No Content Request processed, no content to return
206 Partial Content Partial GET request fulfilled (e.g., video range request)

3XX Redirection

Code Description Explanation
301 Moved Permanently URL permanently changed, use new location
302 Found URL temporarily moved
303 See Other Response available at different location
304 Not Modified Cached content still valid, no transfer needed

4XX Client Errors

Code Description Explanation
400 Bad Request Server could not understand the request
401 Unauthorized Authentication required
403 Forbidden Server refuses to fulfill request (hotlink protection, token auth)
404 Not Found File not found
405 Method Not Allowed Request method not supported
410 Gone Resource no longer available
429 Too Many Requests Rate limit exceeded
499 Client Closed Request Client terminated connection before response completed
A 499 status code appears in logs when a client closes the connection before the server finishes responding. This commonly occurs due to mobile network interruptions, ad blockers, or users navigating away. It's normal and doesn't indicate a server problem.

5XX Server Errors

Code Description Explanation
500 Internal Server Error Unexpected server error
502 Bad Gateway Invalid response from upstream server
503 Service Unavailable Server temporarily overloaded or under maintenance
504 Gateway Timeout Upstream server didn't respond in time
502 and 504 errors typically indicate the CDN edge nodes cannot reach your origin. Check if your origin firewall is blocking bunny.net IPs.