Skip to content

Instantly share code, notes, and snippets.

@colinrymer
Created March 13, 2017 21:02
Show Gist options
  • Save colinrymer/cba1a54dae069bd6c706d9bb91f13cd4 to your computer and use it in GitHub Desktop.
Save colinrymer/cba1a54dae069bd6c706d9bb91f13cd4 to your computer and use it in GitHub Desktop.
Phoenix Prometheus Setup
...
# Prometheus
config :prometheus, MyApp.PhoenixInstrumenter,
controller_call_labels: [:controller, :action],
duration_buckets: [10, 25, 50, 100, 250, 500, 1000, 2500, 5000,
10_000, 25_000, 50_000, 100_000, 250_000, 500_000,
1_000_000, 2_500_000, 5_000_000, 10_000_000],
registry: :default,
duration_unit: :microseconds
config :prometheus, MyApp.PipelineInstrumenter,
labels: [:status_class, :method, :host, :scheme, :request_path],
duration_buckets: [10, 100, 1_000, 10_000, 100_000,
300_000, 500_000, 750_000, 1_000_000,
1_500_000, 2_000_000, 3_000_000],
registry: :default,
duration_unit: :microseconds
# If you're using fuse
config :fuse,
stats_plugin: :fuse_stats_prometheus
...
defmodule MyApp.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
socket "/socket", MyApp.UserSocket
# Serve at "/" the static files from "priv/static" directory.
#
# You should set gzip to true if you are running phoenix.digest
# when deploying your static files in production.
plug Plug.Static,
at: "/", from: :my_app, gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt)
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
if code_reloading? do
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
end
plug Plug.RequestId
plug Plug.Logger
plug MyApp.PrometheusExporter # makes the /metrics URL happen
plug MyApp.PipelineInstrumenter # measures pipeline exec times
plug Plug.Parsers,
#...
end
defmodule MyApp.PhoenixInstrumenter do
@moduledoc """
Provides instrumentation for Phoenix specific metrics.
"""
use Prometheus.PhoenixInstrumenter
end
defmodule MyApp.PipelineInstrumenter do
@moduledoc """
Instrumentation for the entire plug pipeline.
"""
use Prometheus.PlugPipelineInstrumenter
@spec label_value(:request_path, Plug.Conn.t) :: binary
def label_value(:request_path, conn) do
conn.request_path
end
end
defmodule MyApp.PrometheusExporter do
@moduledoc """
This module implements a plug that provides the `/metrics` endpoint
for Prometheus to scrape.
"""
use Prometheus.PlugExporter
end
defmodule MyApp.RepoInstrumenter do
@moduledoc """
Instrumentation of Ecto activity.
"""
use Prometheus.EctoInstrumenter
end
defmodule MyApp.VersionInstrumenter do
@moduledoc """
Prometheus Gauge to expose the version info and build details as described in
https://www.robustperception.io/exposing-the-software-version-to-prometheus/
"""
use Prometheus.Metric
@spec setup(otp_app :: atom) :: any
def setup(otp_app) do
gauge_name = String.to_atom("#{otp_app}_build_info")
Gauge.declare([name: gauge_name,
help: help(otp_app),
labels: [:version],
registry: :default])
Gauge.set([name: gauge_name,
labels: [version(otp_app)],
registry: :default], 1)
end
defp help(otp_app), do: "Build information for the currently deployed version of #{app_name(otp_app)}"
defp app_name(otp_app), do: otp_app |> Atom.to_string() |> String.capitalize()
defp version(otp_app), do: otp_app |> Application.spec() |> Keyword.get(:vsn) |> List.to_string
end
defmodule MyApp do
@moduledoc """
OTP module for working with application and defining callbacks
"""
use Application
alias MyApp
# See http://elixir-lang.org/docs/stable/elixir/Application.html
# for more information on OTP Applications
@spec start(any, any) :: any
def start(_type, _args) do
import Supervisor.Spec, warn: false
opts = [strategy: :one_for_one, name: Supervisor]
children = [
supervisor(MyApp.Endpoint, []),
supervisor(MyApp.Repo, []),
]
require Prometheus.Registry
MyApp.PhoenixInstrumenter.setup()
MyApp.PipelineInstrumenter.setup()
MyApp.RepoInstrumenter.setup()
if :os.type == {:unix, :linux} do
Prometheus.Registry.register_collector(:prometheus_process_collector)
end
MyApp.PrometheusExporter.setup()
MyApp.VersionInstrumenter.setup(:my_app)
Supervisor.start_link(children, opts)
end
# Tell Phoenix to update the endpoint configuration
# whenever the application is updated.
@spec config_change(any, any, any) :: :ok
def config_change(changed, _new, removed) do
MyApp.Endpoint.config_change(changed, removed)
:ok
end
end
...
defp deps do
[...
{:prometheus_ecto, "~> 1.0"},
{:prometheus_ex, "~> 1.0"},
{:prometheus_phoenix, "~> 1.0"},
{:prometheus_plugs, "~> 1.0"},
{:prometheus_process_collector, "~> 1.0"},
...]
end
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment