Skip to content
Coritan Docs

Logs and metrics

Read and follow a deployment's logs, forward them to your own service with a drain, and watch its requests, errors, latency and alerts.

View as Markdown

What your app prints goes to its logs, which you can search, follow live and forward to a service of your own. The deployment's metrics count its requests, errors, latency and bandwidth for every hour, and alerts tell you by email when a release fails or errors climb. The Logs and Metrics tabs hold them for a web service or a hybrid site, and a static site has the Metrics tab. A game server's or a database's output is in its console instead (Use the console).

  • Logs are kept for as long as your plan says: a day on Free, 7 days on Pro, 30 days on Business and 90 days on Enterprise (Pricing).
  • Log drains are part of the Pro, Business and Enterprise plans.

Open the deployment and select the Logs tab. The newest lines are at the bottom, each with its time, the instance and process that printed it, and the location. You can:

  • search for lines that hold a word, ignoring case;
  • narrow the lines to one instance or one process, such as web or worker;
  • go back to a time, such as two hours ago, and page through older lines;
  • follow new lines live as the instances print them.

Lines are collected from the instances every minute, so a line's time is when it was collected, within a minute of when it was printed. When an instance printed faster than we could collect, a line is marked as coming after a gap, because lines may be missing just before it. An instance that stops is read once more, so its last words are kept.

A live tail shows each instance's recent lines, then follows new ones for up to 15 minutes, including instances that a new release starts meanwhile. You can have up to 5 live tails open at once. From a terminal, coritan logs -f does the same (The Coritan CLI).

A drain sends the deployment's lines to a service of your own as they are collected, such as a log platform or your own server:

HTTP
Each batch is a POST of newline-delimited JSON to an https:// address. Each request is signed, so your service can check it came from us (Check a drain's signature).
Syslog
RFC 5424 messages over TLS to an address such as syslog+tls://logs.example.com:6514.

A drain can take only some processes, or only production or previews. It starts with the newest line collected when you create it, not the history. Delivery is at least once, so a batch that failed can arrive twice: remove duplicates by each line's id. Lines more than an hour old when a drain reaches them are skipped. A drain that fails every minute for an hour is turned off, and says why. Send a test line at any time to check it.

Your plan sets how many drains your account can have, counted across all its deployments, and a deployment can have up to 10.

An HTTP drain has a secret, which we generate unless you give one of 16 to 200 characters, and which is shown only once. Each request carries X-Coritan-Signature: t=<unix time>,v1=<signature>, where the signature is the HMAC SHA-256 of the time, a full stop and the raw body, keyed with the secret:

Python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    parts = dict(item.split("=", 1) for item in header.split(","))
    t = int(parts["t"])
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return abs(time.time() - t) <= tolerance and hmac.compare_digest(expected, parts["v1"])

Each line is an object with id, ts, deployment, deployment_name, instance, process, location, release, environment, message and gap. A test line also has "test": true.

The Metrics tab shows the last 24 hours, 7 days or 30 days, hour by hour: requests, how many were blocked by the firewall, answers by status (2xx, 3xx, 4xx, 5xx), bandwidth in and out, and the average and slowest latency. It also shows each running instance's processor and memory use now and over the last hour, day or week, kept as long as your plan keeps logs. You can look at one address at a time, such as a preview's.

Recent requests are sampled at every location and kept for 3 days: for each address, every request up to 5 a second, then one in a hundred, and every 5xx answer. Filter them by address, answer or path to find the path behind a burst of errors.

Page views and visitors are counted for the pages that load the Coritan tracking script, over 7, 30 or 90 days. Requests count everything; page views count only people who loaded a page with the script.

We email the deployment's owner, or an organization's owner, when:

  • a production release fails;
  • errors climb: in one hour, at least 100 requests of which 10% or more were 5xx answers;
  • visitors kept waking a sleeping deployment: 25 requests or more in an hour while it was asleep (Sleep when idle).

Alert emails follow your Usage alerts preference (Notifications). An organization's webhooks get the same alerts as events.

The Logs tab shows what the instances printed, and a drain's last delivery says when lines last reached your service.

The logs are empty
Lines are collected every minute, so a new instance's first lines take up to a minute to appear. A static site has no instances and no logs.
A drain turned itself off
It failed for an hour. Its last error says why, such as a refused connection or a 401. Fix the address or the secret, then turn it on again, which starts it from the newest line.
too_many_streams
You have 5 live tails open. Close one, or wait for one to end.
The metrics for the current hour are empty
Each hour fills in after it ends.

The routes are under /api/v1/client/deployments/{uuid} for your own deployment and /api/v1/orgs/{org_slug}/deployments/{uuid} for an organization's. Any member of an organization reads them; owners and admins change drains.

GET /logs answers the newest limit lines (100 unless you ask for up to 1,000), oldest first, with since, until, instance, process and q to narrow them. since and until take a time or how long ago, such as 2h. Pass the answer's next as before for older lines, and add format=ndjson for one line object a line:

Shell
curl "https://api.coritan.com/api/v1/client/deployments/$DEPLOYMENT/logs?since=2h&q=timeout" \
  -H "Authorization: Bearer $CORITAN_TOKEN"

GET /logs/stream follows new lines as Server-Sent Events, with tail (up to 200 lines to start with) and seconds (up to 900). GET /logs/instances lists the instances with lines kept, and their id for instance.

POST /drains with {"kind": "http", "url": "https://intake.example.com/v1"} creates a drain and answers its generated secret this once. PATCH /drains/{id} changes it, POST /drains/{id}/test sends a test line, and DELETE /drains/{id} removes it.

GET /metrics?window=7d, GET /requests?status=5xx, GET /analytics?window=30d and GET /alerts answer what the Metrics tab shows.

API operations on this page

MethodPathWhat it does
GET/api/v1/client/deployments/{deployment_uuid}/logsGet logs
GET/api/v1/client/deployments/{deployment_uuid}/logs/instancesGet log instances
GET/api/v1/client/deployments/{deployment_uuid}/logs/streamStream logs
GET/api/v1/client/deployments/{deployment_uuid}/drainsList drains
POST/api/v1/client/deployments/{deployment_uuid}/drainsA drain that forwards the lines collected from now on
PATCH/api/v1/client/deployments/{deployment_uuid}/drains/{drain_id}Update drain
DELETE/api/v1/client/deployments/{deployment_uuid}/drains/{drain_id}Remove the drain; nothing more is sent to it
POST/api/v1/client/deployments/{deployment_uuid}/drains/{drain_id}/testTest drain
GET/api/v1/client/deployments/{deployment_uuid}/requestsGet requests
GET/api/v1/client/deployments/{deployment_uuid}/metricsGet metrics
GET/api/v1/client/deployments/{deployment_uuid}/analyticsGet analytics
GET/api/v1/client/deployments/{deployment_uuid}/alertsGet alerts
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/logsGet logs
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/logs/instancesGet log instances
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/logs/streamStream logs
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/drainsList drains
POST/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/drainsA drain that forwards the lines collected from now on
PATCH/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/drains/{drain_id}Update drain
DELETE/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/drains/{drain_id}Remove the drain; nothing more is sent to it
POST/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/drains/{drain_id}/testTest drain
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/requestsGet requests
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/metricsGet metrics
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/analyticsGet analytics
GET/api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/alertsGet alerts