Packages
plug
1.20.3
1.20.3
1.20.2
1.20.1
retired
1.20.0
retired
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.15.6
1.15.5
1.15.4
1.15.3
1.15.2
1.15.1
1.15.0
1.14.2
1.14.1
1.14.0
1.13.6
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
retired
1.13.0
retired
1.12.1
1.12.0
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.2
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.0
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.14.0
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
Compose web applications with functions
Current section
Files
Jump to
Current section
Files
lib/plug/request_id.ex
defmodule Plug.RequestId do
@moduledoc """
A plug for generating a unique request ID for each request.
The generated request ID will be in the format:
```
GEBMr97eLMHtGWsAAAVj
```
If a request ID already exists in a configured HTTP request header (see options below),
then this plug will use that value, *assuming it is between 20 and 200 characters*.
If such header is not present, this plug will generate a new request ID.
The request ID is added to the `Logger` metadata as `:request_id`, and to the
response as the configured HTTP response header (see options below). To see the
request ID in your log output, configure your logger formatter to include the `:request_id`
metadata. For example:
config :logger, :default_formatter, metadata: [:request_id]
We recommend to include this metadata configuration in your production
configuration file.
> #### Programmatic access to the request ID {: .tip}
>
> To access the request ID programmatically, use the `:assign_as` option (see below)
> to assign the request ID to a key in `conn.assigns`, and then fetch it from there.
## Usage
To use this plug, just plug it into the desired module:
plug Plug.RequestId
## Options
* `:http_header` - The name of the HTTP *request* header to check for
existing request IDs. This is also the HTTP *response* header that will be
set with the request id. Default value is `"x-request-id"`.
plug Plug.RequestId, http_header: "custom-request-id"
* `:assign_as` - The name of the key that will be used to store the
discovered or generated request id in `conn.assigns`. If not provided,
the request id will not be stored. *Available since v1.16.0*.
plug Plug.RequestId, assign_as: :plug_request_id
* `:logger_metadata_key` - The name of the key that will be used to store the
discovered or generated request id in `Logger` metadata. If not provided,
the request ID Logger metadata will be stored as `:request_id`. *Available
since v1.18.0*.
plug Plug.RequestId, logger_metadata_key: :my_request_id
* `:generator` - The function used to generate the request ID, defaults to
`Plug.RequestId.generate/0`. When setting up a custom function, it is recommended
to be in the `&MyApp.custom_request_id/0` format, so it can be stored at compile-time.
The generated value must also have size between 20 and 200 bytes.
plug Plug.RequestId, generator: &MyApp.custom_request_id/0
"""
alias Plug.Conn
@behaviour Plug
@impl true
def init(opts) do
{
Keyword.get(opts, :http_header, "x-request-id"),
Keyword.get(opts, :assign_as),
Keyword.get(opts, :logger_metadata_key, :request_id),
Keyword.get(opts, :generator, &__MODULE__.generate/0)
}
end
@impl true
def call(conn, {header, assign_as, logger_metadata_key, generator}) do
request_id = get_request_id(conn, header, generator)
Logger.metadata([{logger_metadata_key, request_id}])
conn = if assign_as, do: Conn.assign(conn, assign_as, request_id), else: conn
Conn.put_resp_header(conn, header, request_id)
end
defp get_request_id(conn, header, generator) do
case Conn.get_req_header(conn, header) do
[val | _] when byte_size(val) in 20..200 -> val
_ -> generator.()
end
end
@doc """
Generates a random Base64 encoded request ID.
"""
@spec generate :: binary()
def generate do
binary = <<
System.system_time(:nanosecond)::64,
:erlang.phash2({node(), self()}, 16_777_216)::24,
:erlang.unique_integer()::32
>>
Base.url_encode64(binary)
end
end