read_logs

Generated automatically from the published contract sources.

Build metadata: Registered in this build. Registration describes the default dispatcher in this build. It does not guarantee that a caller has the required credential or grant, that a tool is listed for that connection, or that the required service is configured.

A script calls this action over HTTPS at POST https://turnzero.ai/api/v1/actions/read_logs, with a bearer credential and the action's payload as the JSON body. It also accepts GET.

Contract description

Read an application's log records for one environment, within a time window (`since`, `until`) or the most recent `limit`. Choose the `source` first: `container` holds the process's standard output and standard error, `console.error` among them, and `app` holds only what the application writes through the logging package.

The `platform` source holds the platform's entries about the application, `router` the serving router's records, `egress` the outbound proxy's records, and `harness` the runtime harness's connection records. The value `all`, or an omitted source, reads every source the logging service stores, merged by time; console output is read under `container` alone.

The `container` source reads the named environment's compute, production where none is named. With no compute, it answers a failed first check's kept lines or refuses `never_deployed`. A container read naming `local` is refused: a local run has no console. For `container`, `since`, `limit`, `filter`, and `contains` apply; the answer carries `lines`, no `entries`. `contains` searches the newest 1,000 lines, ignoring case, and the `detail` names what it searched. A `level` or `field` is refused `invalid_request`: a console line carries neither. With `wait_seconds`, the read follows the console up to 40 seconds, answering once a matching line is written; give `since`.

Records arrive with a lag. An empty answer carries a `detail` saying why, and so does an answer whose window ends inside its source's lag, since its newest records may not have arrived yet. Where the `detail` says lines may still be in the ingestion, read again about a minute later. A `container` line from the version being replaced carries `[retiring]`.

The `filter` argument reads the outbound connections against the manifest: `declared` or `undeclared` hosts, as the manifest stands at the read. The rest is on the page /cloud/reference/actions/read-logs/, which `read_documentation` reads as `page` and the platform's origin serves.

More about this action

The sources `app`, `platform`, `router`, `egress`, and `harness` are the records the logging service stores in the environment's stream. The `platform` source is the platform's entries about the application, each scheduled run's outcome among them.

The `router` source is the serving router's records: one `legs_ended` record per invocation kind and outcome per minute with the count and the duration's sum and maximum. It also holds each `window_ended` request whole, each `upstream_ended` request whole, a request an application's process end cut. It holds one `source_refused` record per minute the per-source bound refused requests in, with the bound, the count refused, and the distinct sources refused.

An answered leg's `legs_ended` record also carries its `status_class`, `2xx` to `5xx`, so a 500 never folds into the row of a 200. Each 5xx answer is also kept whole, as an `answered_5xx` record with the path and no query, the status, the duration, and the serving version. At most twenty are kept per application and environment a minute, the rest counted on the fold.

The `egress` source is the outbound proxy's records: one `egress_establishments` record per host, port, outcome, and declared flag per minute with the count, an observed undeclared host's refusal name and, where one exists, the remedy on it, and each `egress_refusal` whole. The `harness` source is the runtime harness's connection-observer records shipped from the application's own process under its own credential, not an attested platform record. It holds one `egress_establishments` record per host, port, and outcome per minute with the proxied mark and the count, and each failed `egress_establishment` whole.

The `container` source is the one console read: the process's standard output and standard error, where `console.log` and `console.error` lines and the harness's `window_ended`, `process_ended`, and `harness_refusal` lines land. It is the process's own console, not a stream. For an environment on the pod grain it is the pod's console through the cluster's API server, the previous container's log where the current one has restarted. It is empty once the pod has scaled to zero because the console lives as long as the pod. For a container placement it is the provider's console log store — where the window's `process_ended` and `harness_refusal` lines and the logging client's fallback lines land.

