Packages
appsignal
1.1.1
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/config.ex
defmodule Appsignal.Config do
@system Application.get_env(:appsignal, :appsignal_system, Appsignal.System)
@default_config %{
active: false,
debug: false,
enable_host_metrics: true,
endpoint: "https://push.appsignal.com",
env: :dev,
filter_parameters: nil,
ignore_actions: [],
ignore_errors: [],
send_params: true,
skip_session_data: false,
log: "file"
}
@doc """
Initializes the AppSignal config. Looks at the config default, the
Elixir-provided configuration and the various `APPSIGNAL_*`
OS environment variables. Returns whether or not the configuration is valid.
"""
@spec initialize() :: :ok | {:error, :invalid_config}
def initialize() do
system_config = load_from_system()
app_config = Application.get_env(:appsignal, :config, []) |> coerce_map
env_config = load_from_environment()
config = @default_config
|> Map.merge(system_config)
|> Map.merge(app_config)
|> Map.merge(env_config)
config = config
# Config is valid when we have a push api key
|> Map.put(:valid, !empty?(config[:push_api_key]))
Application.put_env(:appsignal, :config, config)
case config[:valid] do
true ->
:ok
false ->
{:error, :invalid_config}
end
end
@doc """
Returns whether the AppSignal agent is configured to start on application launch.
"""
@spec active?() :: boolean
def active? do
config = Application.fetch_env!(:appsignal, :config)
config.valid && config.active
end
@env_to_key_mapping %{
"APPSIGNAL_ACTIVE" => :active,
"APPSIGNAL_PUSH_API_KEY" => :push_api_key,
"APPSIGNAL_APP_NAME" => :name,
"APPSIGNAL_APP_ENV" => :env,
"APPSIGNAL_CA_FILE_PATH" => :ca_file_path,
"APPSIGNAL_PUSH_API_ENDPOINT" => :endpoint,
"APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH" => :frontend_error_catching_path,
"APPSIGNAL_HOSTNAME" => :hostname,
"APPSIGNAL_FILTER_PARAMETERS" => :filter_parameters,
"APPSIGNAL_DEBUG" => :debug,
"APPSIGNAL_LOG" => :log,
"APPSIGNAL_LOG_PATH" => :log_path,
"APPSIGNAL_IGNORE_ERRORS" => :ignore_errors,
"APPSIGNAL_IGNORE_ACTIONS" => :ignore_actions,
"APPSIGNAL_HTTP_PROXY" => :http_proxy,
"APPSIGNAL_RUNNING_IN_CONTAINER" => :running_in_container,
"APPSIGNAL_WORKING_DIR_PATH" => :working_dir_path,
"APPSIGNAL_ENABLE_HOST_METRICS" => :enable_host_metrics,
"APPSIGNAL_SKIP_SESSION_DATA" => :skip_session_data
}
@string_keys ~w(APPSIGNAL_APP_NAME APPSIGNAL_PUSH_API_KEY APPSIGNAL_PUSH_API_ENDPOINT APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HOSTNAME APPSIGNAL_HTTP_PROXY APPSIGNAL_LOG APPSIGNAL_LOG_PATH APPSIGNAL_WORKING_DIR_PATH APPSIGNAL_CA_FILE_PATH)
@bool_keys ~w(APPSIGNAL_ACTIVE APPSIGNAL_DEBUG APPSIGNAL_INSTRUMENT_NET_HTTP APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING APPSIGNAL_ENABLE_ALLOCATION_TRACKING APPSIGNAL_ENABLE_GC_INSTRUMENTATION APPSIGNAL_RUNNING_IN_CONTAINER APPSIGNAL_ENABLE_HOST_METRICS APPSIGNAL_SKIP_SESSION_DATA)
@atom_keys ~w(APPSIGNAL_APP_ENV)
@string_list_keys ~w(APPSIGNAL_FILTER_PARAMETERS APPSIGNAL_IGNORE_ACTIONS APPSIGNAL_IGNORE_ERRORS)
defp load_environment(config, list, converter) do
list |> Enum.reduce(
config,
fn(key, cfg) ->
value = System.get_env(key)
if !empty?(value) do
Map.put(cfg, @env_to_key_mapping[key], converter.(value))
else
cfg
end
end)
end
defp load_from_system() do
config = %{hostname: @system.hostname_with_domain}
# Make AppSignal active by default if the APPSIGNAL_PUSH_API_KEY
# environment variable is present.
# Is overwritten by application config and env config.
config = case System.get_env("APPSIGNAL_PUSH_API_KEY") do
nil -> config
_ -> Map.merge(config, %{active: true})
end
# Detect Heroku
case Appsignal.System.heroku? do
false -> config
true -> Map.merge(config, %{running_in_container: true, log: "stdout"})
end
end
defp load_from_environment() do
%{}
|> load_environment(@string_keys, &(&1))
|> load_environment(@bool_keys, &(true?(&1)))
|> load_environment(@atom_keys, &(String.to_atom(&1)))
|> load_environment(@string_list_keys, &(String.split(&1, ",")))
end
defp coerce_map(value) when is_list(value) do
value |> Enum.into(%{})
end
defp coerce_map(%{} = value) do
value
end
defp empty?(nil), do: true
defp empty?(""), do: true
defp empty?(_), do: false
defp true?("true"), do: true
defp true?(true), do: true
defp true?(_), do: false
@agent_version Appsignal.Agent.version
@language_integration_version Mix.Project.config[:version]
@doc """
Write the currently known AppSignal configuration to the system environment.
Must be run before starting the AppSignal agent otherwise it won't know the
correct configuration.
## Example
case {Appsignal.Config.initialize, Appsignal.Config.active?} do
{:ok, true} ->
Appsignal.Config.write_to_environment
Appsignal.Nif.start
{:ok, false} ->
# AppSignal not active
{{:error, :invalid_config}, _} ->
# AppSignal has invalid config
end
"""
def write_to_environment do
config = Application.get_env(:appsignal, :config)
write_to_environment(config)
end
defp write_to_environment(config) do
reset_environment_config!()
System.put_env("_APPSIGNAL_ACTIVE", Atom.to_string(config[:active]))
System.put_env("_APPSIGNAL_AGENT_PATH", List.to_string(:code.priv_dir(:appsignal)))
System.put_env("_APPSIGNAL_AGENT_VERSION", @agent_version)
System.put_env("_APPSIGNAL_APP_PATH", List.to_string(:code.priv_dir(:appsignal))) # FIXME - app_path should not be necessary
unless empty?(config[:name]) do
System.put_env("_APPSIGNAL_APP_NAME", app_name_to_string(config[:name]))
end
unless empty?(config[:ca_file_path]) do
System.put_env("_APPSIGNAL_CA_FILE_PATH", config[:ca_file_path])
end
System.put_env("_APPSIGNAL_DEBUG_LOGGING", Atom.to_string(config[:debug]))
System.put_env("_APPSIGNAL_ENABLE_HOST_METRICS", Atom.to_string(config[:enable_host_metrics]))
System.put_env("_APPSIGNAL_ENVIRONMENT", Atom.to_string(config[:env]))
unless empty?(config[:filter_parameters]) do
System.put_env("_APPSIGNAL_FILTER_PARAMETERS", config[:filter_parameters] |> Enum.join(","))
end
System.put_env("_APPSIGNAL_HOSTNAME", config[:hostname])
unless empty?(config[:http_proxy]) do
System.put_env("_APPSIGNAL_HTTP_PROXY", config[:http_proxy])
end
System.put_env("_APPSIGNAL_IGNORE_ACTIONS", config[:ignore_actions] |> Enum.join(","))
System.put_env("_APPSIGNAL_IGNORE_ERRORS", config[:ignore_errors] |> Enum.join(","))
System.put_env("_APPSIGNAL_LANGUAGE_INTEGRATION_VERSION", "elixir-" <> @language_integration_version)
System.put_env("_APPSIGNAL_LOG", config[:log])
unless empty?(config[:log_path]) do
System.put_env("_APPSIGNAL_LOG_FILE_PATH", config[:log_path])
end
System.put_env("_APPSIGNAL_PUSH_API_ENDPOINT", config[:endpoint] || "")
System.put_env("_APPSIGNAL_PUSH_API_KEY", config[:push_api_key] || "")
unless empty?(config[:running_in_container]) do
System.put_env("_APPSIGNAL_RUNNING_IN_CONTAINER", Atom.to_string(config[:running_in_container]))
end
System.put_env("_APPSIGNAL_SEND_PARAMS", Atom.to_string(config[:send_params]))
unless empty?(config[:working_dir_path]) do
System.put_env("_APPSIGNAL_WORKING_DIR_PATH", config[:working_dir_path])
end
end
@doc """
Reset the config written to the environment by `write_to_environment/1`.
This makes sure no existing config gets reused and the configuration for the
agent gets set again.
"""
def reset_environment_config! do
System.get_env
|> Enum.filter(
fn({"_APPSIGNAL_" <> _, _}) -> true;
(_) -> false end
) |> Enum.each(fn({key, _}) ->
System.delete_env(key)
end)
end
defp app_name_to_string(name) when is_atom(name), do: Atom.to_string(name)
defp app_name_to_string(name) when is_binary(name), do: name
def get_system_env do
System.get_env
|> Enum.filter(
fn({"APPSIGNAL_" <> _, _}) -> true;
(_) -> false end)
|> Enum.into(%{})
end
# When you use Appsignal.Config you get a handy config macro which
# can be used to read the application config.
defmacro __using__(_) do
quote do
defmacro config do
quote do
Application.get_env(:appsignal, :config, [])
end
end
end
end
end