defmodule Phoenix.LiveDashboard.RequestLogger do @moduledoc """ A plug that enables request logging. See [our Request Logger guides](request_logger.html) for more information. """ @behaviour Plug @max_age 3600 @private_key :phoenix_request_logger @impl true def init(opts) do param_key = opts[:param_key] cookie_key = opts[:cookie_key] unless param_key || cookie_key do raise ArgumentError, "either :param_key or :cookie_key is expected" end {param_key, cookie_key} end @impl true def call(conn, {param_key, cookie_key}) do conn |> verify_from_param_key(param_key) |> verify_from_cookie_key(cookie_key) |> Plug.Conn.put_private(@private_key, {param_key, cookie_key}) end defp verify_from_param_key(conn, nil), do: conn defp verify_from_param_key(conn, param_key) do conn = Plug.Conn.fetch_query_params(conn) verify_value(conn, param_key, conn.query_params[param_key]) conn end defp verify_from_cookie_key(conn, nil), do: conn defp verify_from_cookie_key(conn, cookie_key) do conn = Plug.Conn.fetch_cookies(conn) verify_value(conn, cookie_key, conn.req_cookies[cookie_key]) conn end defp verify_value(conn, key, value) do with true <- is_binary(value), {:ok, stream} <- Phoenix.Token.verify(conn, key, value, max_age: @max_age) do # TODO: Remove || once we support Phoenix v1.5+ endpoint = conn.private.phoenix_endpoint pubsub_server = endpoint.config(:pubsub_server) || endpoint.__pubsub_server__() Logger.metadata(logger_pubsub_backend: {pubsub_server, topic(stream)}) end end @doc false def topic(stream) do "phx_dashboard:request_logger:#{stream}" end @doc false def param_key(conn) do conn.private[@private_key] end @doc false def sign(endpoint, param_key, stream) when is_atom(endpoint) and is_binary(param_key) and is_binary(stream) do Phoenix.Token.sign(endpoint, param_key, stream) end end