Packages
appsignal
1.4.9
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
mix_helpers.exs
defmodule Mix.Appsignal.Helper do
@moduledoc """
Helper functions for downloading and compiling the AppSignal agent library.
"""
require Logger
@max_retries 5
def verify_system_architecture() do
input_arch = :erlang.system_info(:system_architecture)
platform = Appsignal.System.agent_platform
map_arch(input_arch, 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.rm_rf!(priv_dir())
File.mkdir_p!(priv_dir())
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.rm_rf!(priv_dir())
File.mkdir_p!(priv_dir())
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
download_file(url, version)
|> verify_checksum(checksum)
|> extract
end
defp download_file(url, version) do
filename = Path.join(tmp_dir(), "appsignal-agent-#{version}.tar.gz")
case File.exists?(filename) do
true ->
filename
false ->
Logger.info "Downloading agent release from #{url}"
case System.find_executable("curl") do
nil ->
raise Mix.Error, message: """
Could not find the curl executable. Please make sure curl is
installed on this system as it is needed to download the AppSignal
extension and agent.
"""
_ ->
case System.cmd("curl", ["-s", "-S", "--retry", Integer.to_string(@max_retries), "-f", "-o", filename, url], stderr_to_stdout: true) do
{_, 0} ->
filename
{result, exitcode} ->
IO.binwrite(result)
raise Mix.Error, message: """
Download failed with code #{exitcode}
"""
end
end
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_dir(), do: Appsignal.System.priv_dir
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
end