README.md

<div align="center">
  <img src="https://user-images.githubusercontent.com/464900/183483800-f313a3c0-1877-4c37-ac07-e08bed3f2276.png" width="500" />
  <br /><br />
  Telemetry-based metrics UI. Take your <a href="https://github.com/beam-telemetry/telemetry"><code>telemetry</code></a> metrics and display them in a web page.
  <br /><br />
  <a href="https://hex.pm/packages/telemetry_ui"><img src="https://img.shields.io/hexpm/v/telemetry_ui.svg" /></a>
</div>

## Features

`telemetry_ui`’s primary goal is to display [your application metrics](https://hexdocs.pm/telemetry_metrics) without external infrastructure dependencies. [Phoenix](https://hexdocs.pm/phoenix/telemetry.html), [Absinthe](https://hexdocs.pm/absinthe/telemetry.html), [Ecto](https://hexdocs.pm/ecto/Ecto.Repo.html#module-telemetry-events), [Erlang VM](https://hexdocs.pm/telemetry_poller/readme.html), [Tesla](https://hexdocs.pm/tesla/Tesla.Middleware.Telemetry.html), [Redix](https://hexdocs.pm/redix/telemetry.html), [Oban](https://hexdocs.pm/oban/Oban.Telemetry.html) and others expose all sorts of data that can be useful. You can also emit your own events from your application.

Your data should not have to be uploaded somewhere else to have insighful metrics.

It comes with a Postgres adapter, powered by Ecto, to quickly (and efficiently) store and query your application events.

<img alt="Screenshot of /metrics showcasing values and charts" src="https://user-images.githubusercontent.com/464900/183487842-095023b1-0fb6-4a53-ae21-4734f581fa43.png">

## Usage

### Installation

TelemetryUI is published on Hex. Add it to your list of dependencies in `mix.exs`:

```elixir
# mix.exs
def deps do
  [
    {:telemetry_ui, ">= 0.0.1"}
  ]
end
```

Then run mix deps.get to install Telemetry and its dependencies.

After the packages are installed you must create a database migration to add the `telemetry_ui_events` table to your database:

```sh
mix ecto.gen.migration add_telemetry_ui_events_table
```

Open the generated migration in your editor and call the up and down functions on `TelemetryUI.Adapter.EctoPostres.Migrations`:

```elixir
defmodule MyApp.Repo.Migrations.AddTelemetryUIEventsTable do
  use Ecto.Migration

  def up do
    TelemetryUI.Adapter.EctoPostres.Migrations.up(version: 1)
  end

  # We specify `version: 1` in `down`, ensuring that we'll roll all the way back down if
  # necessary, regardless of which version we've migrated `up` to.
  def down do
    TelemetryUI.Adapter.EctoPostres.Migrations.down(version: 1)
  end
end
```

This will run all of TelemetryUI's versioned migrations for your database. Migrations between versions are idempotent and rarely change after a release. As new versions are released you may need to run additional migrations.

Now, run the migration to create the table:

```sh
mix ecto.migrate
```

Before you can run a TelemetryUI instance you must provide some configuration. Set some base configuration within config.exs:

```elixir
# config/config.exs
config :my_app, TelemetryUI.Adapter.EctoPostres, repo: MyApp.Repo
```

TelemetryUI instances are isolated supervision trees and must be included in your application's supervisor to run. Use the application configuration you've just set and include TelemetryUI in the list of supervised children:

```elixir
# lib/my_app/application.ex
def start(_type, _args) do
  children = [
    MyApp.Repo,
    {TelemetryUI, telemetry_config()}
  ]

  Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end

defp telemetry_config do
  import Telemetry.Metrics

  [
    metrics: [
      counter("phoenix.router_dispatch.stop.duration", description: "Number of requests", unit: {:native, :millisecond}),
      summary("vm.memory.total", unit: {:byte, :megabyte}),
    ],
    adapter: TelemetryUI.Adapter.EctoPostgres,
    pruner: [threshold: [months: -1], interval: 84_000],
    write_buffer: [max_buffer_size: 10_000, flush_interval_ms: 5_000]
  ]
end
```

Since the config is read once at startup, you need to restart the server of you add new metrics to track.

To see the rendered metrics, you need to add a route to your router.

```elixir
# lib/my_app_web/router.ex
get("/metrics", TelemetryUI.Web, [])
```

#### Security

But since it may contain sensitive data, TelemetryUI require a special assign to render the page.

`:telemetry_ui_allowed` must be set to true in the `conn` struct before it enters the `TelemetryUI.Web` module.
The easiest way to do that in a Phoenix router is to use a pipeline with a private function

```elixir
pipeline :telemetry_ui do
  plug(:allow)
end

scope "/" do
  pipe_through(:telemetry_ui)
  get("/metrics", TelemetryUI.Web, [])
end

defp allow(conn, _), do: assign(conn, :telemetry_ui_allowed, true)
```

By using a special assign to control access, you can integrate `TelemetryUI` page with you existing authorization. We can imagine an admin protected section that also gives you access to the `TelemetryUI` page:

```elixir
pipeline :admin_protected do
  plug(MyAppWeb.EnsureCurrentUser)
  plug(MyAppWeb.EnsureRole, :admin)
  plug(:enable_telemetry_ui)
end

def enable_telemetry_ui(conn, _), do: assign(conn, :telemetry_ui_allowed, true)
```

That’s it! You can declare as many metrics as you want and they will render in HTML on your page!

## License

`TelemetryUI` is © 2022 [Mirego](https://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/telemetry_ui/blob/master/LICENSE.md) file.

## About Mirego

[Mirego](https://www.mirego.com) is a team of passionate people who believe that work is a place where you can innovate and have fun. We’re a team of [talented people](https://life.mirego.com) who imagine and build beautiful Web and mobile applications. We come together to share ideas and [change the world](http://www.mirego.org).

We also [love open-source software](https://open.mirego.com) and we try to give back to the community as much as we can.