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

# Logging from Ruby

export const VersionRequirements = ({versions = []}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const boundaries = {
    upper: " or lower",
    exact: "",
    lower: " or higher"
  };
  const containerStyle = {
    marginTop: "0.5rem",
    marginBottom: "1.5rem"
  };
  const lineStyle = {
    display: "block",
    margin: "0 0 0.35rem 0",
    fontSize: "0.875rem",
    lineHeight: "1.4"
  };
  const pillBaseStyle = {
    display: "inline-block",
    padding: "0.1em 0.4em",
    borderRadius: "0.25rem",
    border: "1px solid",
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
    fontSize: "0.85em",
    fontWeight: 500
  };
  const pillColors = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#e9d5ff",
      color: "#9333ea"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde68a",
      color: "#ca8a04"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#99f6e4",
      color: "#0d9488"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde68a",
      color: "#ca8a04"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#bbf7d0",
      color: "#16a34a"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#bfdbfe",
      color: "#2563eb"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fecaca",
      color: "#dc2626"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fed7aa",
      color: "#ea580c"
    }
  };
  const defaultPillColor = {
    background: "#f4f4f5",
    borderColor: "#e4e4e7",
    color: "#52525b"
  };
  const getPillStyle = name => ({
    ...pillBaseStyle,
    ...pillColors[name] || defaultPillColor
  });
  const getBoundText = bound => {
    return boundaries[bound] || boundaries.lower;
  };
  return <div style={containerStyle}>
      {versions.map((v, i) => <p key={`${v.name}-${v.version}-${v.bound || "lower"}-${i}`} style={lineStyle}>
          This feature requires{" "}
          <code style={getPillStyle(v.name)}>{v.name}</code> version {v.version}
          {getBoundText(v.bound)}.
        </p>)}
    </div>;
};

export const Compatibility = ({versions = [], label = "Available in"}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const defaultPillStyle = {
    borderColor: "#d4d4d8",
    background: "#f4f4f5",
    color: "#3f3f46"
  };
  const pillStyles = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#d8b4fe",
      color: "#6b21a8"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#5eead4",
      color: "#115e59"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#86efac",
      color: "#166534"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#93c5fd",
      color: "#1e40af"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fca5a5",
      color: "#991b1b"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fdba74",
      color: "#9a3412"
    }
  };
  const getPillStyle = name => ({
    ...defaultPillStyle,
    ...pillStyles[name] || ({})
  });
  return <div className="not-prose my-4 rounded-lg border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm dark:border-white/10 dark:bg-white/5">
      <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
        <span className="font-semibold text-zinc-700 dark:text-zinc-200">
          {label}:
        </span>
        {versions.map((v, i) => <span key={`${v.name}-${v.version}-${i}`} className="inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium" style={getPillStyle(v.name)}>
            <span>{v.name}</span>
            <span className="opacity-70">
              {v.version}
              {v.exact ? "" : "+"}
            </span>
          </span>)}
      </div>
    </div>;
};

<VersionRequirements
  versions={[
{ name: "AppSignal for Ruby", version: "3.2.0" }
]}
/>

This documentation outlines how to configure logging with your AppSignal for Ruby integration.

## Configure Logging

<Warning>
  🔐 Do not send <strong>Personal Identifiable Information (PII)</strong> to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. <br /> <br /> For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons).
</Warning>

You do not need to create a log source to send logs from the AppSignal for Ruby integration. An "application" log source will be created automatically.

### Rails Logger

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "4.3.0" }]} />

You can configure the Rails framework to send logs to AppSignal in an initializer file like `config/initializers/logging.rb`:

<CodeGroup>
  ```ruby Ruby theme={null}
  # config/initializers/logging.rb
  appsignal_logger = Appsignal::Logger.new("rails")
  Rails.logger = ActiveSupport::TaggedLogging.new(appsignal_logger)
  ```
</CodeGroup>

#### Using multiple logging backends

To send logs to both AppSignal's logger and Rails' default logger, use our logger's `.broadcast_to` helper:

