diff --git a/lib/appsignal/config.ex b/lib/appsignal/config.ex index d0d411f14..8eb58d80f 100644 --- a/lib/appsignal/config.ex +++ b/lib/appsignal/config.ex @@ -3,13 +3,14 @@ defmodule Appsignal.Config do @default_config %{ debug: false, - ignore_errors: [], - ignore_actions: [], - env: :dev, - send_params: true, - endpoint: "https://push.appsignal.com", enable_host_metrics: false, + endpoint: "https://push.appsignal.com", + env: :dev, filter_parameters: nil, + ignore_actions: [], + ignore_errors: [], + running_in_container: false, + send_params: true, skip_session_data: false } @@ -20,10 +21,12 @@ defmodule Appsignal.Config do """ @spec initialize() :: :ok | {:error, :invalid_config} def initialize() do + system_config = %{running_in_container: System.get_env("DYNO") != nil} 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) @@ -63,6 +66,7 @@ defmodule Appsignal.Config do "APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH" => :frontend_error_catching_path, "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, @@ -73,10 +77,10 @@ defmodule Appsignal.Config do "APPSIGNAL_SKIP_SESSION_DATA" => :skip_session_data } - @string_keys ~w(APPSIGNAL_PUSH_API_KEY APPSIGNAL_PUSH_API_ENDPOINT APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY APPSIGNAL_LOG_PATH APPSIGNAL_WORKING_DIR_PATH APP_REVISION) + @string_keys ~w(APPSIGNAL_PUSH_API_KEY APPSIGNAL_PUSH_API_ENDPOINT APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY APPSIGNAL_LOG APPSIGNAL_LOG_PATH APPSIGNAL_WORKING_DIR_PATH APP_REVISION) @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_NAME APPSIGNAL_ENVIRONMENT) - @string_list_keys ~w(APPSIGNAL_FILTER_PARAMETERS) + @string_list_keys ~w(APPSIGNAL_FILTER_PARAMETERS APPSIGNAL_IGNORE_ACTIONS APPSIGNAL_IGNORE_ERRORS) defp load_environment(config, list, converter) do list |> Enum.reduce( @@ -93,8 +97,6 @@ defmodule Appsignal.Config do defp load_from_environment() do %{} - # Heroku is a container based system - |> Map.put(:running_in_container, System.get_env("DYNO") != nil) |> load_environment(@string_keys, &(&1)) |> load_environment(@bool_keys, &(true?(&1))) |> load_environment(@atom_keys, &(String.to_atom(&1))) @@ -138,8 +140,12 @@ defmodule Appsignal.Config do unless empty?(config[:http_proxy]) do System.put_env("APPSIGNAL_HTTP_PROXY", config[:http_proxy]) end + unless empty?(config[:filter_parameters]) do + System.put_env("APPSIGNAL_FILTER_PARAMETERS", config[:filter_parameters] |> Enum.join(",")) + 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_SEND_PARAMS", Atom.to_string(config[:send_params])) System.put_env("APPSIGNAL_RUNNING_IN_CONTAINER", Atom.to_string(config[:running_in_container])) unless empty?(config[:working_dir_path]) do System.put_env("APPSIGNAL_WORKING_DIR_PATH", config[:working_dir_path]) diff --git a/test/config/appsignal_config_test.exs b/test/config/appsignal_config_test.exs index 5275e6b25..b6b3cc296 100644 --- a/test/config/appsignal_config_test.exs +++ b/test/config/appsignal_config_test.exs @@ -7,77 +7,357 @@ defmodule AppsignalConfigTest do alias Appsignal.Config - test "unconfigured" do - System.put_env("APPSIGNAL_PUSH_API_KEY", "") + setup do Application.delete_env(:appsignal, :config) + + ~w( + APPSIGNAL_ACTIVE + APPSIGNAL_APP_NAME + APPSIGNAL_DEBUG + APPSIGNAL_DEBUG_LOGGING + APPSIGNAL_ENABLE_HOST_METRICS + APPSIGNAL_ENVIRONMENT + APPSIGNAL_FILTER_PARAMETERS + APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH + APPSIGNAL_HTTP_PROXY + APPSIGNAL_IGNORE_ACTIONS + APPSIGNAL_IGNORE_ERRORS + APPSIGNAL_LOG + APPSIGNAL_LOG_PATH + APPSIGNAL_PUSH_API_ENDPOINT + APPSIGNAL_PUSH_API_KEY + APPSIGNAL_RUNNING_IN_CONTAINER + APPSIGNAL_SKIP_SESSION_DATA + APPSIGNAL_WORKING_DIR_PATH + APP_REVISION + DYNO + ) |> Enum.each(fn(key) -> + System.delete_env(key) + end) + end + + test "unconfigured" do assert {:error, :invalid_config} = Config.initialize() end test "minimum config from OS env" do - System.put_env("APPSIGNAL_PUSH_API_KEY", "-test-") + System.put_env( + "APPSIGNAL_PUSH_API_KEY", "00000000-0000-0000-0000-000000000000" + ) assert :ok = Config.initialize() end test "minimum config from application env" do - Application.put_env(:appsignal, :config, - push_api_key: "-test") + Application.put_env( + :appsignal, :config, + push_api_key: "00000000-0000-0000-0000-000000000000" + ) assert :ok = Config.initialize() end - test "app revision" do - System.put_env("APP_REVISION", "0c497d") - assert "0c497d" = init_config()[:revision] + test "default configuration" do + assert default_configuration == init_config end - test "app revision from application env" do - System.delete_env("APP_REVISION") - Application.put_env(:appsignal, :config, - push_api_key: "-test", - revision: "b5f2b9") - assert "b5f2b9" = init_config()[:revision] + describe "using the application environment" do + setup do + Application.put_env( + :appsignal, :config, + push_api_key: "00000000-0000-0000-0000-000000000000" + ) + end + + test "valid configuration" do + assert valid_configuration == init_config + end + + test "active" do + add_to_application_env(:active, false) + assert valid_configuration |> Map.put(:active, false) == init_config + assert "false" == System.get_env("APPSIGNAL_ACTIVE") + end + + test "name" do + add_to_application_env(:name, :my_application) + assert valid_configuration |> Map.put(:name, :my_application) == init_config + assert "my_application" == System.get_env("APPSIGNAL_APP_NAME") + end + + test "debug" do + add_to_application_env(:debug, true) + assert valid_configuration |> Map.put(:debug, true) == init_config + assert "true" == System.get_env("APPSIGNAL_DEBUG_LOGGING") + end + + test "filter_parameters" do + add_to_application_env(:filter_parameters, ~w(password secret)) + assert valid_configuration |> Map.put(:filter_parameters, ~w(password secret)) == init_config + assert "password,secret" == System.get_env("APPSIGNAL_FILTER_PARAMETERS") + end + + test "frontend_error_catching_path" do + add_to_application_env(:frontend_error_catching_path, "/appsignal_error_catcher") + assert valid_configuration |> Map.put(:frontend_error_catching_path, "/appsignal_error_catcher") == init_config + end + + test "http_proxy" do + add_to_application_env(:http_proxy, "http://10.10.10.10:8888") + assert valid_configuration |> Map.put(:http_proxy, "http://10.10.10.10:8888") == init_config + assert "http://10.10.10.10:8888" == System.get_env("APPSIGNAL_HTTP_PROXY") + end + + test "ignore_actions" do + actions = ~w( + ExampleApplication.PageController#ignored + ExampleApplication.PageController#also_ignored + ) + add_to_application_env(:ignore_actions, actions) + assert valid_configuration |> Map.put(:ignore_actions, actions) == init_config + assert "ExampleApplication.PageController#ignored,ExampleApplication.PageController#also_ignored" == System.get_env("APPSIGNAL_IGNORE_ACTIONS") + end + + test "ignore_errors" do + errors = ~w(VerySpecificError AnotherError) + add_to_application_env(:ignore_errors, errors) + assert valid_configuration |> Map.put(:ignore_errors, errors) == init_config + assert "VerySpecificError,AnotherError" == System.get_env("APPSIGNAL_IGNORE_ERRORS") + end + + test "enable_host_metrics" do + add_to_application_env(:enable_host_metrics, true) + assert valid_configuration |> Map.put(:enable_host_metrics, true) == init_config + assert "true" == System.get_env("APPSIGNAL_ENABLE_HOST_METRICS") + end + + test "log" do + add_to_application_env(:log, "stdout") + assert valid_configuration |> Map.put(:log, "stdout") == init_config + end + + test "log_path" do + add_to_application_env(:log_path, "log/appsignal.log") + assert valid_configuration |> Map.put(:log_path, "log/appsignal.log") == init_config + assert "log/appsignal.log" == System.get_env("APPSIGNAL_LOG_FILE_PATH") + end + + test "endpoint" do + add_to_application_env(:endpoint, "https://push.staging.lol") + assert valid_configuration |> Map.put(:endpoint, "https://push.staging.lol") == init_config + assert "https://push.staging.lol" == System.get_env("APPSIGNAL_PUSH_API_ENDPOINT") + end + + test "running_in_container" do + add_to_application_env(:running_in_container, true) + assert valid_configuration |> Map.put(:running_in_container, true) == init_config + assert "true" == System.get_env("APPSIGNAL_RUNNING_IN_CONTAINER") + end + + test "send_params" do + add_to_application_env(:send_params, true) + assert valid_configuration |> Map.put(:send_params, true) == init_config + assert "true" == System.get_env("APPSIGNAL_SEND_PARAMS") + end + + test "skip_session_data" do + add_to_application_env(:skip_session_data, true) + assert valid_configuration |> Map.put(:skip_session_data, true) == init_config + end + + test "working_dir_path" do + add_to_application_env(:working_dir_path, "/tmp/appsignal") + assert valid_configuration |> Map.put(:working_dir_path, "/tmp/appsignal") == init_config + assert "/tmp/appsignal" == System.get_env("APPSIGNAL_WORKING_DIR_PATH") + end + + test "revision" do + add_to_application_env(:revision, "03bd9e") + assert valid_configuration |> Map.put(:revision, "03bd9e") == init_config + assert "03bd9e" == System.get_env("APP_REVISION") + end + end + + describe "using the system environment" do + setup do + System.put_env( + "APPSIGNAL_PUSH_API_KEY", "00000000-0000-0000-0000-000000000000" + ) + end + + test "valid configuration" do + assert valid_configuration == init_config + end + + test "active" do + System.put_env("APPSIGNAL_ACTIVE", "false") + assert valid_configuration |> Map.put(:active, false) == init_config + assert "false" == System.get_env("APPSIGNAL_ACTIVE") + end + + test "name" do + System.put_env("APPSIGNAL_APP_NAME", "my_application") + assert valid_configuration |> Map.put(:name, :my_application) == init_config + assert "my_application" == System.get_env("APPSIGNAL_APP_NAME") + end + + test "debug" do + System.put_env("APPSIGNAL_DEBUG", "true") + assert valid_configuration |> Map.put(:debug, true) == init_config + assert "true" == System.get_env("APPSIGNAL_DEBUG_LOGGING") + end + + test "filter_parameters" do + System.put_env("APPSIGNAL_FILTER_PARAMETERS", "password,secret") + assert valid_configuration |> Map.put(:filter_parameters, ~w(password secret)) == init_config + assert "password,secret" == System.get_env("APPSIGNAL_FILTER_PARAMETERS") + end + + test "frontend_error_catching_path" do + System.put_env("APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH", "/appsignal_error_catcher") + assert valid_configuration |> Map.put(:frontend_error_catching_path, "/appsignal_error_catcher") == init_config + end + + test "http_proxy" do + System.put_env("APPSIGNAL_HTTP_PROXY", "http://10.10.10.10:8888") + assert valid_configuration |> Map.put(:http_proxy, "http://10.10.10.10:8888") == init_config + assert "http://10.10.10.10:8888" == System.get_env("APPSIGNAL_HTTP_PROXY") + end + + test "ignore_actions" do + System.put_env("APPSIGNAL_IGNORE_ACTIONS", "ExampleApplication.PageController#ignored,ExampleApplication.PageController#also_ignored") + actions = ~w( + ExampleApplication.PageController#ignored + ExampleApplication.PageController#also_ignored + ) + assert valid_configuration |> Map.put(:ignore_actions, actions) == init_config + assert "ExampleApplication.PageController#ignored,ExampleApplication.PageController#also_ignored" == System.get_env("APPSIGNAL_IGNORE_ACTIONS") + end + + test "ignore_errors" do + System.put_env("APPSIGNAL_IGNORE_ERRORS", "VerySpecificError,AnotherError") + errors = ~w(VerySpecificError AnotherError) + assert valid_configuration |> Map.put(:ignore_errors, errors) == init_config + assert "VerySpecificError,AnotherError" == System.get_env("APPSIGNAL_IGNORE_ERRORS") + end + + test "enable_host_metrics" do + System.put_env("APPSIGNAL_ENABLE_HOST_METRICS", "true") + assert valid_configuration |> Map.put(:enable_host_metrics, true) == init_config + assert "true" == System.get_env("APPSIGNAL_ENABLE_HOST_METRICS") + end + + test "log" do + System.put_env("APPSIGNAL_LOG", "stdout") + assert valid_configuration |> Map.put(:log, "stdout") == init_config + end + + test "log_path" do + System.put_env("APPSIGNAL_LOG_PATH", "log/appsignal.log") + assert valid_configuration |> Map.put(:log_path, "log/appsignal.log") == init_config + assert "log/appsignal.log" == System.get_env("APPSIGNAL_LOG_FILE_PATH") + end + + test "endpoint" do + System.put_env("APPSIGNAL_PUSH_API_ENDPOINT", "https://push.staging.lol") + assert valid_configuration |> Map.put(:endpoint, "https://push.staging.lol") == init_config + assert "https://push.staging.lol" == System.get_env("APPSIGNAL_PUSH_API_ENDPOINT") + end + + test "running_in_container" do + System.put_env("APPSIGNAL_RUNNING_IN_CONTAINER", "true") + assert valid_configuration |> Map.put(:running_in_container, true) == init_config + assert "true" == System.get_env("APPSIGNAL_RUNNING_IN_CONTAINER") + end + + test "send_params" do + System.put_env("APPSIGNAL_SEND_PARAMS", "true") + assert valid_configuration |> Map.put(:send_params, true) == init_config + assert "true" == System.get_env("APPSIGNAL_SEND_PARAMS") + end + + test "skip_session_data" do + System.put_env("APPSIGNAL_SKIP_SESSION_DATA", "true") + assert valid_configuration |> Map.put(:skip_session_data, true) == init_config + end + + test "working_dir_path" do + System.put_env("APPSIGNAL_WORKING_DIR_PATH", "/tmp/appsignal") + assert valid_configuration |> Map.put(:working_dir_path, "/tmp/appsignal") == init_config + assert "/tmp/appsignal" == System.get_env("APPSIGNAL_WORKING_DIR_PATH") + end + + test "revision" do + System.put_env("APP_REVISION", "03bd9e") + assert valid_configuration |> Map.put(:revision, "03bd9e") == init_config + assert "03bd9e" == System.get_env("APP_REVISION") + end + end + + test "system environment overwrites application environment configuration" do + Application.put_env( + :appsignal, :config, + push_api_key: "11111111-1111-1111-1111-111111111111" + ) + System.put_env( + "APPSIGNAL_PUSH_API_KEY", "00000000-0000-0000-0000-000000000000" + ) + + assert valid_configuration == init_config + assert "00000000-0000-0000-0000-000000000000" == System.get_env("APPSIGNAL_PUSH_API_KEY") + end + + describe "on Heroku" do + setup do + System.put_env("APPSIGNAL_PUSH_API_KEY", "00000000-0000-0000-0000-000000000000") + System.put_env("DYNO", "web.1") + end + + test "running_in_container" do + assert valid_configuration |> Map.put(:running_in_container, true) == init_config + assert "true" == System.get_env("APPSIGNAL_RUNNING_IN_CONTAINER") + end + + test "application environment overwrites :running_in_container config on Heroku" do + Application.put_env( + :appsignal, :config, + running_in_container: false + ) + assert valid_configuration |> Map.put(:running_in_container, false) == init_config + assert "false" == System.get_env("APPSIGNAL_RUNNING_IN_CONTAINER") + end end - test "app config from application env gets put in system env" do - System.delete_env("APPSIGNAL_ACTIVE") - System.delete_env("APPSIGNAL_ENVIRONMENT") - System.delete_env("APPSIGNAL_PUSH_API_KEY") - System.delete_env("APPSIGNAL_APP_NAME") - System.delete_env("APPSIGNAL_ENABLE_HOST_METRICS") - System.delete_env("APP_REVISION") + defp default_configuration do + %{ + active: false, + debug: false, + enable_host_metrics: false, + endpoint: "https://push.appsignal.com", + env: :dev, + filter_parameters: nil, + ignore_actions: [], + ignore_errors: [], + running_in_container: false, + send_params: true, + skip_session_data: false, + valid: false + } + end + defp valid_configuration do + default_configuration + |> Map.put(:active, true) + |> Map.put(:push_api_key, "00000000-0000-0000-0000-000000000000") + |> Map.put(:valid, true) + end + + defp add_to_application_env(key, value) do Application.put_env(:appsignal, :config, - active: true, - env: :prod, - debug: true, - log_path: "log/appsignal.log", - push_api_endpoint: "https://push.appsignal.com", - push_api_key: "00000000-0000-0000-0000-000000000000", - name: :ExampleApplication, - http_proxy: "http://10.10.10.10:8888", - ignore_actions: ["ExampleApplication.PageController#ignored"], - ignore_errors: ["VerySpecificError"], - working_dir_path: "/tmp/appsignal", - enable_host_metrics: true, - revision: "03bd9e") - init_config() - assert "true" = System.get_env("APPSIGNAL_ACTIVE") - assert "prod" = System.get_env("APPSIGNAL_ENVIRONMENT") - assert "true" = System.get_env("APPSIGNAL_DEBUG_LOGGING") - assert "log/appsignal.log" = System.get_env("APPSIGNAL_LOG_FILE_PATH") - assert "https://push.appsignal.com" = System.get_env("APPSIGNAL_PUSH_API_ENDPOINT") - assert "00000000-0000-0000-0000-000000000000" = System.get_env("APPSIGNAL_PUSH_API_KEY") - assert "ExampleApplication" = System.get_env("APPSIGNAL_APP_NAME") - assert "http://10.10.10.10:8888" = System.get_env("APPSIGNAL_HTTP_PROXY") - assert "ExampleApplication.PageController#ignored" = System.get_env("APPSIGNAL_IGNORE_ACTIONS") - assert "VerySpecificError" = System.get_env("APPSIGNAL_IGNORE_ERRORS") - assert "/tmp/appsignal" = System.get_env("APPSIGNAL_WORKING_DIR_PATH") - assert "true" = System.get_env("APPSIGNAL_ENABLE_HOST_METRICS") - assert "03bd9e" = System.get_env("APP_REVISION") + Application.get_env(:appsignal, :config) ++ [{key, value}] + ) end defp init_config do Config.initialize() Application.get_all_env(:appsignal)[:config] end - end diff --git a/test/transaction/filter_test.exs b/test/transaction/filter_test.exs index 486fed372..aed94c51f 100644 --- a/test/transaction/filter_test.exs +++ b/test/transaction/filter_test.exs @@ -70,6 +70,7 @@ defmodule AppsignalTransactionFilterTest do Application.put_env(app, key, value) function.() Application.delete_env(app, key) + System.delete_env("APPSIGNAL_FILTER_PARAMETERS") end end