A `container` read acts on the named environment's compute — production where none is named. Where that environment names no compute, nothing is in flight, and its newest version failed its health check with no earlier version serving, it answers the lines that check kept, at most 40, with `failed_check`. Otherwise it is refused `never_deployed`, the detail naming the version in flight where a deploy or promote runs. Where nothing runs and the environment's latest version failed, the detail names that failed deploy or promote and, where recorded, its step and error. The failure stays in that version's outcome in `read_status`, the failed health check's last console lines among it where the check failed.

Every store source, `app`, `platform`, `router`, `egress`, `harness`, and the whole stream, answers `lines` and adds `entries`, the same records parsed, each with its `at`, `level`, `source`, `message`, and any `fields`. An unrecognized `source` value is ignored, the limit member's precedent.

A store source's entries land within a few seconds, from the logging client's interval flush, and the per-minute records under `router`, `egress`, and `harness` once their minute has ended. On the container grain, where the platform has the direct read enabled, a `container` read also reads each running replica's console directly, once, so where that direct read succeeds it answers the newest lines at once.

The `filter` argument reads the proxy's and the harness's per-minute establishment records and their whole refusals and failures within the page the read answered — the named source's, or every source's where none is named. The platform's own endpoints, the loopback targets, and the harness's proxied records are left out either way. The `filter` argument shows what to add to the manifest before enforcement. Where a `container` read carries `contains`, it runs over the lines that matched, among those searched, before the cut to the newest `limit`.

A `since` or `until` timestamp's calendar date must exist; hours are 00–23, minutes and seconds 00–59, and offset hours/minutes 00–23/00–59. Leap seconds and 24:00 are not accepted. Values normalize to UTC at millisecond precision.

With `wait_seconds` on a store source, the platform reads the store every two seconds and answers once a matching entry stands or this many seconds have passed since the call arrived, with `waited_ms`. An entry already in the window ends the wait at once, so give `since` to wait for entries written after a moment. The wait takes the application's one held place, so a concurrent held `read_status` or held act answers at once, and a wait that finds the place taken answers at once, its empty answer's `detail` leading with a sentence that the wait did not hold.

On a `container` read, `wait_seconds` follows the console instead: the console of each running replica, three at most, or of the newest pod. The answer comes once a line the call's filters admit is written at or after `since`, or at the earlier of `wait_seconds` and 40 seconds, with every line read and `waited_ms`. The wait needs the direct read enabled. It cannot hold where the place is taken, the platform's waits or follows are full, or the management API is near its limit. It then answers at once as an ordinary `container` read, its `detail` saying why. Where the limit comes during the wait, it answers with the lines read so far. A crashed process's earlier lines are read without the wait.

Access and action metadata

{
  "name": "read_logs",
  "resource": "environment",
  "tier": "observe",
  "clients": [
    "bearer",
    "browser_session"
  ],
  "summary": "The environment's log entries written through the logging service, filterable by time, level, message, field, and source — `source` selecting one of the stream's sources, `app` (only what the application writes through the logging package; standard output and standard error land under `container`), `platform` (the platform's entries about it, each scheduled run's outcome among them), `router` (the serving router's `legs_ended` records per invocation kind and outcome per minute, its `window_ended` requests whole, its `upstream_ended` requests whole, each a request an application's process end cut, and its `source_refused` records, one per minute the per-source bound refused requests in), `egress` (the tunnel seat's `egress_establishments` records per host and outcome per minute, an observed host's refusal name and remedy on them, and its refusals whole), or `harness` (the runtime harness's connection observer's `egress_establishments` records and its failed `egress_establishment` records, shipped from the application's own process), or `all` (every source the logging service stores; console output is read under `container` alone) — and `container` the one console read, the named environment's own compute (production where none is named; a pod's console read through the cluster's API server and living as long as the pod), where the process's standard output and standard error land, `console.log` and `console.error` lines among them, beside the `process_ended` and `harness_refusal` lines and the logging client's fallback lines; `filter` the declared-versus-observed reading, `declared` or `undeclared` against the manifest's egress member over the aggregated records with the platform endpoints and the loopback targets subtracted. An answered leg's `legs_ended` record carries its `status_class`, and each 5xx answer is kept whole as an `answered_5xx` record, under a per-minute cap. Store entries land within a few seconds, and on the container grain a `container` line reaches the log workspace up to about a minute after it is written. On the container grain, where the platform has the direct read enabled, the read also reads each running replica's console directly, once, and where that direct read succeeds it answers its newest lines at once. A `container` answer is ordered by each line's write time, and a line from the environment's recorded previous compute carries `[retiring]`. An empty answer, or one whose window ends inside that lag, carries a `detail` saying why. On the container grain, where the direct read is enabled, that `detail` also reports it. It names the time from which lines were read from the replica directly where any were kept, and says when lines may still be in the ingestion, naming a failed read's reason. On a `container` read, `contains` searches its newest 1,000 lines, and a `level` or `field` is refused `invalid_request`, a console line carrying neither.",
  "annotations": {
    "readOnlyHint": true,
    "destructiveHint": false,
    "openWorldHint": true,
    "idempotentHint": true
  }
}