<CodeGroup>
  ```ruby Ruby theme={null}
  # config/initializers/logging.rb
  appsignal_logger = Appsignal::Logger.new("rails")
  appsignal_logger.broadcast_to(Rails.logger)
  Rails.logger = ActiveSupport::TaggedLogging.new(appsignal_logger)
  ```
</CodeGroup>

We do not recommend using Rails' built-in broadcast logger feature, due to compatibility issues when used alongside tagged logging.

#### Tagged logging support

The use of `ActiveSupport::TaggedLogging` in the above examples enables support for Rails' log tags. For example, if you wish to add the request ID tag to the log messages, add it to the `config.log_tags` array in the `config/application.rb` file:

<CodeGroup>
  ```ruby Ruby theme={null}
  module TestApp
    class Application < Rails::Application
      config.log_tags = [:request_id]
    end
  end
  ```
</CodeGroup>

#### Using Lograge

<Warning>
  This Lograge config is not a replacement for the Rails logger config. If you
  want to report logs from `Rails.logger`, the [Rails logger config
  steps](#rails-logger) also need to be followed.
</Warning>

The [Lograge](https://github.com/roidrage/lograge) library is a popular solution for ingesting structured Rails *request* logs.

After adding the `lograge` gem, you can configure it in `config/initializers/lograge.rb` to send logs to AppSignal:

<CodeGroup>
  ```ruby Ruby theme={null}
  Rails.application.configure do
    config.lograge.enabled = true
    config.lograge.keep_original_rails_log = true
    config.lograge.logger = Appsignal::Logger.new(
      "rails",
      format: Appsignal::Logger::LOGFMT
    )
  end
  ```
</CodeGroup>

<Tip>
  Lograge does not support log levels. All logs emitted via Lograge will appear
  with severity level `INFO` in the AppSignal Logging UI.
</Tip>

### Sinatra Logger

You can configure Sinatra to send request logs to AppSignal using Rack's CommonLogger middleware. Configure it like shown below.

Consider if request logs contain useful information for you, read our [what logs should I store](https://www.appsignal.com/learning-center/what-logs-should-i-store) learning center article.

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("sinatra")
  use Rack::CommonLogger, logger
  ```
</CodeGroup>

#### Using multiple logging backends

To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper:

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("sinatra")
  logger.broadcast_to(Logger.new($stdout))
  use Rack::CommonLogger, logger
  ```
</CodeGroup>

### Sidekiq Logger

You can configure Sidekiq to send its logs to AppSignal, including the logs emitted by your background jobs:

<CodeGroup>
  ```ruby Ruby theme={null}
  Sidekiq.configure_server do |config|
    config.logger = Appsignal::Logger.new("sidekiq")
    config.logger.formatter = Sidekiq::Logger::Formatters::WithoutTimestamp.new
  end
  ```
</CodeGroup>

#### Using multiple logging backends

To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper:

<CodeGroup>
  ```ruby Ruby theme={null}
  Sidekiq.configure_server do |config|
    config.logger = Appsignal::Logger.new("sidekiq")
    config.logger.broadcast_to(Logger.new($stdout))
    config.logger.formatter = Sidekiq::Logger::Formatters::WithoutTimestamp.new
  end
  ```
</CodeGroup>

### Ruby Logger

To send logs to AppSignal as you would with Ruby's `Logger` class, you will need to create an instance of `Appsignal::Logger` and provide it with a `groupname` that defines where you are logging from, for example, if we were logging from a helper for invoicing clients:

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("invoice_helper")
  ```
</CodeGroup>

#### Using multiple logging backends

To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper:

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("invoice_helper")
  logger.broadcast_to(Logger.new($stdout))
  ```
</CodeGroup>

### Semantic Logger

The [Semantic Logger](https://logger.rocketjob.io/) library provides a comprehensive logging solution for Ruby and Rails applications.

After adding the `semantic_logger` gem, you can configure it to send logs to AppSignal as follows:

<CodeGroup>
  ```ruby Ruby theme={null}
  appsignal_logger = Appsignal::Logger.new("rails", format: Appsignal::Logger::LOGFMT)
  SemanticLogger.add_appender(logger: appsignal_logger, formatter: :logfmt)
  ```
</CodeGroup>

#### Using multiple logging backends

To send logs to both AppSignal's logger and `STDOUT`, add another appender using the `add_appender` method:

<CodeGroup>
  ```ruby Ruby theme={null}
  appsignal_logger = Appsignal::Logger.new("rails", format: Appsignal::Logger::LOGFMT)
  SemanticLogger.add_appender(logger: appsignal_logger, formatter: :logfmt)
  SemanticLogger.add_appender(io: $stdout)
  ```
</CodeGroup>

## Usage

### Sending Logs

Like the Ruby/Rails `Logger` class, you can define the severity level of your logs by using `fatal`, `error`, `warn`, `info`, and `debug`:

<CodeGroup>
  ```ruby Ruby theme={null}
  logger.warn("Something went wrong")
  ```
</CodeGroup>

You can define custom attributes to send log information that can be used when filtering and querying logs:

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("invoice_helper")
  logger.info("Generating invoice for customer", { customer_id: @customer.id })
  invoice = generate_invoice(@customer)
  logger.info("Generated invoice for customer", { customer_id: @customer.id, invoice_id: invoice.id })
  ```
</CodeGroup>

You can query and filter on message contents and attribute values using our [query syntax](/logging/query-syntax).

Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface.

### Default Logger Attributes

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "4.2.0" }]} />

When initializing the AppSignal logger, you can provide default attributes that will be included in all log messages:

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("invoice_helper", attributes: { customer_id: @customer.id })
  ```
</CodeGroup>

The attributes provided when initializing the logger will be included in all log messages sent from that logger instance. Attributes provided with the log message will be merged with the default logger attributes.

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("invoice_helper", attributes: { customer_id: @customer.id })
  # This log message will contain the `customer_id` attribute:
  logger.info("Generating invoice for customer")

  invoice = generate_invoice(@customer)
  # This log message will contain the `customer_id` and `invoice_id` attributes:
  logger.info("Generated invoice for customer", { invoice_id: invoice.id })
  ```
</CodeGroup>

When both the logger and the log message provide the same attribute, the log message's attribute will override the default logger attribute.

## Formats

### Auto detected format

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "4.7.3" }]} />

The AppSignal for Ruby gem will automatically detect the log line's format as JSON, Logfmt or plaintext by default, and parse attributes from it.
You don't need to manually set the log format, unless it's not being detected properly.
Please also [notify us](mailto:support@appsignal.com?subject=Log%20format%20auto%20detection%20not%20working) if this isn't working automatically.

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("group")
  # Plaintext format
  logger.info("This is about the blog")
  # Logfmt format
  logger.info("category=blog This is about the blog")
  # JSON format
  logger.info('{"category": "blog", "message": "This is about the blog"}')
  ```
</CodeGroup>

### Logfmt

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "3.3.6" }]} />

The AppSignal Logger can be explicitly configured to expect the line to be formatted as Logfmt and parse attributes from it.
Use this option when using an older AppSignal for Ruby gem version, which does not support [automatic format detection](#auto-detected-format).

The log format can be specified when creating a logger.
When initializing the AppSignal logger pass the Logfmt constant in the format option.

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("group", format: Appsignal::Logger::LOGFMT)
  logger.info("category=blog This is about the blog")
  ```
</CodeGroup>

In the example above, a filterable category attribute with the value "blog" will be logged.

### JSON

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "3.3.6" }]} />

The AppSignal Logger can be explicitly configured to expect the line to be formatted as JSON and parse attributes from it.
Use this option when using an older AppSignal for Ruby gem version, which does not support [automatic format detection](#auto-detected-format).

The log format can be specified when creating a logger.
When initializing the AppSignal logger pass the JSON constant in the format option.

<CodeGroup>
  ```ruby Ruby theme={null}
  logger = Appsignal::Logger.new("group", format: Appsignal::Logger::JSON)
  logger.info('{"category": "blog", "message": "This is about the blog"}')
  ```
</CodeGroup>

In the example above, a filterable category attribute with the value "blog" will be logged.

## Filtering Logs

You can use [the `ignore_logs` configuration option](/ruby/configuration/options#option-ignore_logs) to ignore log lines. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more.

## Need Help?

After configuring your Ruby application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track!
