Packages
appsignal
1.8.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/mix/tasks/appsignal.diagnose.ex
defmodule Mix.Tasks.Appsignal.Diagnose do
use Mix.Task
alias Appsignal.Config
alias Appsignal.Diagnose
@system Application.get_env(:appsignal, :appsignal_system, Appsignal.System)
@report Application.get_env(:appsignal, :appsignal_diagnose_report, Appsignal.Diagnose.Report)
@shortdoc "Starts and tests AppSignal while validating the configuration."
def run(args) do
send_report =
cond do
is_nil(args) -> nil
Enum.member?(args, "--send-report") -> :send_report
Enum.member?(args, "--no-send-report") -> :no_send_report
true -> nil
end
Application.load(:appsignal)
report = %{process: %{uid: @system.uid}}
configure_appsignal()
config = Application.get_env(:appsignal, :config)
header()
empty_line()
library_report = Diagnose.Library.info()
report = Map.put(report, :library, library_report)
print_library_info(library_report)
empty_line()
host_report = Diagnose.Host.info()
report = Map.put(report, :host, host_report)
print_host_information(host_report)
empty_line()
report =
case Diagnose.Agent.report() do
{:ok, agent_report} ->
print_agent_diagnostics(agent_report)
Map.put(report, :agent, agent_report)
{:error, :nif_not_loaded} ->
IO.puts("Agent diagnostics")
IO.puts(" Error: Nif not loaded, aborting.\n")
report
{:error, raw_report} ->
IO.puts("Agent diagnostics")
IO.puts(" Error: Could not parse the agent report:")
IO.puts(" Output: #{raw_report}\n")
Map.put(report, :agent, %{output: raw_report})
end
report = Map.put(report, :config, config)
print_configuration(config)
empty_line()
validation_report = Diagnose.Validation.validate(config)
report = Map.put(report, :validation, validation_report)
print_validation(validation_report)
empty_line()
path_report = Diagnose.Paths.info(config)
report = Map.put(report, :paths, path_report)
print_paths(path_report)
empty_line()
logs = Diagnose.Logs.info()
report = Map.put(report, :logs, logs)
print_logs(logs)
send_report_to_appsignal_if_agreed_upon(config, report, send_report)
end
defp header do
IO.puts("AppSignal diagnose")
IO.puts(String.duplicate("=", 80))
IO.puts("Use this information to debug your configuration.")
IO.puts("More information is available on the documentation site.")
IO.puts("http://docs.appsignal.com/")
IO.puts("Send this output to support@appsignal.com if you need help.")
IO.puts(String.duplicate("=", 80))
end
defp print_library_info(library_report) do
IO.puts("AppSignal agent")
IO.puts(" Language: Elixir")
IO.puts(" Package version: #{library_report[:package_version]}")
IO.puts(" Agent version: #{library_report[:agent_version]}")
IO.puts(" Agent architecture: #{library_report[:agent_architecture]}")
IO.puts(" Nif loaded: #{yes_or_no(library_report[:extension_loaded])}")
end
defp print_host_information(host_report) do
IO.puts("Host information")
IO.puts(" Architecture: #{host_report[:architecture]}")
IO.puts(" Elixir version: #{host_report[:language_version]}")
IO.puts(" OTP version: #{host_report[:otp_version]}")
root_user = if host_report[:root], do: "yes (not recommended)", else: "no"
IO.puts(" root user: #{root_user}")
if host_report[:heroku] do
IO.puts(" Heroku: yes")
end
IO.puts(" Container: #{yes_or_no(host_report[:running_in_container])}")
end
defp configure_appsignal do
Config.initialize()
Config.write_to_environment()
end
defp print_agent_diagnostics(report) do
Diagnose.Agent.print(report)
end
defp print_configuration(config) do
IO.puts("Configuration")
Enum.each(config, &print_configuration_option/1)
end
defp print_configuration_option({key, value}) when is_list(value) do
IO.puts(" #{key}: #{Enum.join(value, ", ")}")
end
defp print_configuration_option({key, value}) do
IO.puts(" #{key}: #{value}")
end
defp print_validation(validation_report) do
IO.puts("Validation")
IO.puts(" Push API key: #{validation_report[:push_api_key]}")
end
defp print_paths(path_report) do
IO.puts("Paths")
Enum.each(path_report, fn path ->
print_path(path)
end)
end
defp print_logs(logs) do
IO.puts("Log files")
Enum.each(logs, fn {filename, log} ->
IO.puts(" #{filename}:")
IO.puts(" Path: #{log[:path]}")
case log do
%{exists: false} ->
IO.puts(" File not found.")
%{content: lines} ->
IO.puts(" Contents:")
Enum.each(lines, &IO.puts/1)
end
empty_line()
end)
end
defp print_path({name, path}) do
IO.puts(" #{name}: #{path[:path]}")
if path[:exists] do
IO.puts(" - Writable?: #{yes_or_no(path[:writable])}")
file_uid = path[:ownership][:uid]
process_uid = @system.uid
IO.write(" - Ownership?: #{yes_or_no(file_uid == process_uid)}")
IO.puts(" (file: #{file_uid}, process: #{process_uid})")
else
IO.puts(" - Exists?: no")
end
if path[:error], do: IO.puts(" - Error: #{path[:error]}")
end
defp send_report_to_appsignal_if_agreed_upon(config, report, send_report) do
IO.puts("\nDiagnostics report")
IO.puts(" Do you want to send this diagnostics report to AppSignal?")
IO.puts(
" If you share this diagnostics report you will be given\n" <>
" a support token you can use to refer to your diagnotics \n" <>
" report when you contact us at support@appsignal.com\n"
)
answer =
case send_report do
:send_report ->
IO.puts(" Confirmed sending report using --send-report option.")
true
:no_send_report ->
IO.puts(" Not sending report. (Specified with the --no-send-report option.)")
false
_ ->
yes_or_no?(" Send diagnostics report to AppSignal? (Y/n): ")
end
case answer do
true ->
IO.puts("\n Transmitting diagnostics report")
send_report_to_appsignal(config, report)
false ->
IO.puts(" Not sending diagnostics report to AppSignal.")
end
end
def send_report_to_appsignal(config, report) do
case @report.send(config, report) do
{:ok, support_token} ->
IO.puts(" Your diagnostics report has been sent to AppSignal.")
IO.puts(" Your support token: #{support_token}")
{:error, %{status_code: 200, body: body}} ->
IO.puts(" Error: Couldn't decode server response.")
IO.puts(" Response body: #{body}")
{:error, %{status_code: status_code, body: body}} ->
IO.puts(" Error: Something went wrong while submitting the report to AppSignal.")
IO.puts(" Response code: #{status_code}")
IO.puts(" Response body: #{body}")
{:error, %{reason: reason}} ->
IO.puts(" Error: Something went wrong while submitting the report to AppSignal.")
IO.puts(reason)
end
end
defp empty_line, do: IO.puts("")
defp yes_or_no(true), do: "yes"
defp yes_or_no(false), do: "no"
# Ask for a yes or no input from the user
defp yes_or_no?(prompt) do
case IO.gets(prompt) do
input when is_binary(input) ->
case String.downcase(String.trim(input)) do
input when input in ["y", "yes", ""] -> true
input when input in ["n", "no"] -> false
_ -> yes_or_no?(prompt)
end
:eof ->
yes_or_no?(prompt)
{:error, reason} ->
IO.puts(" Error while reading input: #{reason}")
yes_or_no?(prompt)
end
end
end