Sometimes it's useful to customize or suppress logging for a specific route in a Phoenix application. One example I've encountered several times is dealing with heartbeat logs, either from dev tooling or from external services or hosts.
In this example, Vite (a front-end build tool I use) is repeatedly pinging the route /__vite_ping
, due to a tab in local dev where the connection was lost when I restarted the server but didn't refresh the page. In order to suppress logging on this route, we look at endpoint.ex
where logging is happening:
# plug(Plug.Logger) # (for an older app)
plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint])
In older apps, AppWeb.Endpoint uses Plug.Logger, but in more recent versions of Phoenix, the generated Endpoint module uses Plug.Telemetry. Either can be customized to have route-dependent behavior.
To customize the behavior of Telemetry, create a new Plug module, AppWeb.Plugs.Telemetry
. It doesn't have to be named this, but I generally put plug modules into a plugs directory under the main <app name>_web
directory. In this case, it's lib/app_web/plugs/telemetry.ex
.
defmodule AppWeb.Plugs.Telemetry do
@behaviour Plug
# ...
end
To implement the Plug behaviour
(note the spelling), we need to define two functions, init/1
and call/2
. The simplest version of this module would just use the Plug.Telemetry
library's functions for each, like this:
defmodule AppWeb.Plugs.Telemetry do
@behaviour Plug
@impl true
def init(opts), do: Plug.Telemetry.init(opts)
@impl true
def call(conn, opts) do
Plug.Telemetry.call(conn, opts)
end
end
Just dishing off calls to use the Telemetry library's built-in functions won't actually change the behavior of our app, though, so we also need to add a function head for call that matches the "__vite_ping" path were we don't want logging and handle it without invoking Plug.Telemetry.call/2
).
defmodule AppWeb.Plugs.Telemetry do
@behaviour Plug
@impl true
def init(opts), do: Plug.Telemetry.init(opts)
@impl true
def call(%{path_info: ["__vite_ping"]} = conn, opts) do
conn
|> Plug.Conn.send_resp(200, "")
|> Plug.Conn.halt()
end
def call(conn, opts) do
Plug.Telemetry.call(conn, opts)
end
end
The final step is to replace the call to Plug.Telemetry with our customized version in endpoint.ex
.
plug(AppWeb.Plugs.Telemetry, event_prefix: [:phoenix, :endpoint])
1 Comment
😶