# `PushX.Telemetry`
[🔗](https://github.com/cignosystems/pushx/blob/v0.11.0/lib/push_x/telemetry.ex#L1)

Telemetry integration for PushX.

PushX emits the following telemetry events:

## Events

### `[:pushx, :push, :start]`

Emitted when a push notification request starts.

**Measurements:** `%{system_time: integer}`
**Metadata:**
  * `:provider` - `:apns` or `:fcm`
  * `:token` - Device token (truncated for privacy)

### `[:pushx, :push, :stop]`

Emitted when a push notification request completes successfully.

**Measurements:** `%{duration: integer}` (in native time units)
**Metadata:**
  * `:provider` - `:apns` or `:fcm`
  * `:token` - Device token (truncated)
  * `:status` - `:sent`
  * `:id` - Provider message ID (if available)

### `[:pushx, :push, :exception]`

Emitted when a push notification request raises an exception.

**Measurements:** `%{duration: integer}`
**Metadata:**
  * `:provider` - `:apns` or `:fcm`
  * `:token` - Device token (truncated)
  * `:kind` - Exception kind (`:error`, `:exit`, `:throw`)
  * `:reason` - Exception reason
  * `:stacktrace` - Exception stacktrace

### `[:pushx, :push, :error]`

Emitted when a push notification request returns an error response.

**Measurements:** `%{duration: integer}`
**Metadata:**
  * `:provider` - `:apns` or `:fcm`
  * `:token` - Device token (truncated)
  * `:status` - Error status (e.g., `:invalid_token`, `:rate_limited`)
  * `:reason` - Error reason string

### `[:pushx, :retry, :attempt]`

Emitted when a retry attempt is made.

**Measurements:** `%{delay_ms: integer, attempt: integer}`
**Metadata:**
  * `:provider` - `:apns` or `:fcm`
  * `:status` - The error status that triggered the retry

## Example Usage

Attach a handler in your application startup:

    :telemetry.attach_many(
      "pushx-logger",
      [
        [:pushx, :push, :start],
        [:pushx, :push, :stop],
        [:pushx, :push, :error],
        [:pushx, :push, :exception]
      ],
      &MyApp.PushXTelemetry.handle_event/4,
      nil
    )

Example handler:

    defmodule MyApp.PushXTelemetry do
      require Logger

      def handle_event([:pushx, :push, :stop], %{duration: duration}, metadata, _config) do
        duration_ms = System.convert_time_unit(duration, :native, :millisecond)
        Logger.info("Push sent to #{metadata.provider} in #{duration_ms}ms")
      end

      def handle_event([:pushx, :push, :error], _measurements, metadata, _config) do
        Logger.warning("Push failed: #{metadata.status} - #{metadata.reason}")
      end

      def handle_event(_event, _measurements, _metadata, _config), do: :ok
    end

## Metrics with Telemetry.Metrics

    defmodule MyApp.Telemetry do
      import Telemetry.Metrics

      def metrics do
        [
          counter("pushx.push.stop.count", tags: [:provider]),
          counter("pushx.push.error.count", tags: [:provider, :status]),
          distribution("pushx.push.stop.duration",
            unit: {:native, :millisecond},
            tags: [:provider]
          )
        ]
      end
    end

# `truncate_token`

```elixir
@spec truncate_token(String.t()) :: String.t()
```

Truncates a device token for privacy-safe logging.

Shows first 8 and last 4 characters, replacing the middle with `...`.
Returns the token unchanged if it is 16 characters or shorter.

## Examples

    iex> PushX.Telemetry.truncate_token("abcdefgh12345678ijklmnop")
    "abcdefgh...mnop"

    iex> PushX.Telemetry.truncate_token("short")
    "short"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