MCP catalog entry

{
  "name": "read_logs",
  "tier": "observe",
  "scenario": "CHI-L0-09",
  "summary": "Read an application's log records for one environment, within a time window (`since`, `until`) or the most recent `limit`. Choose the `source` first: `container` holds the process's standard output and standard error, `console.error` among them, and `app` holds only what the application writes through the logging package.\n\nThe `platform` source holds the platform's entries about the application, `router` the serving router's records, `egress` the outbound proxy's records, and `harness` the runtime harness's connection records. The value `all`, or an omitted source, reads every source the logging service stores, merged by time; console output is read under `container` alone.\n\nThe `container` source reads the named environment's compute, production where none is named. With no compute, it answers a failed first check's kept lines or refuses `never_deployed`. A container read naming `local` is refused: a local run has no console. For `container`, `since`, `limit`, `filter`, and `contains` apply; the answer carries `lines`, no `entries`. `contains` searches the newest 1,000 lines, ignoring case, and the `detail` names what it searched. A `level` or `field` is refused `invalid_request`: a console line carries neither. With `wait_seconds`, the read follows the console up to 40 seconds, answering once a matching line is written; give `since`.\n\nRecords arrive with a lag. An empty answer carries a `detail` saying why, and so does an answer whose window ends inside its source's lag, since its newest records may not have arrived yet. Where the `detail` says lines may still be in the ingestion, read again about a minute later. A `container` line from the version being replaced carries `[retiring]`.\n\nThe `filter` argument reads the outbound connections against the manifest: `declared` or `undeclared` hosts, as the manifest stands at the read. The rest is on the page /cloud/reference/actions/read-logs/, which `read_documentation` reads as `page` and the platform's origin serves.",
  "owners": [
    "EGW-L0-17",
    "EGW-L0-15",
    "HST-L0-03",
    "PLD-L0-40",
    "SVC-L0-07",
    "SVC-L0-18",
    "HST-L0-01",
    "PLD-L0-62",
    "MAN-09"
  ]
}

request

JSON pointer Description and constraints
"" (root) Type: object
Required fields: ["application"]
/properties/application The application id, from `list_applications`.

Type: string
/properties/environment The stream to read: `development` or `production`, or `local` for the developer-machine stream. Omission reads production. A stream with no deploy in its history is refused `never_deployed`; `local` needs none. Where the environment names no compute, a `container` read answers the lines a failed first deploy's or first promote's health check kept, and is otherwise refused `never_deployed`. Naming `local`, it is refused `invalid_request`: a local run has no console.

Type: string
/properties/since Inclusive start of the time window. Use YYYY-MM-DD followed by T (or t), HH:mm, optional :ss, an optional decimal fraction of 1–9 digits after seconds, then Z (or z) or a signed HH:mm offset. Omission leaves this bound open, except on a `container` read of an environment that runs as a container, whose window then starts 24 hours before the read. A null, empty, wrongly typed, or malformed value is refused 400 invalid_request naming the member.

Type: string
/properties/limit How many entries at most, 1 to 1000; 100 where none is given.

