Packages
timber
1.0.5
3.1.2
3.1.1
3.1.0
3.0.0
3.0.0-alpha.3
3.0.0-alpha.2
3.0.0-alpha.1
2.8.4
2.8.3
2.8.2
2.8.1
2.8.0
2.7.0
2.6.1
2.6.0
2.5.6
2.5.5
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.4.5
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.4
2.3.3
2.3.1
2.3.0
2.2.1
2.2.0
2.1.8
2.1.7
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.2
2.0.1
2.0.0
2.0.0-rc7
2.0.0-rc6
2.0.0-rc5
2.0.0-rc4
2.0.0-rc3
2.0.0-rc2
2.0.0-rc1
1.1.18
1.1.17
1.1.16
1.1.15
1.1.14
1.1.13
1.1.12
1.1.11
1.1.10
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.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
🌲 Great Elixir Logging Made Easy. Official Timber.io Integration.
Current section
Files
Jump to
Current section
Files
lib/timber/events/http_client_request_event.ex
defmodule Timber.Events.HTTPClientRequestEvent do
@moduledoc """
The `HTTPClientRequestEvent` tracks *outgoing* HTTP requests giving you structured insight
into communication with external services.
This event is HTTP client agnostic, use it with your HTTP client of choice.
## Hackney Example
```elixir
req_method = :get
req_url = "https://some.api.com/path?query=1"
req_headers = [{"Accept", "application/json"}]
# Log the outgoing request
{req_event, req_message} = Timber.Events.HTTPClientRequestEvent.new_with_message(method: req_method, url: req_url, headers: req_headers)
Logger.info req_message, event: req_event
# Make the request
timer = Timber.Timer.start()
{:ok, status, headers, body} = :hackney.request(req_method, req_url, req_headers, "")
# Log the response
{resp_event, resp_message} = Timber.Events.HTTPClientResponseEvent.new(headers: headers, status: status, timer: timer)
Logger.info resp_message, event: resp_event
```
"""
alias Timber.Utils.HTTP, as: UtilsHTTP
@enforce_keys [:host, :method, :path, :scheme]
defstruct [:headers, :host, :method, :path, :port, :query_string, :scheme, :service_name]
@type t :: %__MODULE__{
headers: headers | nil,
host: String.t,
method: String.t,
path: String.t,
port: pos_integer | nil,
query_string: String.t | nil,
scheme: String.t,
service_name: String.t | nil
}
@type headers :: %{
accept: String.t | nil,
content_type: String.t | nil,
request_id: String.t | nil,
user_agent: String.t | nil
}
@recognized_headers ~w(
accept
content-type
user-agent
x-request-id
)
@doc """
Builds a new struct taking care to normalize data into a valid state. This should
be used, where possible, instead of creating the struct directly.
"""
@spec new(Keyword.t) :: t
def new(opts) do
opts =
opts
|> Keyword.update(:headers, nil, fn headers -> UtilsHTTP.normalize_headers(headers, @recognized_headers) end)
|> Keyword.update(:method, nil, &UtilsHTTP.normalize_method/1)
|> Keyword.update(:service_name, nil, &UtilsHTTP.try_atom_to_string/1)
|> Keyword.merge(UtilsHTTP.normalize_url(Keyword.get(opts, :url)))
|> Keyword.delete(:url)
|> Enum.filter(fn {_k,v} -> v != nil end)
struct!(__MODULE__, opts)
end
@doc """
Convenience methods for creating an event and getting the message at the same time.
"""
@spec new_with_message(Keyword.t) :: {t, IO.chardata}
def new_with_message(opts) do
event = new(opts)
{event, message(event)}
end
@doc """
Message to be used when logging. The format looks like:
Outgoing HTTP request to :service_name [GET] /path, ID: :request_id
Taking care to format the string properly if optional attributes like `:service_name` and
`:request_id` are not present.
"""
@spec message(t) :: IO.chardata
def message(%__MODULE__{headers: headers, host: host, method: method,
path: path, port: port, query_string: query_string, scheme: scheme, service_name: service_name})
do
message = ["Outgoing HTTP request to "]
message = if service_name,
do: [message, service_name, " [", method, "] ", UtilsHTTP.full_path(path, query_string)],
else: [message, "[", method, "] ", UtilsHTTP.full_url(scheme, host, path, port, query_string)]
request_id = Map.get(headers || %{}, :request_id)
message = if request_id,
do: [message, ", ID ", request_id],
else: message
message
end
end