> ## 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.

# Event formatters

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>;
};

Event formatters are helper classes to format event metadata for AppSignal transactions. In the AppSignal gem, event formatters are used to format event metadata from [ActiveSupport::Notifications instrumentation][as_instrumentation] events to AppSignal event metadata.

When a block of code is instrumented by ActiveSupport::Notifications, AppSignal will record the event on the transactions, just like it would for the [`Appsignal.instrument` helper][instrument_helper]. Event formatters allow the data to be passed to the `ActiveSupport::Notifications.instrument` method call to be formatted for AppSignal events.

The metadata for the events formatted by the event formatters will be visible on trace detail pages in the event timeline. Hover over a specific event and the on mouse hover pop-up will show details like the exact database being queried or the query that was executed.

<Tip>
  **Note**: If there are no other reasons to use
  [`ActiveSupport::Notifications`][as_instrumentation] instrumentation than
  AppSignal instrumentation, we recommend using the [`Appsignal.instrument`
  helper][instrument_helper] for instrumentation. Using
  `ActiveSupport::Notifications` adds more overhead than directly calling
  `AppSignal.instrument`. No event formatter will be needed either, as
  `AppSignal.instrument` accepts the metadata to be set directly.
</Tip>

<h2 id="creating-an-event-formatter">
  Creating an event formatter
</h2>

An AppSignal event formatter is a class with one instance method, `format`. This format method receives the event payload Hash and needs to return an Array with three values.

It's possible to add event formatter for libraries that use ActiveSupport::Notifications instrumentation, but look out that there's not already an event formatter registered for it.

It's also possible to create an event formatter for your own events. When adding your own event names, please mind the [event naming](/api/event-names) guidelines.

Each event formatter receives an event metadata "payload" Hash from which the event formatter can format the metadata for the event in AppSignal. This AppSignal event metadata needs to be returned by the event formatter in this order in an Array:

<CodeGroup>
  ```ruby Ruby theme={null}
  def format(payload)
    [
      "event title",
      "event body",
      Appsignal::EventFormatter::DEFAULT
    ]
  end
  ```
</CodeGroup>

1. An event title (`String`)
   * A more descriptive title of an event, such as `"Fetch current user"` or `"Fetch blog post comments"`. It will appear next to the event name in the event tree on the performance trace page to provide a little more context on what's happening.
2. An event body (`String`)
   * More details such as the database query that was used by the event.
3. An event body format (`Integer`)
   * Body format supports formatters to scrub the given data in the `body` argument to remove any sensitive data from the value. There are currently two supported values for the `body_format` argument.
     * `Appsignal::EventFormatter::DEFAULT`
       * This default value will indicate to AppSignal to leave the value intact and not scrub any data from it.
     * `Appsignal::EventFormatter::SQL_BODY_FORMAT`
       * The `SQL_BODY_FORMAT` value will indicate to AppSignal to run your data through the SQL sanitizer and scrub any values in SQL queries.

<CodeGroup>
  ```sql SQL theme={null}
  -- An event body with the value of:
  SELECT * FROM users WHERE email = 'hector@appsignal.com' AND password = 'iamabot'
  -- becomes
  SELECT * FROM users WHERE email = ? AND password = ?
  ```
</CodeGroup>

<Warning>
  **Warning**: the event formatter has no exception handling wrapped around it.
  If the custom event formatter raises an error, it will crash the web request
  or background job.
</Warning>

<h2 id="example-event-formatter">
  Example event formatter
</h2>

<CodeGroup>
  ```ruby Ruby theme={null}
  # A custom event formatter class
  class MyCustomEventFormatter
    def format(payload)
      [
        payload[:title],
        payload[:body],
        Appsignal::EventFormatter::DEFAULT
      ]
    end
  end

  # Register the custom event formatter class for a specific event
  Appsignal::EventFormatter.register("event.custom", MyCustomEventFormatter)
  # Can be registerd multiple times for other event names
  Appsignal::EventFormatter.register("other_event.custom", MyCustomEventFormatter)
  ```
</CodeGroup>

Then when instrumenting a block of code, use the event name that's registered for your custom event formatter.

<CodeGroup>
  ```ruby Ruby theme={null}
  ActiveSupport::Notifications.instrument(
    "event.custom", # Use the registered event name
    { # Pass along event metadata
      :title => "some event name",
      :body => "some event body"
    }
  ) do
    sleep 2
  end
  ```
</CodeGroup>

<h2 id="formatting-drymonitor-events">
  Formatting Dry::Monitor events
</h2>

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

Event formatters also format events instrumented through [Dry::Monitor notifications](/ruby/instrumentation/instrumentation#drymonitornotifications). Register the formatter against the Dry::Monitor event ID followed by `.dry`, so an event instrumented as `sql` is formatted by the formatter registered for `sql.dry`.

The first value the formatter returns means something different for these events. For an ActiveSupport::Notifications event it is the event's title. For a Dry::Monitor event it is the event's name, and the event is recorded in the timeline without a title.

<CodeGroup>
  ```ruby Ruby theme={null}
  class MyQueryFormatter
    def format(payload)
      [
        "query.my_library", # The event name, rather than the title
        payload[:query],
        Appsignal::EventFormatter::SQL_BODY_FORMAT
      ]
    end
  end

  Appsignal::EventFormatter.register("sql.dry", MyQueryFormatter)
  ```
</CodeGroup>

<h2 id="unregistering-an-event-formatter">
  Unregistering an event formatter
</h2>

Unregister a formatter to stop AppSignal from using it for an event name.

<CodeGroup>
  ```ruby Ruby theme={null}
  Appsignal::EventFormatter.unregister("event.custom", MyCustomEventFormatter)
  ```
</CodeGroup>

Use `Appsignal::EventFormatter.registered?("event.custom")` to check whether an event name has a formatter registered.

<h2 id="changes-in-gem-2-5">
  Changes in gem 2.5
</h2>

In AppSignal for Ruby gem version `2.5.2` some changes were made in how event formatters are registered. The old method of registering event formatters was deprecated in this release and will be removed in version `3.0` of the Ruby gem.

The new method of registering EventFormatters will allow custom formatters to be registered after AppSignal has loaded. This allows EventFormatters to be registered in [Rails initializers](http://guides.rubyonrails.org/configuring.html#using-initializer-files).

In gem version `2.5.1` and older, it is possible to register an event formatter like the following example, calling the `register` method in the class itself.

<CodeGroup>
  ```ruby Ruby theme={null}
  # Pre 2.5.2 method of registering event formatters
  # This method is now deprecated
  class MyCustomEventFormatter < Appsignal::EventFormatter
    register "event.custom"

    def format(payload)
      [payload[:title], payload[:body], Appsignal::EventFormatter::DEFAULT]
    end
  end
  ```
</CodeGroup>

With the new setup the register call was extracted from the class itself, so it can instead be registered directly on the EventFormatter class.

<CodeGroup>
  ```ruby Ruby theme={null}
  class MyCustomEventFormatter
    def format(payload)
      [payload[:title], payload[:body], Appsignal::EventFormatter::DEFAULT]
    end
  end

  Appsignal::EventFormatter.register("event.custom", MyCustomEventFormatter)
  ```
</CodeGroup>

This also means your EventFormatters no longer need to be a subclass of the `Appsignal::EventFormatter` class.

[as_instrumentation]: /ruby/instrumentation/instrumentation#activesupportnotifications

[instrument_helper]: /ruby/instrumentation/instrumentation#instrumentation-helpers


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.