Type: integer
Minimum: 1
Maximum: 1000
/properties/source Which records to read. `container` is the process's own console: its standard output and standard error, `console.log` and `console.error` among them. `app` is only what the application writes through the logging package. The `platform` source is the platform's entries about it, `router` the serving router's records, `egress` the outbound proxy's records, and `harness` the runtime harness's connection-observer records (the platform's code loaded into the application's process). The value `all`, or an omitted source, reads every source the logging service stores; console output is read under `container` alone. An unrecognized value is ignored.

Type: string
Allowed values: ["app","platform","router","egress","harness","container","all"]
/properties/filter Read only the outbound connections whose destination host the manifest's `egress` member declares (`declared`) or does not (`undeclared`), classified against the manifest as it stands at the read. With the `container` source the same classification runs over the console's lines.

Allowed values: ["declared","undeclared"]
/properties/until Inclusive end of the time window, in the form `since` states and refused as it is. Omission leaves this bound open. A `container` read ignores it.

Type: string
/properties/level The lowest level to include — `debug`, `info`, `warn`, or `error`; entries at that level and above are answered, and any other value is ignored. One of the four on a `container` read is refused `invalid_request`, since a console line carries no level.

Type: string
/properties/contains Only entries whose message contains this text, on a store source. On a `container` read, only the lines that contain it, ignoring case, as the answer gives each line. The read searches up to its newest 1,000 lines before the `limit` cut. For a trace's other lines, omit it, `limit` 1000.

Type: string
/properties/field The name of one structured field to match; give the value it must hold in `value`. A non-empty name on a `container` read is refused `invalid_request`, since a console line carries no structured field.

Type: string
/properties/value The scalar value the named field must equal, with its JSON type preserved. Omit value to match entries containing the field; explicit null matches a null field value.

Type: ["string","number","boolean","null"]
/properties/wait_seconds Optional. The seconds, 1 to 45, the answer is held while the read with this call's filters finds no entry: a store source is read every two seconds, and a `container` read follows the console, 40 seconds at most. Give `since`. A value outside 1 to 45 is refused `invalid_request`, its detail naming the bound.

Type: integer
Minimum: 1
Maximum: 45

response

JSON pointer Description and constraints
"" (root) Type: object
Required fields: ["contract_version","lines"]
/properties/contract_version Required value: 1
/properties/reference The short reference the platform recorded this call under, ten lowercase hexadecimal characters, the value the call’s record row carries; quote it when reporting the call.

Type: string
Pattern: ^[0-9a-f]{10}$
/properties/lines The answer's lines, oldest first. From a store source each line renders one entry. From `container` a line is `<time> <stream> <text>`: the time the process wrote it, then `stdout` or `stderr` on the container grain, or `-` on the pod grain, whose log names no stream, the lines ordered by that time. A line from the compute the environment records as previous, the version being replaced, carries `[retiring]` after its stream; a line of the new version never does. On the container grain a line the stopped replica wrote at or after the provider's scale to zero carries `[idle-stop]` there instead, and a `[retiring]` line never carries it; the pod grain marks none. A read whose window starts after the scale to zero, or one made before the provider's record of the stop arrives, leaves those lines unmarked. Where the environment names no compute and a failed first health check kept lines, `container` answers those lines as the check kept them, at most 40, with no line written after the check.

