-
Notifications
You must be signed in to change notification settings - Fork 592
/
Copy pathrequest_id.ex
63 lines (47 loc) · 1.94 KB
/
request_id.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
defmodule Plug.RequestId do
@moduledoc """
A plug for generating a unique request id for each request. A generated
request id will in the format "uq8hs30oafhj5vve8ji5pmp7mtopc08f".
If a request id already exists as the "x-request-id" HTTP request header,
then that value will be used assuming it is between 20 and 200 characters.
If it is not, a new request id will be generated.
The request id is added to the Logger metadata as `:request_id` and the response as
the "x-request-id" HTTP header. To see the request id in your log output,
configure your logger backends to include the `:request_id` metadata:
config :logger, :console, metadata: [:request_id]
It is recommended to include this metadata configuration in your production
configuration file.
To use it, 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"
"""
require Logger
alias Plug.Conn
@behaviour Plug
def init(opts) do
Keyword.get(opts, :http_header, "x-request-id")
end
def call(conn, req_id_header) do
conn
|> get_request_id(req_id_header)
|> set_request_id(req_id_header)
end
defp get_request_id(conn, header) do
case Conn.get_req_header(conn, header) do
[] -> {conn, generate_request_id()}
[val|_] -> if valid_request_id?(val), do: {conn, val}, else: {conn, generate_request_id()}
end
end
defp set_request_id({conn, request_id}, header) do
Logger.metadata(request_id: request_id)
Conn.put_resp_header(conn, header, request_id)
end
defp generate_request_id do
Base.hex_encode32(:crypto.strong_rand_bytes(20), case: :lower)
end
defp valid_request_id?(s), do: byte_size(s) in 20..200
end