Skip to main content

Overview

Log schemas modify matching Connector and Endpoint logs before Formal stores or exports them. Use schemas to remove, encrypt, truncate, or sanitize sensitive fields with field-level precision. Configure them with the formal_log_schema Terraform resource. Each schema contains:
  • A CEL scope that selects logs.
  • One or more protobuf field paths.
  • One or more actions for each path.
  • An optional asymmetric encryption key.

Configure a Log Schema

This example removes SQL literals from queries for one resource:
Run terraform apply, then query the resource through Formal. Verify: Open Logs and inspect the resulting request log. The query has values_stripped: true and does not contain its original literals.

Scope Fields

The scope_cel expression must return a boolean. It can use these fields: The scope cannot inspect payload fields, timestamps, or the complete log. Use paths to select payload fields after the scope matches.
Endpoint schemas use log.source == "endpoint". Stored Endpoint logs use source:desktop when you search them.

Schema Actions

encrypt and encrypt_sql require encryption_key_id. The key must use an asymmetric algorithm. See Encryption Keys. You can combine compatible actions on one path. drop takes precedence over every other action. Truncation runs before encryption. SQL stripping runs before SQL encryption.

Encryption Examples

Each example encrypts one kind of log content. Every example needs an asymmetric encryption_key_id. encrypt selects one string, google.protobuf.Struct, or google.protobuf.Value field. To encrypt a whole message, such as an HTTP body, list each sensitive field inside it. A path can cross a repeated field, such as messages. The action then applies to every element of that list. You can merge these paths into one schema. Do not repeat a path across schemas.

HTTP Bodies

This schema encrypts HTTP request and response bodies from Connectors and Endpoints:
received and sent hold the body before and after Formal policies run. dry_run_policies holds the body that dry-run policies would produce.

LLM Content

LLM content appears in two places. log.llm is the top-level view of the whole exchange. log.request.http.llm holds the LLM fields parsed from the HTTP request. Encrypt both to cover every copy:
messages holds the prompt the client sent. response_messages holds the model’s reply. content_parts.input holds tool inputs, encrypted as one value. To remove prompts instead, use one drop path on log.llm.messages. Do not combine it with child paths such as log.llm.messages.content_parts.text.

S3 Requests

This schema encrypts the bucket name and object path of S3 requests:

Exec Streams

This schema encrypts the terminal data of Kubernetes exec sessions:
This path encrypts every stream message, including terminal resize events. Verify: Run terraform apply, then send matching traffic through Formal. Open Logs and inspect the log. Each selected field holds ciphertext instead of plaintext.

Supported Paths

Every path starts with log. The following path families support schema actions: encrypt and truncate only support singular string fields. drop can select a supported parent field, string, list, or map. Paths use protobuf field names, not search aliases. For example, use log.request.http.body.received, not request_body.

Path Restrictions

A schema cannot contain both a parent path and its child. For example, you cannot combine log.request.http.body with log.request.http.body.received. Do not configure overlapping paths across separate schemas.

Failure Behavior

Formal clears a selected sensitive field if its encryption action fails. It then continues applying actions to other paths. A failed SQL encryption clears the complete selected query object. A scope evaluation failure skips only that schema. Other matching schemas continue to apply.

Next Steps

Configure Encryption Keys

Register an asymmetric key for encrypted fields

Policy Input Retention

Configure how long policy evaluation inputs are kept