zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

request_id.ex (2382B)


      1 defmodule Plug.RequestId do
      2   @moduledoc """
      3   A plug for generating a unique request id for each request.
      4 
      5   The generated request id will be in the format "uq8hs30oafhj5vve8ji5pmp7mtopc08f".
      6 
      7   If a request id already exists as the "x-request-id" HTTP request header,
      8   then that value will be used assuming it is between 20 and 200 characters.
      9   If it is not, a new request id will be generated.
     10 
     11   The request id is added to the Logger metadata as `:request_id` and the response as
     12   the "x-request-id" HTTP header. To see the request id in your log output,
     13   configure your logger backends to include the `:request_id` metadata:
     14 
     15       config :logger, :console, metadata: [:request_id]
     16 
     17   It is recommended to include this metadata configuration in your production
     18   configuration file.
     19 
     20   You can also access the `request_id` programmatically by calling
     21   `Logger.metadata[:request_id]`. Do not access it via the request header, as
     22   the request header value has not been validated and it may not always be
     23   present.
     24 
     25   To use this plug, just plug it into the desired module:
     26 
     27       plug Plug.RequestId
     28 
     29   ## Options
     30 
     31     * `:http_header` - The name of the HTTP *request* header to check for
     32       existing request ids. This is also the HTTP *response* header that will be
     33       set with the request id. Default value is "x-request-id"
     34 
     35           plug Plug.RequestId, http_header: "custom-request-id"
     36 
     37   """
     38 
     39   require Logger
     40   alias Plug.Conn
     41   @behaviour Plug
     42 
     43   @impl true
     44   def init(opts) do
     45     Keyword.get(opts, :http_header, "x-request-id")
     46   end
     47 
     48   @impl true
     49   def call(conn, req_id_header) do
     50     conn
     51     |> get_request_id(req_id_header)
     52     |> set_request_id(req_id_header)
     53   end
     54 
     55   defp get_request_id(conn, header) do
     56     case Conn.get_req_header(conn, header) do
     57       [] -> {conn, generate_request_id()}
     58       [val | _] -> if valid_request_id?(val), do: {conn, val}, else: {conn, generate_request_id()}
     59     end
     60   end
     61 
     62   defp set_request_id({conn, request_id}, header) do
     63     Logger.metadata(request_id: request_id)
     64     Conn.put_resp_header(conn, header, request_id)
     65   end
     66 
     67   defp generate_request_id do
     68     binary = <<
     69       System.system_time(:nanosecond)::64,
     70       :erlang.phash2({node(), self()}, 16_777_216)::24,
     71       :erlang.unique_integer()::32
     72     >>
     73 
     74     Base.url_encode64(binary)
     75   end
     76 
     77   defp valid_request_id?(s), do: byte_size(s) in 20..200
     78 end