Type: array
/properties/lines/items Type: string
/properties/detail Present on an empty answer, saying why nothing was found, and on any answer whose window ends within its source's lag of the read, saying the newest records may not have arrived yet. A read of all sources that holds entries also carries it, saying after any lag that console output is read with `container` alone, as an empty one says; on the `local` stream, which has no console to read, neither says so. Where the entries of a read of all sources or of `router` hold the router's `answered_5xx` record, the detail names the `container` read and its `since`. That `since` is the earliest such record's instant less its duration and five seconds. The detail also says that the read answers the newest lines after its `since`, so a caller raises `limit` or adds `contains`, and this sentence stands in place of the console sentence. On the pod grain the read is named for a record of the serving version alone, and the sentence adds that a pod's console ends with the pod. Where the records there are of another version, the detail names that version and no read; where they name none, it says so and names no read. On a read of all sources that sentence follows the console sentence. A `container` read carrying `contains` carries it, opening with the lines searched and matched, what the egress filter kept where given, the number answered where `limit` cut them, and, on the container grain, their span. A `container` answer with lines also carries it where the environment is idle now, saying after any lag that the last lines are an idle stop and that the next request starts the application. Where the platform marked a line of the answer `[retiring]`, the detail ends by saying that such lines are the previous version's, unless that sentence would take it past its budget. Where a `container` detail would pass its budget, sentences are left out, in a fixed order, until it fits. The sentence on more instances than a wait followed goes first. Then go the sentences on missing lines, on the delay before lines reach the log store, on an idle environment, and on a replica not running, stopped, or just restarted. The `[retiring]` sentence goes next, and the sentence on how a wait ended goes last. A pod answer says so where a line longer than the 262,144 bytes its read holds was not returned. Idle is the container app's latest revision holding no replica, or the pod's Deployment scaled to zero, and a halted environment is never idle. Under `app`, only what the application writes through the logging package lands there, and standard output and standard error land under `container`. Under `container`, the compute may have scaled to zero, recent lines may still be in the ingestion, `contains` matched none, or `filter` kept none. Under any other source, no entry stands in the window, or none matches the read's filters. The lag is a few seconds for the store's entries, up to a minute for the per-minute records under `router`, `egress`, and `harness` and for a container app's console, and none for a pod's console. On the container grain, where the platform has the direct read enabled, a `container` read also reads each running replica's console directly, once and bounded, and its detail says how that read went. Where the direct read kept lines, the detail names the time from which the newest lines were read from the replica directly, and says a later read may answer them again with the log workspace's stamp. The detail says lines may still be in the ingestion where that read reached no replica or did not complete, naming the reason where it failed. Where it did not complete, the sentence on the delay says instead that the log workspace's lines reach to about a minute before the read, and that a read a minute later answers the rest. A reason's word longer than 29 characters is cut to 29 characters, ending with `…`, in the detail, and `reason` carries it whole. It says so too where a replica is not running, stopped, or has just restarted, or where the answer may lack lines. Where none of those holds and the direct read kept no line, the detail says the replicas' newest lines are in this answer. An empty answer then says only that the compute may have scaled to zero and written nothing. Lines still in the ingestion reach the log workspace up to about a minute after the process writes them, so a later read answers them. A `container` read whose `wait_seconds` did not hold says why, unless its budget leaves that sentence out. The causes are the place taken, the platform's waits or follows full, the management API near its limit, the direct read off, or, on the pod grain, no pod running to follow. It also says where more instances run than the three followed. A `container` answer from a failed health check's kept lines opens with what happened and where `read_status` holds the same lines. Its `contains`, `filter`, and `limit` sentences give counts alone and no span, since those lines carry no time.

Type: string
/properties/reason Present only where a `container` read's direct read of the replicas did not complete: the reason's one word, whole at any length, such as `timed_out`, `throttled`, `http_503`, or a network error code. The `detail` names the same reason, cutting a word longer than 29 characters. On an answer with lines, or one the filter emptied, it also says how far the log workspace's lines reach, unless its budget leaves that sentence out. The word comes from the platform's own read of your replicas through the hosting provider, and its cause may not be known. It does not say whether your application is healthy; `read_status` does. A stream that answered a 5xx status, 501 and 505 aside, was asked once more where the read's bound allowed.

Type: string
/properties/failed_check Present only on a `container` answer where the environment names no compute and the newest version's failed health check kept a record. Its lines are that record's, at most 40, and none written after the check. Its `version` and `kind` name the failed version, `ended_at` its end, `since` the instant the check read its lines from, and `truncated` whether the check's bound cut them.

