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

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 Elixir", version: "2.6.0" }
]}
/>

This documentation outlines how to configure logging with the AppSignal for Elixir 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 Elixir integration. An "application" log source will be created automatically.

### Logger Handler

<Compatibility
  versions={[
{ name: "AppSignal for Elixir", version: "2.7.10" },
{ name: "Elixir", version: "1.15" },
]}
/>

You can configure the Erlang `:logger` to use the `Appsignal.Logger.Handler` module as a handler, by calling the `Appsignal.Logger.Handler.add/2` function on your `Application.start/2` callback:

<CodeGroup>
  ```elixir Elixir theme={null}
  @impl true
  def start(_type, _args) do
    Appsignal.Logger.Handler.add("phoenix")
  end
  ```
</CodeGroup>

The given argument is the group name that describes where you are logging from. This group name can be used in AppSignal to filter your logs.

### Logger Backend

<Tip>
  Starting with Elixir version 1.15, Elixir logger backends are no longer
  recommended. See the [Logger Handler section](#logger-handler) above for the
  recommended alternative.
</Tip>

Instead of using an Elixir logger handler, you can configure the Elixir logger backend to use the `Appsignal.Logger.Backend` module as a backend by placing the code below in the `config/runtime.exs` file:

<CodeGroup>
  ```elixir Elixir theme={null}
  config :logger, backends: [:console, {Appsignal.Logger.Backend, [group: "phoenix"]}]
  ```
</CodeGroup>

The `group` option describes where you are logging from. This group name can be used in AppSignal to filter your logs.

You can also add the backend using the `add_backend/2` function on your `Application.start/2` callback:

<CodeGroup>
  ```elixir Elixir theme={null}
  @impl true
  def start(_type, _args) do
    Logger.add_backend(Appsignal.Logger.Backend, group: "phoenix")
  end
  ```
</CodeGroup>

### Elixir Logger

To send logs to AppSignal without using the Elixir Logger backend, you can use one of `Appsignal.Logger`'s logging functions 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>
  ```elixir Elixir theme={null}
  Appsignal.Logger.info(
    "invoice_helper",
    "Generating invoice for customer 129"
  )
  ```
</CodeGroup>

## Usage

### Sending Logs

Like the Elixir/Phoenix logger class, you can define the severity level of your logs by using `fatal`, `error`, `warning`, `info`, and `debug`:

<CodeGroup>
  ```elixir Elixir theme={null}
  Appsignal.Logger.warning(
    "app",
    "Something's gone terribly wrong here"
  )
  ```
</CodeGroup>

You can pass custom attributes as the last argument, to send log information that can be used when filtering and querying logs:

<CodeGroup>
  ```elixir Elixir theme={null}
  Appsignal.Logger.info(
    "invoice_helper",
    "Generated invoice for customer #{customer.id}",
    %{ 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.

## Formats

### Auto detected format

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

The AppSignal for Elixir package 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>
  ```elixir Elixir theme={null}
  # Plaintext format
  Appsignal.Logger.info(
    "invoice_helper",
    "Generated invoice"
  )
  # Logfmt format
  Appsignal.Logger.info(
    "invoice_helper",
    "Generated invoice invoice_id=A145 for customer customer_id=123"
  )
  # JSON format
  Appsignal.Logger.info(
    "invoice_helper",
    ~s({"message": "Generated invoice for customer", "invoice_id": "A145", "customer_id": "123"})
  )
  ```
</CodeGroup>

### Logfmt

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 Elixir package version, which does not support [automatic format detection](#auto-detected-format).

The Logfmt format can be specified when the AppSignal logger is called by adding the `:logfmt` value as the last argument.

<CodeGroup>
  ```elixir Elixir theme={null}
  Appsignal.Logger.info(
    "invoice_helper",
    "Generated invoice invoice_id=A145 for customer customer_id=123",
    :logfmt
  )
  ```
</CodeGroup>

### JSON

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 Elixir package version, which does not support [automatic format detection](#auto-detected-format).

The JSON format can be specified when the AppSignal logger is called by adding the `:json` value as the last argument.

<CodeGroup>
  ```elixir Elixir theme={null}
  Appsignal.Logger.info(
    "invoice_helper",
    ~s({"message": "Generated invoice for customer", "invoice_id": "A145", "customer_id": "123"}),
    :json
  )
  ```
</CodeGroup>

Only primitive non-nested values (numbers, strings, booleans and `null`) will be shown as log attributes. All other attributes will be discarded.

## Filtering Logs

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

## Need Help?

After configuring your Elixir 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!
