Packages
appsignal
1.13.4
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.ex
defmodule Appsignal do
@moduledoc """
AppSignal for Elixir. Follow the [installation guide](https://docs.appsignal.com/elixir/installation.html) to install AppSignal into your Elixir app.
This module contains the main AppSignal OTP application, as well as
a few helper functions for sending metrics to AppSignal.
These metrics do not rely on an active transaction being
present. For transaction related-functions, see the
[Appsignal.Transaction](Appsignal.Transaction.html) module.
"""
use Application
alias Appsignal.{Backtrace, Config, Error}
require Logger
@transaction Application.get_env(
:appsignal,
:appsignal_transaction,
Appsignal.Transaction
)
if System.otp_release() >= "21" do
@report_handler Appsignal.LoggerHandler
else
@report_handler Appsignal.ErrorLoggerHandler
end
@doc """
Application callback function
"""
def start(_type, _args) do
import Supervisor.Spec, warn: false
initialize()
add_report_handler()
if phoenix?(), do: Appsignal.Phoenix.EventHandler.attach()
children = [
worker(Appsignal.Transaction.Receiver, [], restart: :permanent),
worker(Appsignal.Transaction.ETS, [], restart: :permanent),
worker(Appsignal.Probes, [])
]
result = Supervisor.start_link(children, strategy: :one_for_one, name: Appsignal.Supervisor)
# Add our default system probes. It's important that this is called after
# the Suportvisor has started. Otherwise the GenServer cannot register the
# probe.
add_default_probes()
result
end
def plug? do
Code.ensure_loaded?(Plug)
end
def phoenix? do
Code.ensure_loaded?(Phoenix)
end
def live_view? do
phoenix?() && Code.ensure_loaded?(Phoenix.LiveView)
end
@doc """
Application callback function
"""
def stop(_state) do
Logger.debug("AppSignal stopping.")
end
def config_change(_changed, _new, _removed) do
# Spawn a separate process that reloads the configuration. AppSignal can't
# reload it in the same process because the GenServer would continue
# calling itself once it reached `Application.put_env` in
# `Appsignal.Config`.
spawn(fn ->
:ok = Appsignal.Nif.stop()
:ok = initialize()
end)
end
@doc false
def initialize do
case {Config.initialize(), Config.configured_as_active?()} do
{_, false} ->
Logger.info("AppSignal disabled.")
{:ok, true} ->
Logger.debug("AppSignal starting.")
Config.write_to_environment()
Appsignal.Nif.start()
if Appsignal.Nif.loaded?() do
Logger.debug("AppSignal started.")
else
Logger.error(
"Failed to start AppSignal. Please run the diagnose task " <>
"(https://docs.appsignal.com/elixir/command-line/diagnose.html) " <>
"to debug your installation."
)
end
{{:error, :invalid_config}, true} ->
Logger.warn(
"Warning: No valid AppSignal configuration found, continuing with " <>
"AppSignal metrics disabled."
)
end
end
@doc false
def add_report_handler, do: @report_handler.add()
@doc false
def remove_report_handler, do: @report_handler.remove()
@doc false
def add_default_probes do
Appsignal.Probes.register(:erlang, &Appsignal.Probes.ErlangProbe.call/0)
end
@doc """
Set a gauge for a measurement of some metric.
"""
@spec set_gauge(String.t(), float | integer, map) :: :ok
def set_gauge(key, value, tags \\ %{})
def set_gauge(key, value, tags) when is_integer(value) do
set_gauge(key, value + 0.0, tags)
end
def set_gauge(key, value, %{} = tags) when is_float(value) do
encoded_tags = Appsignal.Utils.DataEncoder.encode(tags)
:ok = Appsignal.Nif.set_gauge(key, value, encoded_tags)
end
@doc """
Increment a counter of some metric.
"""
@spec increment_counter(String.t(), number, map) :: :ok
def increment_counter(key, count \\ 1, tags \\ %{})
def increment_counter(key, count, %{} = tags) when is_number(count) do
encoded_tags = Appsignal.Utils.DataEncoder.encode(tags)
:ok = Appsignal.Nif.increment_counter(key, count + 0.0, encoded_tags)
end
@doc """
Add a value to a distribution
Use this to collect multiple data points that will be merged into a
graph.
"""
@spec add_distribution_value(String.t(), float | integer, map) :: :ok
def add_distribution_value(key, value, tags \\ %{})
def add_distribution_value(key, value, tags) when is_integer(value) do
add_distribution_value(key, value + 0.0, tags)
end
def add_distribution_value(key, value, %{} = tags) when is_float(value) do
encoded_tags = Appsignal.Utils.DataEncoder.encode(tags)
:ok = Appsignal.Nif.add_distribution_value(key, value, encoded_tags)
end
@doc """
Send an error to AppSignal
When there is no current transaction, this call starts one.
## Examples
Appsignal.send_error(%RuntimeError{})
Appsignal.send_error(%RuntimeError{}, "", __STACKTRACE__)
Appsignal.send_error(%RuntimeError{}, "", [], %{foo: "bar"})
Appsignal.send_error(%RuntimeError{}, "", [], %{}, %Plug.Conn{})
Appsignal.send_error(%RuntimeError{}, "", [], %{}, nil, fn(transaction) ->
Appsignal.Transaction.set_sample_data(transaction, "key", %{foo: "bar"})
end)
"""
def send_error(
error,
prefix \\ "",
stack \\ nil,
metadata \\ %{},
conn \\ nil,
fun \\ fn t -> t end,
namespace \\ :http_request
) do
stack =
case stack do
nil ->
IO.warn(
"Appsignal.send_error/1-7 without passing a stack trace is deprecated, and defaults to passing an empty stacktrace. Please explicitly pass a stack trace or an empty list."
)
[]
_ ->
stack
end
transaction = @transaction.create("_" <> @transaction.generate_id(), namespace)
fun.(transaction)
{exception, stacktrace} = Error.normalize(error, stack)
{name, message} = Error.metadata(exception)
backtrace = Backtrace.from_stacktrace(stacktrace)
Appsignal.ErrorHandler.submit_transaction(
transaction,
name,
prefixed(prefix, message),
backtrace,
metadata,
conn
)
end
defp prefixed("", message), do: message
defp prefixed(prefix, message) when is_binary(prefix), do: prefix <> ": " <> message
defp prefixed(_, message), do: message
end