Type: object
Required fields: ["version","kind","ended_at","since","truncated"]
Additional properties: false
/properties/failed_check/properties/version Type: integer
/properties/failed_check/properties/kind Type: string
Allowed values: ["deploy","promote","restart"]
/properties/failed_check/properties/ended_at Type: ["string","null"]
/properties/failed_check/properties/since Type: ["string","null"]
/properties/failed_check/properties/truncated Type: boolean
/properties/environment Type: string
/properties/entries Type: array
/properties/entries/items Type: object
Required fields: ["at","level","source","message"]
/properties/entries/items/properties/at Type: string
/properties/entries/items/properties/level Type: string
/properties/entries/items/properties/source Type: string
/properties/entries/items/properties/message Type: string
/properties/entries/items/properties/fields Type: object
/properties/waited_ms Present where the request carried `wait_seconds`: the time the answer was held, in milliseconds. On a store source, the answer's `lines` and `entries` come from a fresh read after the wait, whatever ended it. A `container` answer on a container app merges the store's lines with every line its follows read, and on a pod it carries the followed lines alone. It carries no `settled`.

Type: integer
Minimum: 0

Complete payload contract

{
  "request": {
    "type": "object",
    "required": [
      "application"
    ],
    "properties": {
      "application": {
        "type": "string",
        "description": "The application id, from `list_applications`."
      },
      "environment": {
        "type": "string",
        "description": "The stream to read: `development` or `production`, or `local` for the developer-machine stream. Omission reads production. A stream with no deploy in its history is refused `never_deployed`; `local` needs none. Where the environment names no compute, a `container` read answers the lines a failed first deploy's or first promote's health check kept, and is otherwise refused `never_deployed`. Naming `local`, it is refused `invalid_request`: a local run has no console."
      },
      "since": {
        "type": "string",
        "description": "Inclusive start of the time window. Use YYYY-MM-DD followed by T (or t), HH:mm, optional :ss, an optional decimal fraction of 1–9 digits after seconds, then Z (or z) or a signed HH:mm offset. Omission leaves this bound open, except on a `container` read of an environment that runs as a container, whose window then starts 24 hours before the read. A null, empty, wrongly typed, or malformed value is refused 400 invalid_request naming the member."
      },
      "limit": {
        "type": "integer",
        "minimum": 1,
        "maximum": 1000,
        "description": "How many entries at most, 1 to 1000; 100 where none is given."
      },
      "source": {
        "type": "string",
        "description": "Which records to read. `container` is the process's own console: its standard output and standard error, `console.log` and `console.error` among them. `app` is only what the application writes through the logging package. The `platform` source is the platform's entries about it, `router` the serving router's records, `egress` the outbound proxy's records, and `harness` the runtime harness's connection-observer records (the platform's code loaded into the application's process). The value `all`, or an omitted source, reads every source the logging service stores; console output is read under `container` alone. An unrecognized value is ignored.",
        "enum": [
          "app",
          "platform",
          "router",
          "egress",
          "harness",
          "container",
          "all"
        ]
      },
      "filter": {
        "description": "Read only the outbound connections whose destination host the manifest's `egress` member declares (`declared`) or does not (`undeclared`), classified against the manifest as it stands at the read. With the `container` source the same classification runs over the console's lines.",
        "enum": [
          "declared",
          "undeclared"
        ]
      },
      "until": {
        "type": "string",
        "description": "Inclusive end of the time window, in the form `since` states and refused as it is. Omission leaves this bound open. A `container` read ignores it."
      },
      "level": {
        "type": "string",
        "description": "The lowest level to include — `debug`, `info`, `warn`, or `error`; entries at that level and above are answered, and any other value is ignored. One of the four on a `container` read is refused `invalid_request`, since a console line carries no level."
      },
      "contains": {
        "type": "string",
        "description": "Only entries whose message contains this text, on a store source. On a `container` read, only the lines that contain it, ignoring case, as the answer gives each line. The read searches up to its newest 1,000 lines before the `limit` cut. For a trace's other lines, omit it, `limit` 1000."
      },
      "field": {
        "type": "string",
        "description": "The name of one structured field to match; give the value it must hold in `value`. A non-empty name on a `container` read is refused `invalid_request`, since a console line carries no structured field."
      },
      "value": {
        "type": [
          "string",
          "number",
          "boolean",
          "null"
        ],
        "description": "The scalar value the named field must equal, with its JSON type preserved. Omit value to match entries containing the field; explicit null matches a null field value."
      },
      "wait_seconds": {
        "type": "integer",
        "minimum": 1,
        "maximum": 45,
        "description": "Optional. The seconds, 1 to 45, the answer is held while the read with this call's filters finds no entry: a store source is read every two seconds, and a `container` read follows the console, 40 seconds at most. Give `since`. A value outside 1 to 45 is refused `invalid_request`, its detail naming the bound."
      }
    }
  },
  "response": {
    "type": "object",
    "required": [
      "contract_version",
      "lines"
    ],
    "properties": {
      "contract_version": {
        "const": 1
      },
      "reference": {
        "type": "string",
        "pattern": "^[0-9a-f]{10}$",
        "description": "The short reference the platform recorded this call under, ten lowercase hexadecimal characters, the value the call’s record row carries; quote it when reporting the call."
      },
      "lines": {
        "type": "array",
        "description": "The answer's lines, oldest first. From a store source each line renders one entry. From `container` a line is `<time> <stream> <text>`: the time the process wrote it, then `stdout` or `stderr` on the container grain, or `-` on the pod grain, whose log names no stream, the lines ordered by that time. A line from the compute the environment records as previous, the version being replaced, carries `[retiring]` after its stream; a line of the new version never does. On the container grain a line the stopped replica wrote at or after the provider's scale to zero carries `[idle-stop]` there instead, and a `[retiring]` line never carries it; the pod grain marks none. A read whose window starts after the scale to zero, or one made before the provider's record of the stop arrives, leaves those lines unmarked. Where the environment names no compute and a failed first health check kept lines, `container` answers those lines as the check kept them, at most 40, with no line written after the check.",
        "items": {
          "type": "string"
        }
      },
      "detail": {
        "type": "string",
        "description": "Present on an empty answer, saying why nothing was found, and on any answer whose window ends within its source's lag of the read, saying the newest records may not have arrived yet. A read of all sources that holds entries also carries it, saying after any lag that console output is read with `container` alone, as an empty one says; on the `local` stream, which has no console to read, neither says so. Where the entries of a read of all sources or of `router` hold the router's `answered_5xx` record, the detail names the `container` read and its `since`. That `since` is the earliest such record's instant less its duration and five seconds. The detail also says that the read answers the newest lines after its `since`, so a caller raises `limit` or adds `contains`, and this sentence stands in place of the console sentence. On the pod grain the read is named for a record of the serving version alone, and the sentence adds that a pod's console ends with the pod. Where the records there are of another version, the detail names that version and no read; where they name none, it says so and names no read. On a read of all sources that sentence follows the console sentence. A `container` read carrying `contains` carries it, opening with the lines searched and matched, what the egress filter kept where given, the number answered where `limit` cut them, and, on the container grain, their span. A `container` answer with lines also carries it where the environment is idle now, saying after any lag that the last lines are an idle stop and that the next request starts the application. Where the platform marked a line of the answer `[retiring]`, the detail ends by saying that such lines are the previous version's, unless that sentence would take it past its budget. Where a `container` detail would pass its budget, sentences are left out, in a fixed order, until it fits. The sentence on more instances than a wait followed goes first. Then go the sentences on missing lines, on the delay before lines reach the log store, on an idle environment, and on a replica not running, stopped, or just restarted. The `[retiring]` sentence goes next, and the sentence on how a wait ended goes last. A pod answer says so where a line longer than the 262,144 bytes its read holds was not returned. Idle is the container app's latest revision holding no replica, or the pod's Deployment scaled to zero, and a halted environment is never idle. Under `app`, only what the application writes through the logging package lands there, and standard output and standard error land under `container`. Under `container`, the compute may have scaled to zero, recent lines may still be in the ingestion, `contains` matched none, or `filter` kept none. Under any other source, no entry stands in the window, or none matches the read's filters. The lag is a few seconds for the store's entries, up to a minute for the per-minute records under `router`, `egress`, and `harness` and for a container app's console, and none for a pod's console. On the container grain, where the platform has the direct read enabled, a `container` read also reads each running replica's console directly, once and bounded, and its detail says how that read went. Where the direct read kept lines, the detail names the time from which the newest lines were read from the replica directly, and says a later read may answer them again with the log workspace's stamp. The detail says lines may still be in the ingestion where that read reached no replica or did not complete, naming the reason where it failed. Where it did not complete, the sentence on the delay says instead that the log workspace's lines reach to about a minute before the read, and that a read a minute later answers the rest. A reason's word longer than 29 characters is cut to 29 characters, ending with `…`, in the detail, and `reason` carries it whole. It says so too where a replica is not running, stopped, or has just restarted, or where the answer may lack lines. Where none of those holds and the direct read kept no line, the detail says the replicas' newest lines are in this answer. An empty answer then says only that the compute may have scaled to zero and written nothing. Lines still in the ingestion reach the log workspace up to about a minute after the process writes them, so a later read answers them. A `container` read whose `wait_seconds` did not hold says why, unless its budget leaves that sentence out. The causes are the place taken, the platform's waits or follows full, the management API near its limit, the direct read off, or, on the pod grain, no pod running to follow. It also says where more instances run than the three followed. A `container` answer from a failed health check's kept lines opens with what happened and where `read_status` holds the same lines. Its `contains`, `filter`, and `limit` sentences give counts alone and no span, since those lines carry no time."
      },
      "reason": {
        "type": "string",
        "description": "Present only where a `container` read's direct read of the replicas did not complete: the reason's one word, whole at any length, such as `timed_out`, `throttled`, `http_503`, or a network error code. The `detail` names the same reason, cutting a word longer than 29 characters. On an answer with lines, or one the filter emptied, it also says how far the log workspace's lines reach, unless its budget leaves that sentence out. The word comes from the platform's own read of your replicas through the hosting provider, and its cause may not be known. It does not say whether your application is healthy; `read_status` does. A stream that answered a 5xx status, 501 and 505 aside, was asked once more where the read's bound allowed."
      },
      "failed_check": {
        "type": "object",
        "description": "Present only on a `container` answer where the environment names no compute and the newest version's failed health check kept a record. Its lines are that record's, at most 40, and none written after the check. Its `version` and `kind` name the failed version, `ended_at` its end, `since` the instant the check read its lines from, and `truncated` whether the check's bound cut them.",
        "required": [
          "version",
          "kind",
          "ended_at",
          "since",
          "truncated"
        ],
        "properties": {
          "version": {
            "type": "integer"
          },
          "kind": {
            "type": "string",
            "enum": [
              "deploy",
              "promote",
              "restart"
            ]
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "since": {
            "type": [
              "string",
              "null"
            ]
          },
          "truncated": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "environment": {
        "type": "string"
      },
      "entries": {
        "type": "array",
        "items": {
          "type": "object",
          "required": [
            "at",
            "level",
            "source",
            "message"
          ],
          "properties": {
            "at": {
              "type": "string"
            },
            "level": {
              "type": "string"
            },
            "source": {
              "type": "string"
            },
            "message": {
              "type": "string"
            },
            "fields": {
              "type": "object"
            }
          }
        }
      },
      "waited_ms": {
        "type": "integer",
        "minimum": 0,
        "description": "Present where the request carried `wait_seconds`: the time the answer was held, in milliseconds. On a store source, the answer's `lines` and `entries` come from a fresh read after the wait, whatever ended it. A `container` answer on a container app merges the store's lines with every line its follows read, and on a pod it carries the followed lines alone. It carries no `settled`."
      }
    }
  }
}

Shared contracts