Skip to content

Cookbook: Prometheus integration

Mike R edited this page Aug 9, 2019 · 4 revisions

Because prometheus.erl requires declaring metrics before using them you need to call Tesla.Middleware.Prometheus.setup() before your application starts.

Requires {:prometheus, "~> 4.0"} dependency.

defmodule Tesla.Middleware.Prometheus do
  @moduledoc """
  Prometheus metrics

  Usage:
      defmodule MyApi do
        use Tesla

        plug Tesla.Middleware.Prometheus
      end

      # lib/my_app/application.ex
      defmodule MyApp.Application do
        def start(_type, _args) do
          Tesla.Middleware.Prometheus.setup()

          # ...
        end
      end


  Metrics:
    - tesla_request_duration_seconds{host,status}
  """

  @buckets [
    0.001,
    0.002,
    0.004,
    0.008,
    0.016,
    0.032,
    0.064,
    0.128,
    0.256,
    0.512,
    1.024,
    2.048,
    4.096
  ]

  def setup do
    :prometheus_histogram.declare(
      name: :tesla_request_duration_seconds,
      help: "Time spent executing the request",
      labels: [:host, :status],
      buckets: @buckets
    )
  end

  def call(env, next, _opts) do
    start = System.monotonic_time()
    response = Tesla.run(env, next)
    stop = System.monotonic_time()

    labels = [
      URI.parse(env.url).host,
      status(response)
    ]

    :prometheus_histogram.observe(:tesla_request_duration_seconds, labels, stop - start)

    response
  end

  defp status({:ok, %{status: status}}), do: status
  defp status(_error), do: "error"
end