Packages
timber
1.1.15
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"}]
req_body = "{\"example\": \"payload\"}"
# Log the outgoing request
{req_event, req_message} = Timber.Events.HTTPClientRequestEvent.new_with_message(method: req_method, url: req_url, headers: req_headers, body: req_body)
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
time_ms = Timber.duration_ms(timer)
{resp_event, resp_message} = Timber.Events.HTTPClientResponseEvent.new(headers: headers, body: body, status: status, time_ms: time_ms)
Logger.info resp_message, event: resp_event
```
"""
alias Timber.Utils.HTTPEvents, as: UtilsHTTPEvents
@enforce_keys [:host, :method, :path, :scheme]
defstruct [:body, :headers, :host, :method, :path, :port, :query_string, :request_id, :scheme,
:service_name]
@type t :: %__MODULE__{
body: String.t | nil,
headers: map | nil,
host: String.t,
method: String.t,
path: String.t,
port: pos_integer | nil,
query_string: String.t | nil,
request_id: String.t | nil,
scheme: String.t,
service_name: String.t | nil
}
@doc """
Builds a new struct taking care to:
* Parsing the `:url` and mapping it to the appropriate attributes.
* Truncate the body if it is too large.
* Normalize header values so they are consistent.
* Normalize the method.
* Removes "" or nil values.
"""
@spec new(Keyword.t) :: t
def new(opts) do
opts =
opts
|> Keyword.update(:body, nil, fn body -> UtilsHTTPEvents.normalize_body(body) end)
|> Keyword.update(:headers, nil, fn headers -> UtilsHTTPEvents.normalize_headers(headers) end)
|> Keyword.update(:method, nil, &UtilsHTTPEvents.normalize_method/1)
|> Keyword.update(:service_name, nil, &UtilsHTTPEvents.try_atom_to_string/1)
|> Keyword.merge(UtilsHTTPEvents.normalize_url(Keyword.get(opts, :url)))
|> Keyword.delete(:url)
|> Enum.filter(fn {_k,v} -> !(v in [nil, ""]) end)
opts = Keyword.put_new_lazy(opts, :request_id, fn -> UtilsHTTPEvents.get_request_id_from_headers(opts[:headers]) 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__{host: host, method: method, path: path, port: port,
query_string: query_string, scheme: scheme, service_name: service_name})
do
message = ["Outgoing HTTP request to "]
if service_name,
do: [message, service_name, " [", method, "] ", UtilsHTTPEvents.full_path(path, query_string)],
else: [message, "[", method, "] ", UtilsHTTPEvents.full_url(scheme, host, path, port, query_string)]
end
end