Packages
appsignal
2.17.2
2.17.4
2.17.3
2.17.2
2.17.1
2.17.0
2.16.0
2.15.11
2.15.10
2.15.9
2.15.8
2.15.7
2.15.6
2.15.5
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.1
2.14.0
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.12.3
2.12.2
2.12.1
2.12.0
2.11.0
2.10.2
2.10.1
2.10.0
2.9.2
2.9.1
2.9.0
2.8.3
2.8.2
2.8.1
2.8.0
2.7.13
2.7.12
2.7.11
2.7.10
2.7.9
2.7.8
2.7.7
2.7.6
2.7.5
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.7.0-beta.1
2.6.1
2.6.0
2.5.3
2.5.2
2.5.1
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.1
2.3.0
2.2.19
2.2.18
2.2.17
2.2.16
2.2.15
2.2.14
2.2.13
2.2.12
retired
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.15
2.1.14
2.1.13
2.1.12
2.1.11
2.1.10
2.1.9
2.1.8
2.1.7
2.1.7-beta.1
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.8
2.0.7
2.0.6
2.0.6-beta.1
2.0.5
retired
2.0.4
retired
2.0.3
retired
2.0.2
retired
2.0.1
retired
2.0.0
retired
2.0.0-beta.11
2.0.0-beta.10
2.0.0-beta.9
2.0.0-beta.8
2.0.0-beta.7
2.0.0-beta.6
2.0.0-beta.5
2.0.0-beta.4
2.0.0-beta.3
2.0.0-beta.2
2.0.0-beta.1
2.0.0-alpha.7
2.0.0-alpha.6
2.0.0-alpha.5
2.0.0-alpha.4
2.0.0-alpha.3
2.0.0-alpha.2
2.0.0-alpha.1
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
1.13.0
1.13.0-beta.2
1.13.0-beta.1
1.12.1
1.12.0
1.12.0-beta.3
1.12.0-beta.2
1.12.0-beta.1
1.11.8
1.11.7
1.11.6
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
1.11.0
1.11.0-beta.1
1.10.13
1.10.12
1.10.11
1.10.10
1.10.9
1.10.8
1.10.7
1.10.6
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.4
1.9.3
1.9.2
1.9.1
1.9.1-beta.1
1.9.0
1.9.0-beta.1
1.9.0-alpha.1
1.8.2
1.8.1
1.8.1-beta.2
1.8.1-beta.1
1.8.0
1.7.2
1.7.1
1.7.0
1.7.0-beta.2
1.7.0-beta.1
1.7.0-alpha.4
1.7.0-alpha.3
1.7.0-alpha.2
1.7.0-alpha.1
1.6.7
1.6.6
1.6.6-beta.2
1.6.6-beta.1
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-beta.1
1.6.0-alpha.1
1.5.1
1.5.0
1.5.0-beta.2
1.5.0-beta.1
1.4.11-beta.1
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-alpha.1
1.3.6
1.3.6-beta.1
1.3.5
1.3.4
1.3.4-beta.1
1.3.3
1.3.2
1.3.1
1.3.0
1.3.0-beta.3
1.3.0-beta.2
1.3.0-beta.1
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.1
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.2
0.9.1
0.9.0
0.8.0
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Collects error and performance data from your Elixir applications and sends it to AppSignal
Current section
Files
Jump to
Current section
Files
lib/appsignal/transmitter.ex
defmodule Appsignal.Transmitter do
@moduledoc false
require Logger
def request_standalone(method, url, headers \\ [], body \\ "") do
:application.ensure_all_started(:telemetry)
http_client = Application.get_env(:appsignal, :http_client, Finch)
name = :"AppsignalFinch_#{:erlang.unique_integer([:positive])}"
{:ok, pid} = Finch.start_link(name: name, pools: %{default: pool_options(url)})
try do
method
|> http_client.build(url, headers, body)
|> http_client.request(name)
after
Process.exit(pid, :normal)
end
end
def request(method, url, headers \\ [], body \\ "") do
http_client = Application.get_env(:appsignal, :http_client, Finch)
method
|> http_client.build(url, headers, body)
|> http_client.request(AppsignalFinch)
end
@doc false
def pool_options(url \\ nil) do
if https?(url) do
case ssl_options() do
[] -> []
ssl_opts -> [conn_opts: [transport_opts: ssl_opts]]
end
else
[]
end
end
defp https?(nil), do: true
defp https?(url), do: String.starts_with?(url, "https://")
def transmit(url, payload_and_format \\ {nil, nil}, config \\ nil)
def transmit(url, nil, config) do
transmit(url, {nil, nil}, config)
end
def transmit(url, {payload, format}, config) do
do_transmit(url, {payload, format}, config, false)
end
def transmit(url, nil, config, standalone) do
transmit(url, {nil, nil}, config, standalone)
end
def transmit(url, {payload, format}, config, standalone) do
do_transmit(url, {payload, format}, config, standalone)
end
def do_transmit(url, {payload, format}, config, standalone) do
config = config || Appsignal.Config.config()
params =
URI.encode_query(%{
api_key: config[:push_api_key],
name: config[:name],
environment: config[:env],
hostname: config[:hostname]
})
url = "#{url}?#{params}"
headers = [{"Content-Type", "application/json; charset=UTF-8"}]
body = encode_body(payload, format)
request_fun = if standalone, do: &request_standalone/4, else: &request/4
request_fun.(:post, url, headers, body)
end
defp encode_body(nil, _), do: ""
defp encode_body(payload, :json), do: Jason.encode!(payload)
defp encode_body(payload, :ndjson) do
payload
|> Enum.map_join("\n", &Jason.encode!/1)
end
defp ssl_options do
ca_file_path = Appsignal.Config.ca_file_path()
result =
case File.stat(ca_file_path) do
{:ok, %{access: access}} when access in [:read, :read_write] ->
{:ok,
[
verify: :verify_peer,
cacertfile: ca_file_path
] ++ tls_options() ++ customize_hostname_check_or_verify_fun()}
{:ok, %{access: access}} ->
{:error, "File access is #{inspect(access)}"}
{:error, reason} ->
{:error, reason}
end
case result do
{:ok, options} ->
options
{:error, message} ->
unless ca_file_path == packaged_ca_file_path() do
Logger.warning(
"Ignoring non-existing or unreadable ca_file_path (#{ca_file_path}): #{inspect(message)}"
)
end
[]
end
end
if System.otp_release() >= "23" do
defp tls_options, do: [versions: :ssl.versions()[:supported]]
else
defp tls_options do
[
depth: 4,
ciphers: ciphers(),
honor_cipher_order: :undefined
]
end
# OTP 21+ is required for Elixir 1.11+, so we always use the new API
defp ciphers, do: :ssl.cipher_suites(:default, :"tlsv1.2")
end
if System.otp_release() >= "21" do
defp customize_hostname_check_or_verify_fun do
[
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
end
else
defp customize_hostname_check_or_verify_fun do
[
verify_fun:
{fn
_, :valid, state -> {:valid, state}
_, :valid_peer, state -> {:valid, state}
_, {:extension, _}, state -> {:unknown, state}
_, reason, _ -> {:fail, reason}
end, self()}
]
end
end
defp packaged_ca_file_path do
Path.join(:code.priv_dir(:appsignal), "cacert.pem")
end
end