# Ruby on Rails logs installation - Docs

`posthog-rails` forwards `Rails.logger` output to PostHog Logs over OpenTelemetry (OTLP), automatically correlated with each request's distinct ID and session ID. Requires Ruby 3.3+.

1.  1

    ## Add the OpenTelemetry gems

    Required

    Add the following gems to your `Gemfile` with `require: false` — `posthog-rails` loads them only when log forwarding is enabled:

    Gemfile

    PostHog AI

    ```ruby
    gem 'opentelemetry-sdk', require: false
    gem 'opentelemetry-logs-sdk', '>= 0.6.0', require: false
    gem 'opentelemetry-exporter-otlp-logs', require: false
    ```

    Then run:

    Terminal

    PostHog AI

    ```bash
    bundle install
    ```

    `opentelemetry-logs-sdk` must be `>= 0.6.0`. The OTLP exporter requires `LogRecordData#event_name`, which only exists from that version onward.

2.  2

    ## Enable log forwarding

    Required

    In `config/initializers/posthog.rb`, enable log forwarding:

    config/initializers/posthog.rb

    PostHog AI

    ```ruby
    PostHog::Rails.configure do |config|
      config.logs_enabled = true
    end
    ```

    Logs reuse the same project token (`api_key`) and host configured in `PostHog.init` — nothing extra to set. Records are sent to `<host>/i/v1/logs`.

    When the OpenTelemetry gems are absent, the integration logs a single warning and no-ops — it's safe to enable conditionally.

3.  3

    ## Optional configuration

    Optional

    **Filter by severity**

    `logs_level` controls which severity levels are forwarded. It never changes what your app logs locally:

    Ruby

    PostHog AI

    ```ruby
    config.logs_level = :info  # :debug, :info, :warn, :error, :fatal, :unknown, or a Logger constant
    ```

    **Rate limiting**

    Forwarding is capped at 6,000 records per minute by default. When the cap is reached, one warning record is emitted and further records are dropped for the remainder of that minute:

    Ruby

    PostHog AI

    ```ruby
    config.logs_max_records_per_minute = 6_000  # nil, 0, or any negative value to disable
    ```

    **Scrub PII**

    Set `logs_before_send` to a proc that receives each record and returns a modified hash to send or `nil` to drop it:

    Ruby

    PostHog AI

    ```ruby
    config.logs_before_send = proc { |record|
      next nil if record[:severity] == :debug
      record[:body] = record[:body].gsub(/\b[\w.+-]+@[\w-]+\.[\w.]+\b/, '[redacted]')
      record
    }
    ```

    The record hash has keys `:timestamp`, `:severity` (a symbol such as `:warn`), `:body`, and `:attributes`. If the callback raises, the record is dropped.

    **Trace correlation**

    If your app uses OpenTelemetry tracing instrumentation gems (for example, `opentelemetry-instrumentation-rails` or `opentelemetry-instrumentation-rack`), log records emitted during a traced request automatically carry the active `trace_id` and `span_id` — no additional configuration needed.

4.  4

    ## Test your setup

    Recommended

    1.  Start your Rails server and trigger a request that logs output.
    2.  Check the [PostHog Logs interface](https://app.posthog.com/logs) for your log entries.
    3.  If logs don't appear, check for a startup warning in your server output (a line starting with `[PostHog]` indicates a configuration issue such as missing gems or an unresolved project token).

    [View your logs in PostHog](https://app.posthog.com/logs)

6.  ## Next steps

    Checkpoint

    *What you can do with your logs*

    | Action | Description |
    | --- | --- |
    | [Why you need logs](/docs/logs/basics.md) | What logs show you that nothing else does |
    | [Search logs](/docs/logs/search.md) | Use the search interface to find specific log entries |
    | Filter by level | Filter by INFO, WARN, ERROR, etc. |
    | [Link session replay](/docs/logs/link-session-replay.md) | Connect logs to users and session replays by passing posthogDistinctId and sessionId |
    | [Link logs to a person](/docs/logs/link-person.md) | Surface every log emitted on behalf of a user on their PostHog person profile |
    | [Logging best practices](/docs/logs/best-practices.md) | Learn what to log, how to structure logs, and patterns that make logs useful in production |

    [Troubleshoot common issues](/docs/logs/troubleshooting.md)

## Configuration reference

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| logs_enabled | Boolean | false | Master switch for log forwarding. Requires Ruby 3.3+ and the three OpenTelemetry gems above. |
| logs_forward_rails_logger | Boolean | true | Broadcast Rails.logger into the PostHog Logs sink. Takes effect only when logs_enabled is true. |
| logs_level | Symbol/Integer | nil | Minimum severity to forward (:debug, :info, :warn, :error, :fatal, :unknown, or a Logger constant). Inherits the Rails logger level when nil. |
| logs_max_records_per_minute | Integer/String | 6000 | Records-per-minute cap. Numeric strings (e.g. from ENV) are coerced. Set to nil, 0, or a negative value to disable. |
| logs_before_send | Proc | nil | Called with each record hash (:timestamp, :severity, :body, :attributes) before sending. Return a modified hash to send or nil to drop. Records are dropped if the callback raises. |

## Troubleshooting

**Logs not appearing in PostHog**

1.  Check the OTel gems are installed: `bundle list | grep opentelemetry`. You should see `opentelemetry-sdk`, `opentelemetry-logs-sdk` (≥ 0.6.0), and `opentelemetry-exporter-otlp-logs`.
2.  Check for a startup warning — if the gems are missing or the project token can't be resolved, PostHog logs a warning to stderr at boot (look for a line starting with `[PostHog]`).
3.  Verify `logs_enabled = true` is set in your initializer and that the initializer runs before the railtie (it should if it lives in `config/initializers/`).
4.  Check test mode — `PostHog.init` with `test_mode: true` disables the logs pipeline entirely. Ensure test mode is only set in the test environment.

For general Logs troubleshooting (authentication, connection issues, format problems), see the [Logs troubleshooting guide](/docs/logs/troubleshooting.md).

### Community questions

Ask a question

### Was this page useful?

HelpfulCould be better