Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you set different log levels for different routes in Phoenix?

I have a /ping route that gets called a lot in production by the load balancer and kubernetes health checks. I'd like to set the log level of Plug.Logger to :debug just for that one route.

defmodule Web.Endpoint do
  ...
  forward "/ping", Web.HealthCheck
  ...
end

defmodule Web.HealthCheck do
  use Plug.Router

  plug :match
  plug :dispatch

  get "/" do
    send_resp(conn, 200, "ok")
  end
end

I've not found a way to modify or remove an existing plug. I tried adding plug Plug.Logger, log: :debug to Web.HealthCheck, but then I just get the route logged twice at different levels

[info] GET /ping
[debug] GET /ping

I've found a way to disable logging entirely for a specific route by removing plug Plug.Logger from endpoint.ex and manually adding back as needed https://elixirforum.com/t/disable-logging-on-specific-route/622, but then I have to be careful to remember to make sure logging is enabled for every new route I add, and really I'd prefer just to have the /ping route set to debug so it can log in dev as needed, but won't be so spammy in production.

like image 797
mmrobins Avatar asked Jan 25 '18 18:01

mmrobins


2 Answers

In more recent versions of Phoenix it looks like that specific log is now produced by Phoenix.Logger in response to telemetry events emitted by Plug.Telemetry. Suppressing specific routes can be done in very much the same fashion as with Plug.Logger. Either create a separate endpoint / pipeline that does not include telemetry at all, or provide a custom implementation of the plug that alters the log level for certain paths:

defmodule MyWeb.Plugs.Telemetry do
  @behaviour Plug

  @impl true
  def init(opts), do: Plug.Telemetry.init(opts)

  @impl true
  def call(%{path_info: ["ping"]} = conn, {start_event, stop_event, opts}) do
    Plug.Telemetry.call(conn, {start_event, stop_event, Keyword.put(opts, :log, :debug)})
  end
  def call(conn, args), do: Plug.Telemetry.call(conn, args)
end

and then replace

  plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]

with

  plug MyWeb.Plugs.Telemetry, event_prefix: [:phoenix, :endpoint]

in your endpoint.ex.

like image 64
Ilja Everilä Avatar answered Nov 17 '22 17:11

Ilja Everilä


You can define a plug that calls Plug.Logger with a different level for different paths.

defmodule MyApp.Logger do
  def init(_opts), do: {}

  def call(%{path_info: ["ping"]} = conn, _opts) do
    Plug.Logger.call(conn, :error)
  end
  def call(conn, _opts) do
    Plug.Logger.call(conn, :info)
  end
end

Now replace plug Plug.Logger with plug MyApp.Logger in your Endpoint module. All requests to /ping will now log at :error level while everything else will log at info level.

like image 23
Dogbert Avatar answered Nov 17 '22 18:11

Dogbert