> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Logs Configuration

> How to configure the audit logs sent by the Formal Connector

For every query going through your Formal Connectors, an audit log is created and sent to the Formal Control Plane for storage and analysis. With the [Terraform provider](https://registry.terraform.io/providers/formalco/formal/latest), you can define how these audit logs are handled.

The logging behavior can be configured at both the Connector and Resource level, with Resource-level configurations taking precedence over Connector-level ones. This allows you to set baseline logging at the Connector level and override specific settings at the Resource level where needed.

With log configurations, you can:

* Encrypt HTTP request and response payloads, SQL queries, and other sensitive data with your own encryption keys
* Limit the size of HTTP request and response payloads
* Strip sensitive values from SQL queries

## Logs Encryption

Before enabling encryption for logs, you need to configure encryption keys. These keys are used to protect sensitive data in payloads and SQL queries. See [Encryption Keys](/docs/guides/integrations/encryption_keys) for detailed information on creating and managing encryption keys.

Once you have created an encryption key, you can use it to encrypt logs:

```hcl theme={null}
resource "formal_log_configuration" "connector_logs" {
  name              = "connector-logs"
  encryption_key_id = formal_encryption_key.logs_key.id

  scope {
    type         = "connector"
    connector_id = formal_connector.main.id
  }

  request {
    encrypt = true
    sql {
      encrypt       = true
      strip_values  = false
    }
  }

  response {
    encrypt = true
  }
}
```

## HTTP Payloads

For HTTP request and response payloads, you can configure:

* Maximum size limits through `max_payload_size` in the `request` and `response` blocks, in bytes
* Encryption using the `encrypt` setting in each block (requires configured encryption keys)

You can choose to encrypt requests and responses independently - enabling encryption for one doesn't require enabling it for the other.

```hcl theme={null}
resource "formal_log_configuration" "http_logs_config" {
  name              = "http-logs"
  encryption_key_id = formal_encryption_key.logs_key.id

  scope {
    type        = "resource"
    resource_id = formal_resource.http_api_resource.id
  }

  request {
    encrypt           = true
    max_payload_size  = 32768
  }

  response {
    encrypt           = true
    max_payload_size  = 32768
  }
}
```

Choose appropriate size limits based on your storage capacity and compliance requirements.

These settings will affect the following fields in logs:

* `request.http.body.received`
* `request.http.body.sent`
* `request.http.body.dry_run_policies`
* `response.http.body.received`
* `response.http.body.sent`
* `response.http.body.dry_run_policies`

<Note>
  The example here uses a `scope` with type `resource`, meaning that the log
  configuration will only apply to the referenced resource (i.e.
  `http_api_resource`). If you want to apply the log configuration to all
  resources, you can use scope type `connector` instead. Resource-level
  configurations take precedence over Connector-level ones.
</Note>

## SQL Queries

When working with database resources, Formal offers two ways to protect sensitive information in SQL queries:

1. **Query Stripping**: Redact sensitive values from SQL queries using `strip_values`
2. **Query Encryption**: Encrypt sensitive parts of SQL queries using `encrypt` (requires a configured encryption key)

```hcl theme={null}
resource "formal_log_configuration" "sql_focused_config" {
  name              = "sql-logs"
  encryption_key_id = formal_encryption_key.logs_key.id

  scope {
    type         = "connector"
    connector_id = formal_connector.main.id
  }

  request {
    encrypt = false
    sql {
      encrypt       = true
      strip_values  = true
    }
  }

  response {
    encrypt = false
  }
}
```

You can enable both stripping and encryption. The values will be redacted first, then encrypted.

These settings will affect the following fields in logs:

* `request.query.received`
* `request.query.sent`
* `request.query.normalized`

## Stream Events

For streaming connections, you can also encrypt stream events using the optional `stream` block. This requires a configured encryption key:

```hcl theme={null}
resource "formal_log_configuration" "stream_config" {
  name              = "stream-logs"
  encryption_key_id = formal_encryption_key.logs_key.id

  scope {
    type         = "connector"
    connector_id = formal_connector.main.id
  }

  request {
    encrypt = false
  }

  response {
    encrypt = false
  }

  stream {
    encrypt = true
  }
}
```

## Logs Spool

When the Connector cannot deliver logs immediately (e.g. due to network issues, Control Plane downtime), it temporarily stores them on disk and retries automatically. This ensures logs are not lost during transient failures or planned restarts.

A typical log entry is around **1 KB**. Logs with [policy evaluation inputs](/docs/guides/observability/logs#policy-evaluation-input-retention) enabled are larger, depending on the size of the input data.

The Connector buffers up to **400 MB** of logs in memory before spooling to disk. Beyond that, disk space determines how many logs can be retained during extended outages. Disk allocation should be planned based on the volume of connections and acceptable outage duration.

<Note>
  The spool directory (`/formal/logs`) must be writable. If the Connector cannot
  write to disk, logs may be lost. For containerized deployments, mount a
  persistent volume to preserve logs across restarts.
</Note>
