# Logs and metrics

> Read your project's deploy and build log, follow it live, and see its traffic, failures and latency in the console or over the API.

Source: https://docs.fortly.com/deploy/logs

Everything about what your project is doing is in one place in the console: open the project and choose **Observability**. It has three tabs: **Overview** for traffic and latency, **Logs** for what the platform and your builds have written, and **Activity** for the history of changes to the project. Each one is a view over an API route you can call yourself.

## Logs

The log is an ordered list of events. Each event has a sequence number (`seq`), a time (`ts`, milliseconds since the epoch), a `source`, a `stream` (`out` or `err`) and its `text`.

| Source | Written by |
| --- | --- |
| `system` | Fortly, narrating what it did to your project: a deploy arriving, what it found, each step, and the outcome. |
| `build` | Your install and build, during a deploy that needs building. |
| `app` | A project running as its own process. |

> **Note:**
>
> Releases served as Workers — server-rendered frameworks and Node servers — do not write what they print to this log. For those, the deploy and build history is here, and how the app is answering is in [Metrics](#metrics).

### Read logs in the console

The **Logs** tab streams new events as they arrive and keeps the view pinned to the newest line. Scroll up to read and it stops following without stopping the stream; it tells you how much arrived while you were reading.

- **Search output** filters by text, across every line of a multi-line entry.
- **Level** filters on the level a line declares about itself — errors, warnings, info, debug — or on `stderr`. Fortly only marks a level when the line contains one near its start; it does not guess.
- **Source** filters to `system`, `build` or `app`.
- **Pause** holds new lines until you resume, **Load older** pages back through history, and the copy and download buttons take the lines currently shown.

Indented lines that follow a line on the same stream, and Python tracebacks, are grouped into one entry you can expand.

### Read a deploy in the log

A deploy reads top to bottom as an account of what happened. A build's own output arrives in one piece when the build finishes — its last 200 lines — between `Building with the build service` and `Built`:

```text
Deploying an upload · 1.2 MB
Unpacked 214 files · 3.4 MB
Node.js · Next.js · npm
Building with the build service (small)
fortly-build: manager=npm adapter=next
...
Built · 87 files · 5.1 MB
Uploading runtime bundle...
Validating deployment...
Deployment ready.
```

A failed deploy ends with an `err` line under `system`, such as `Deploy failed. The release that was already live is still live.` The reason is also kept on the release itself, in its `failure` field. [How builds work](https://docs.fortly.com/deploy/builds#when-a-build-fails) lists the common failures.

Environment values 8 characters or longer are replaced with `[redacted]` wherever they would appear.

### Read logs over the API

```bash
curl "https://api.fortly.com/projects/my-app-ada/logs?lines=100" \
  -H "Authorization: Bearer $FORTLY_TOKEN"
```

- `lines` (integer, optional) — How many events to return, newest last. Defaults to 200; at most 1,000.
- `before` (integer, optional) — Only events with a `seq` lower than this. Pass the `oldest` value from a previous reply to page backwards.

The reply has `events`, plus `oldest` and `newest` (the sequence numbers at each end) and `more` (whether there is older history to page back to).

To follow the log live, open the stream. It uses server-sent events, and each `log` event's id is its sequence number:

```bash
curl -N https://api.fortly.com/projects/my-app-ada/logs/stream \
  -H "Authorization: Bearer $FORTLY_TOKEN"
```

```text
event: gap
data: false

id: 1043
event: log
data: {"seq":1043,"ts":1760263200000,"source":"system","stream":"out","text":"Deployment ready."}
```

To resume after a dropped connection, send the last id you saw as `Last-Event-ID`, or as `?after=`. You receive what you missed, then the live feed. Fortly holds the most recent 2,000 events per project for this. If you were away longer than that, the stream starts with a `gap` event whose data is `true`: fetch history with `GET /logs` instead of assuming nothing happened. A `keep-alive` comment is sent every 20 seconds while nothing is happening.

> **Note:**
>
> Logs are for watching and debugging your project now, not for keeping. They are not a long-term archive.

### Read logs from an agent

An agent connected over [MCP](https://docs.fortly.com/agents/mcp) with the `logs:read` scope can call `query_logs` with a project name. It returns a page of recent lines, oldest first — 100 by default, at most 500 — and takes `before` to page back. It does not follow the log; call it again for newer lines.

## Metrics

The **Overview** tab shows how your project has been answering requests, and refreshes itself every 15 seconds.

| Panel | What it shows |
| --- | --- |
| **Traffic** | Requests over the last 15 minutes, hour, 24 hours or 7 days, split into `2xx–4xx` and `5xx`. Beside the chart: **Requests**, **Success rate** (answers that were not `5xx`), **Failed** (`5xx`, your project's fault) and **Refused** (`4xx`, the caller's). |
| **Latency** | **Median**, **95th percentile** and **Slowest** answer time. |
| **Routes** | Your busiest routes, each with its calls, failures and latency. |

A few things to know when you read them:

- **Failed and refused are kept apart.** A wall of `404`s is usually a broken link somewhere else, not your project being down.
- **Routes are grouped by shape.** `/users/1` and `/users/2` are counted as one route, because a segment that looks like an id is treated as one. Up to 120 routes are tracked per project; past that, new ones are counted together as `other`.
- **Percentiles are from a histogram**, so each reads as "at or under this". There is no average, because one very slow answer barely moves an average.
- **Windows up to 24 hours are counted since Fortly last restarted** the machine serving your project. The 7-day view is read from hourly records and survives restarts; hours from before those records began are missing rather than shown as zero.

[Scheduled runs](https://docs.fortly.com/deploy/schedules) reach your project through the same front door as visitors, so they are counted here too.

### Metrics over the API

```bash
curl "https://api.fortly.com/projects/my-app-ada/traffic?span=1h" \
  -H "Authorization: Bearer $FORTLY_TOKEN"
```

`span` is `15m`, `1h`, `24h` (the default) or `7d`; anything else is refused with `span is 15m, 1h, 24h or 7d, not 2h`. The reply has `step_s`, the width of each point in seconds, and `points`, each with `at`, `requests`, `failed` and `refused`.

`GET /health` summarises every project you can reach: `requests_24h`, `failed_24h`, `refused_24h`, `p50_ms`, `p95_ms` and `slowest_ms` for each, with `"since_restart": true` to remind you where the count began. `GET /projects/{name}/routes` returns the busiest routes with their own latency, and `limit`, the most routes tracked.

## Activity

The **Activity** tab is the history of changes to the project, newest first: projects created, releases deployed, environment values set, and domains added and verified. Each entry links to where the change was made. Things that leave no record — a removed environment value, a deleted project — do not appear.

`GET /activity` returns the same history for every project you can reach, as `events` with `at`, `kind` (`project.created`, `deploy`, `secret.set`, `domain.added` or `domain.verified`), `project` and `detail` (the release id, value name or hostname). It returns the 200 most recent.

## API routes

- `GET /projects/{name}/logs` — A page of recent log events; lines and before
- `GET /projects/{name}/logs/stream` — The log as server-sent events, resumable from a sequence number
- `GET /projects/{name}/traffic` — Requests over a span: 15m, 1h, 24h or 7d
- `GET /projects/{name}/routes` — The busiest routes, with calls, failures and latency
- `GET /health` — Traffic and latency for every project you can reach
- `GET /activity` — Recent changes across your projects

Use the project's full API name, such as `my-app-ada`, in these routes — see [Deploying your code](https://docs.fortly.com/deploy#deploy-an-archive).

## Related

- [How builds work](https://docs.fortly.com/deploy/builds): What each build step writes, and what a failure means.
- [Releases and rollbacks](https://docs.fortly.com/deploy/releases): When the metrics turn bad after a deploy, put the previous release back.
- [Schedules](https://docs.fortly.com/deploy/schedules): Scheduled runs show up in your traffic like any other request.
