defmodule Timber.Plug do @moduledoc """ Documentation for Timber.Plug. """ @doc false # Fetches the request ID from the connection using the given header name # # The request ID may be added to the connection in a number of ways which # complicates how we retrieve it. It is usually set by calling the # Plug.RequestId module on the connection which sets a request ID only if one # hasn't already been set. If the request ID is set by a service prior to # Plug, it will be present as a request header. If Plug.RequestId generates a # request ID, that request ID is only present in the response headers. The # request headers should always take precedent in this function, though. # # This function will return either a single element list containing a # two-element tuple of the form: # # {"x-request-id", "myrequestid91391"} # # or an empty list. This normalizes the expectation of the header name for # future processing. # # Note: Plug.RequestId will change an existing request ID if it doesn't think # the request ID is valid. See # [request_id.ex](https://github.com/elixir-lang/plug/blob/v1.2.2/lib/plug/request_id.ex#L62). @spec get_request_id(Plug.Conn.t(), String.t()) :: [{String.t(), String.t()}] | [] def get_request_id(conn, header_name) do headers = case Plug.Conn.get_req_header(conn, header_name) do [] -> Plug.Conn.get_resp_header(conn, header_name) values -> values end handle_request_id(headers) end # Helper function to take the result of the header retrieval function and # change it to the desired response format for get_request_id/2 @spec handle_request_id([] | [String.t()]) :: [{String.t(), String.t()}] | [] defp handle_request_id([]) do [] end defp handle_request_id([request_id | _]) do [{"x-request-id", request_id}] end @doc false @spec get_client_ip(Plug.Conn.t()) :: String.t() | nil def get_client_ip(%{remote_ip: nil}) do nil end def get_client_ip(%{remote_ip: remote_ip}) do remote_ip |> :inet.ntoa() |> List.to_string() end end