Packages

appsignal

1.7.0-beta.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
appsignal mix_helpers.exs
Raw

mix_helpers.exs

{_, _} = Code.eval_file("agent.exs")
defmodule Mix.Appsignal.Helper do
@moduledoc """
Helper functions for downloading and compiling the AppSignal agent library.
"""
@os Application.get_env(:appsignal, :os, :os)
require Logger
@max_retries 5
def verify_system_architecture() do
input_arch = :erlang.system_info(:system_architecture)
map_arch(input_arch, agent_platform())
end
def ensure_downloaded(arch) do
arch_config = Appsignal.Agent.triples[arch]
System.put_env("LIB_DIR", priv_dir())
if has_local_release_files?() do
IO.puts "AppSignal: Using local agent release."
File.mkdir_p!(priv_dir())
clean_up_extension_files()
Enum.each(["appsignal.h", "appsignal-agent", "appsignal.version", "libappsignal.a"], fn(file) ->
File.cp(project_ext_path(file), priv_path(file))
end)
else
if has_files?() and has_correct_agent_version?() do
:ok
else
if is_nil(arch_config) do
raise Mix.Error, message: """
No config found for architecture '#{arch}'.
Please check http://docs.appsignal.com/support/operating-systems.html
And inform us about this error at support@appsignal.com
"""
end
version = Appsignal.Agent.version
File.mkdir_p!(priv_dir())
clean_up_extension_files()
try do
download_and_extract(arch_config[:download_url], version, arch_config[:checksum])
catch
{:checksum_mismatch, filename, _, _} ->
File.rm!(filename)
try do
download_and_extract(arch_config[:download_url], version, arch_config[:checksum])
catch
{:checksum_mismatch, filename, calculated, expected} ->
raise Mix.Error, message: """
Checksum verification of #{filename} failed!
Calculated: #{calculated}
Expected: #{expected}
"""
end
end
end
end
end
def store_architecture(arch) do
File.mkdir_p!(priv_dir())
case File.open priv_path("appsignal.architecture"), [:write] do
{:ok, file} ->
result = IO.binwrite(file, arch)
File.close(file)
result
{:error, reason} -> {:error, reason}
end
end
defp download_and_extract(url, version, checksum) do
case download_file(url, version) do
{:ok, filename} ->
filename
|> verify_checksum(checksum)
|> extract
error ->
error
end
end
defp download_file(url, version) do
filename = Path.join(tmp_dir(), "appsignal-agent-#{version}.tar.gz")
case File.exists?(filename) do
true ->
{:ok, filename}
false ->
Logger.info("Downloading agent release from #{url}")
:application.ensure_all_started(:hackney)
case do_download_file!(url, filename, @max_retries) do
:ok -> {:ok, filename}
error -> error
end
end
end
defp do_download_file!(url, filename, retries \\ 0)
defp do_download_file!(url, filename, 0) do
case :hackney.request(:get, url) do
{:ok, 200, _, reference} ->
case :hackney.body(reference) do
{:ok, body} -> File.write(filename, body)
{:error, reason} -> {:error, reason}
end
response ->
{:error, response}
end
end
defp do_download_file!(url, filename, retries) do
case do_download_file!(url, filename) do
:ok -> :ok
_ -> do_download_file!(url, filename, retries - 1)
end
end
defp verify_checksum(filename, expected) do
data = File.read!(filename)
calculated = :crypto.hash(:sha256, data) |> Base.encode16(case: :lower)
if calculated != expected do
throw {:checksum_mismatch, filename, calculated, expected}
end
filename
end
defp extract(filename) do
case System.cmd("tar", ["zxf", filename, "--no-same-owner"], stderr_to_stdout: true, cd: priv_dir()) do
{_, 0} ->
:ok
{result, _exitcode} ->
IO.binwrite(result)
raise Mix.Error, message: """
Extracting of #{filename} failed!
"""
end
end
def compile do
{result, error_code} = System.cmd("make", make_args(to_string(Mix.env)))
IO.binwrite(result)
if error_code != 0 do
raise Mix.Error, message: """
Could not run `make`. Please check if `make` and either `clang` or `gcc` are installed
"""
end
:ok
end
defp make_args("test" <> _), do: ["-e", "CFLAGS_ADD=-DTEST"]
defp make_args(_), do: []
if Mix.env != :test_no_nif do
defp map_arch('i386-' ++ _, platform), do: build_for("i686", platform)
defp map_arch('i686-' ++ _, platform), do: build_for("i686", platform)
defp map_arch('x86-' ++ _, platform), do: build_for("i686", platform)
defp map_arch('amd64-' ++ _, platform), do: build_for("x86_64", platform)
defp map_arch('x86_64-' ++ _, platform), do: build_for("x86_64", platform)
end
defp map_arch(arch, platform), do: {:error, {:unknown, {arch, platform}}}
defp build_for(bit, platform) do
arch = "#{bit}-#{platform}"
case Map.has_key?(Appsignal.Agent.triples, arch) do
true -> {:ok, arch}
false -> {:error, {:unsupported, arch}}
end
end
defp tmp_dir do
default_tmp_dir = "/tmp"
case {File.dir?(default_tmp_dir), File.stat(default_tmp_dir)} do
{true, {:ok, %{access: :write}}} -> default_tmp_dir
{true, {:ok, %{access: :read_write}}} -> default_tmp_dir
_ -> System.tmp_dir!
end
end
defp priv_path(filename) do
Path.join(priv_dir(), filename)
end
defp project_ext_path(filename) do
Path.join([__DIR__, "c_src", filename])
end
defp has_file(filename) do
filename |> priv_path |> File.exists?
end
defp has_local_ext_file(filename) do
filename |> project_ext_path |> File.exists?
end
defp has_files? do
has_file("appsignal-agent") and
has_file("appsignal.h") and
has_file("appsignal_extension.so")
end
defp has_local_release_files? do
has_local_ext_file("appsignal-agent") and
has_local_ext_file("appsignal.h") and
has_local_ext_file("libappsignal.a")
end
defp has_correct_agent_version? do
path = priv_path("appsignal.version")
File.read(path) == {:ok, "#{Appsignal.Agent.version}\n"}
end
defp clean_up_extension_files do
priv_dir()
|> Path.join("*appsignal*")
|> Path.wildcard
|> Enum.each(&File.rm_rf!/1)
end
def agent_platform do
case force_musl_build?() do
true -> "linux-musl"
false ->
case @os.type do
{:unix, :linux} ->
agent_platform_by_ldd_version()
{_, os} ->
to_string(os)
end
end
end
def priv_dir() do
case :code.priv_dir(:appsignal) do
{:error, :bad_name} ->
# This happens on initial compilation
Mix.Tasks.Compile.Erlang.manifests
|> List.first
|> Path.dirname
|> String.trim_trailing(".mix")
|> Path.join("priv")
path ->
path
|> List.to_string
end
end
defp agent_platform_by_ldd_version do
try do
{output, _} = System.cmd("ldd", ["--version"], stderr_to_stdout: true)
case String.contains?(output, "musl") do
true -> "linux-musl"
false ->
ldd_version = List.first(Regex.run(~r/\d+\.\d+/, output))
case Version.compare("#{ldd_version}.0", "2.15.0") do
:lt -> "linux-musl"
_ -> "linux"
end
end
rescue
_ -> "linux"
end
end
defp force_musl_build? do
!is_nil(System.get_env("APPSIGNAL_BUILD_FOR_MUSL"))
end
end