Skip to content

Commit

Permalink
Making plug completely optional
Browse files Browse the repository at this point in the history
  • Loading branch information
akoutmos committed Sep 19, 2024
1 parent 3db9646 commit 635491d
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 64 deletions.
3 changes: 2 additions & 1 deletion lib/prom_ex/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ defmodule PromEx.Config do
* `:metrics_server` - This key contains the configuration information needed to run a standalone
HTTP server powered by Cowboy. This server provides a lightweight solution to serving up PromEx
metrics. Its configuration options are:
metrics. In order to use this standalone metrics server plug you need to have `:plug` and `:plug_cowboy`
as dependencies in your project. Its configuration options are:
* `:port` - The port that the Cowboy HTTP server should run on.
Expand Down
131 changes: 68 additions & 63 deletions lib/prom_ex/metrics_server/plug.ex
Original file line number Diff line number Diff line change
@@ -1,81 +1,86 @@
defmodule PromEx.MetricsServer.Plug do
@moduledoc """
This plug is used to serve metrics when PromEx is run in a
standalone server configuration. This plug supports the
following options:
if Code.ensure_loaded?(Plug) do
defmodule PromEx.MetricsServer.Plug do
@moduledoc """
This plug is used to serve metrics when PromEx is run in a
standalone server configuration. This plug supports the
following options:
* `:path` - The route that should expose the metrics (default is "/metrics")
* `:prom_ex_module` - The PromEx module that this plug will expose
"""
* `:path` - The route that should expose the metrics (default is "/metrics")
* `:prom_ex_module` - The PromEx module that this plug will expose
@behaviour Plug
In order to use this standalone metrics server plug you need to have `:plug` and `:plug_cowboy`
as dependencies in your project.
"""

require Logger
@behaviour Plug

import Plug.Conn
require Logger

alias Plug.Conn
import Plug.Conn

@impl true
def init(opts) do
Map.pop(opts, :auth_strategy, :none)
end
alias Plug.Conn

@impl true
def init(opts) do
Map.pop(opts, :auth_strategy, :none)
end

@impl true
def call(%Conn{request_path: path} = conn, {:none, %{path: path, prom_ex_module: prom_ex_module}}) do
case PromEx.get_metrics(prom_ex_module) do
:prom_ex_down ->
Logger.warning("Attempted to fetch metrics from #{prom_ex_module}, but the module has not been initialized")
@impl true
def call(%Conn{request_path: path} = conn, {:none, %{path: path, prom_ex_module: prom_ex_module}}) do
case PromEx.get_metrics(prom_ex_module) do
:prom_ex_down ->
Logger.warning("Attempted to fetch metrics from #{prom_ex_module}, but the module has not been initialized")

conn
|> put_resp_content_type("text/plain")
|> send_resp(503, "Service Unavailable")
conn
|> put_resp_content_type("text/plain")
|> send_resp(503, "Service Unavailable")

metrics ->
PromEx.ETSCronFlusher.defer_ets_flush(prom_ex_module.__ets_cron_flusher_name__())
metrics ->
PromEx.ETSCronFlusher.defer_ets_flush(prom_ex_module.__ets_cron_flusher_name__())

conn
|> put_resp_content_type("text/plain")
|> send_resp(200, metrics)
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, metrics)
end
end
end

def call(
%Conn{request_path: path} = conn,
{:bearer, %{auth_token: auth_token, path: path} = plug_opts}
) do
with ["Bearer " <> req_auth_token] <- get_req_header(conn, "authorization"),
true <- req_auth_token == auth_token do
call(conn, {:none, plug_opts})
else
_ ->
conn
|> put_resp_content_type("text/plain")
|> send_resp(401, "Unauthorized")
def call(
%Conn{request_path: path} = conn,
{:bearer, %{auth_token: auth_token, path: path} = plug_opts}
) do
with ["Bearer " <> req_auth_token] <- get_req_header(conn, "authorization"),
true <- req_auth_token == auth_token do
call(conn, {:none, plug_opts})
else
_ ->
conn
|> put_resp_content_type("text/plain")
|> send_resp(401, "Unauthorized")
end
end
end

def call(
%Conn{request_path: path} = conn,
{:basic, %{auth_user: auth_user, auth_password: auth_password, path: path} = plug_opts}
) do
with ["Basic " <> req_auth_user_pass] <- get_req_header(conn, "authorization"),
{:ok, user_and_pass} <- Base.decode64(req_auth_user_pass),
[req_user, req_pass] <- String.split(user_and_pass, ":", parts: 2),
true <- req_user == auth_user,
true <- req_pass == auth_password do
call(conn, {:none, plug_opts})
else
_ ->
conn
|> put_resp_content_type("text/plain")
|> send_resp(401, "Unauthorized")
def call(
%Conn{request_path: path} = conn,
{:basic, %{auth_user: auth_user, auth_password: auth_password, path: path} = plug_opts}
) do
with ["Basic " <> req_auth_user_pass] <- get_req_header(conn, "authorization"),
{:ok, user_and_pass} <- Base.decode64(req_auth_user_pass),
[req_user, req_pass] <- String.split(user_and_pass, ":", parts: 2),
true <- req_user == auth_user,
true <- req_pass == auth_password do
call(conn, {:none, plug_opts})
else
_ ->
conn
|> put_resp_content_type("text/plain")
|> send_resp(401, "Unauthorized")
end
end
end

def call(conn, _opts) do
conn
|> put_resp_content_type("text/plain")
|> send_resp(404, "Not Found")
def call(conn, _opts) do
conn
|> put_resp_content_type("text/plain")
|> send_resp(404, "Not Found")
end
end
end

0 comments on commit 635491d

Please sign in to comment.