Skip to content
New storyWe built Skald to count visitors. It caught an AI-key thief.
SkaldEvery visit, truly told.

set-up · fastly · json logging

Fastly log analytics, from a JSON endpoint

Fastly log analytics needs Fastly's own log, because a page served from Fastly's cache never reaches your server. Fastly has no fixed format, so you paste one line that Skald reads. Read the limits first: today those days are withheld.

Fastly log analytics is counting the requests Fastly answered for your site, cache hits included, from a logging endpoint that writes one JSON object per request. Skald reads it with the log format fastly_json.

30-day free trial · no card · we set it up within one working day · free to self-host

fastly json log · sample · shortened4 lines
  1. 09:14:02 {"client_ip":"203.0.113.24","url":"/pricing/","response_status":200,"request_user_agent":"GPTBot/1.2"}AI · training
  2. 09:14:04 {"client_ip":"198.51.100.23","url":"/docs/","request_referer":"https://chatgpt.com/"}people · from ChatGPT
  3. 09:14:06 {"client_ip":"203.0.113.66","url":"/blog/","request_user_agent":"Googlebot/2.1"}search
  4. 09:14:09 {"client_ip":"192.0.2.91","url":"/wp-login.php","response_status":404}bots · probe

Sample lines, with most fields left out. Fastly writes one JSON object per request.

[01] read the cdn's log

Why Fastly's log, not your origin server's

A page in Fastly's cache never reaches your server, so your server's access log never sees that request. Fastly's own log sees every one, cache hits included.

Server log analytics then works as for any log: every line sorted into people, AI assistants, search engines, bots and scanners, and your own traffic. Read Fastly's log only, never your server's as well: a cache miss is in both, and would be counted twice.

Read this first: what it does not do yet

  • Days are withheld today. Every Skald figure is counted twice, the second time by an independent audit with its own reader. That reader does not read Fastly lines yet, so the two counts cannot agree, and the daily run withholds those days rather than publish figures nobody checked.
  • The one command on the server behind Fastly works, and its days are checked, but it misses every page Fastly answers from its cache.
  • Fastly writes a file each period, an hour by default, so the day's last lines arrive late. Run the daily report late enough for them.
  • A country only when you log it, as a two-letter code. Skald never guesses a code from a country's name.

[02] the log format

The Fastly JSON log format Skald reads

Fastly has no fixed log format: you write it in the logging endpoint. Leave the endpoint's log line format at Blank, so each line is the JSON object alone, and paste this into its Log format field, as one line.

fastly · logging endpoint · log format
{"timestamp":"%{strftime(\{"%Y-%m-%dT%H:%M:%S%z"\}, time.start)}V","client_ip":"%{req.http.Fastly-Client-IP}V","geo_country":"%{client.geo.country_code}V","host":"%{if(req.http.Fastly-Orig-Host, req.http.Fastly-Orig-Host, req.http.Host)}V","url":"%{json.escape(req.url)}V","request_method":"%{json.escape(req.method)}V","request_referer":"%{json.escape(req.http.referer)}V","request_user_agent":"%{json.escape(req.http.User-Agent)}V","response_state":"%{json.escape(fastly_info.state)}V","response_status":%{resp.status}V,"response_body_size":%{resp.body_bytes_written}V,"time_elapsed":%{time.elapsed.usec}V}
  1. Fastly's own example

    This is the JSON format from Fastly's S3 endpoint guide, with two changes.

  2. A country code

    geo_country logs client.geo.country_code, two letters, instead of the country's name.

  3. The time it took

    time_elapsed is added, in microseconds. Logging from your own VCL? Emit the same object, one per line.

[03] the endpoint

Amazon S3 or SFTP: where Fastly writes the log

Skald reads one log and its rotations. Fastly can put its files in a bucket for Skald's server to copy, or write them straight to that server.

tap one

A bucket, then a copy every 15 minutes

Create an Amazon S3 logging endpoint with the format above. On Skald's server, a short script run from cron every 15 minutes syncs the bucket and appends each new file, in name order, to one log. logrotate rotates that log daily.

config.yml · skald
logs:
  dir: /var/log/cdn
  base: access.log
  format: auto        # or fastly_json
FieldAlso accepted
timestamptime; ISO 8601, Unix seconds, ms, µs or ns
urlrequest_url, or path plus query
request_methodmethod
response_statusstatus, resp_status
request_refererreferer
request_user_agentuser_agent
response_body_sizeresponse_bytes, bytes
geo_countrycountry_code, two letters
time_elapsed (µs)elapsed_ms, time_elapsed_ms

[04] already logging?

A Fastly JSON format you already have may work

Skald accepts the common other names for each field. Two are required: a timestamp and a URL. A line without them is counted as unreadable, never guessed.

Skald tells a Fastly line from a Caddy one, which has a request object, and from a Cloudflare one, which has ClientRequestURI, by its keys. With the format auto, a log that mixes them with nginx lines still reads, for the day you move a site behind a CDN.

[05] what you get

What Skald can show from a Fastly log

Once a day's figures pass both counts, the same dashboard as any site: AI crawlers checked against their owners' addresses, live fetches, people and where they came from, scanners and your own traffic, apart.

Until the audit reads Fastly lines, those days stay withheld. If you need checked figures now, read the server behind Fastly with the one command, and know its figures leave out the cached pages.

Skald crawl health with sample data: sitemap pages beside what Google, Bing and AI crawlers fetched
Sample data. Crawl health, as any site with a checked log shows it.

questions

Fastly log analytics FAQ

Straight answers, including what Skald does not do.

Can Skald read Fastly logs?

Yes. Skald reads a Fastly logging endpoint that writes one JSON object per request, with the log format fastly_json. It also accepts the common other names for the same fields, so a JSON format you already have may work as it is.

Why are my Fastly days withheld?

Every Skald figure is counted twice, the second time by an independent audit with its own reader. Today that reader does not read Fastly lines, so the two counts cannot agree, and the daily run withholds those days rather than publish figures nobody checked.

Which Fastly log format does Skald need?

Fastly's own example JSON format with two changes: geo_country logs the two-letter country code instead of the country name, and time_elapsed is added, in microseconds. Paste the line from this page into the endpoint's Log format field, with the line format left at Blank.

Should I use S3 or SFTP for the Fastly endpoint?

Either works. With S3, a short script on Skald's server copies the bucket and appends new files to one log. With SFTP, the endpoint writes straight to that server's folder, so no bucket and no copy step are needed.

Can I read my origin server's log instead?

You can, with the one command on the server behind Fastly, but pages Fastly answers from its cache never reach that log, so its figures are too low. Never read both for one site: a cache miss is in both and would be counted twice.

$ tail -f access.log | skald

See what AI does with your site. Free for 30 days.

No card. We set up hosted Skald for you within one working day, or you self-host it free. Every line of your log, sorted and added up.

Start free trial Live demo