View Source Telemetria (telemetria v0.22.1)
Telemetría
is the opinionated wrapper for :telemetry
(started with v0.19.0
it became agnostic to the actual telemetry backend and supports
OpenTelemetry
out of the box, allowing for more custom implementations of the said backend.)
It provides handy macros to attach telemetry events to any function, private function,
anonymous functions (on per-clause basis) and just random set of expressions.
Telemetría
exports three macros:
deft/2
which is wrappingKernel.def/2
defpt/2
which is wrappingKernel.defp/2
t/2
which is wrapping the expression passed as the first parameter and adds the options passed as a keyword to the second parameter to the context of the respective telemetry event
Module attribute over macros
Unless inevitably needed, one should prefer module attributes over explicit macros (see the section “Using Module Attribute” below.)
Module attributes have a way richer customization abilities, including but not limited to conditional wrapping, slack messaging etc. See options which are accepted by the module attribute below.
Telemetría
allows compile-time telemetry events definition and provides
a compiler that is responsible for incremental builds and updates of the list of
events telemetry is aware about.
Compile-time config
Telemetría
uses a compiler to wrap annotated functions with a telemetry calls.
That means, that all the configuration must be placed into compile-time config files.
Using Module Attribute
Besides the functions listed above, one might attach Telemetría
to the function
by annotating it with @telemetria
module attribute.
There are several options to pass to this attribute:
true
— attach thetelemetry
to the functionif: boolean()
— compile-time conditionif: (result -> boolean())
— runtime conditionlevel: Logger,level()
— specify a min logger level to attach telemetrygroup: atom()
— the configured group to manage event throttling, see:throttle
setting inTelemetria.Options
locals: [atom()]
— the list of names of local variables to be exported to the telemetry calltransform: [{:args, (list() -> list())}, {:result, (any() -> any())}]
— the functions to be called on the incoming attributes and/or result to reshape themreshape: (map() -> map())
— the function to be called on the resulting attributes to reshape them before sending to the actual telemetry handler; the default application-wide reshaper might be set in:telemetria, :reshaper
configmessenger_channels: %{optional(atom()) => {module, keyword()}
— more handy messenger management, several channels config with channels names associated with their implementations and properties
Example
The following code would emit the telemetry event for the function weather
,
returning result
in Celcius and injecting farenheit
value under locals
defmodule Forecast do
use Telemetria
@telemetria level: :info, group: :weather_reports, locals: [:farenheit]
def weather(city) do
fahrenheit = ExternalService.retrieve(city)
Converter.fahrenheit_to_celcius(fahrenheit)
end
end
Advantages
Telemetría
takes care about managing events in the target application,
makes it a single-letter change to turn a function into a function wrapped
with telemetry call, measuring the execution time out of the box.
It also allows to easily convert expressions to be be telemetry-aware.
Besides that, telemetry: false
flag allows to purge the calls in compile-time
resulting in zero overhead (useful for benchmark, or like.)
Example
You need to include the compiler in mix.exs
:
defmodule MyApp.MixProject do
def project do
[
# ...
compilers: [:telemetria | Mix.compilers()],
# ...
]
end
# ...
end
Enabling Telemetría
To enable telemetría
for the project, you should add :telemetria
compiler to the list
of Mix.compilers/0
as shown below (mix.exs
).
def project do
[
...
compilers: [:telemetria | Mix.compilers()],
...
]
end
Additional steps are described below for the different use-cases.
Plain Macros
In the modules you want to add telemetry macros to, you should require Telemetria
(or,
preferably, import Telemetria
to make it available without FQN.) Once imported,
the macros are available and tracked by the compiler.
defmodule MyMod do
import Telemetria
defpt pi, do: 3.14
deft answer, do: 42 - pi()
def inner do
short_result = t(42 * 42)
result =
t do
# long calculations
:ok
end
end
end
Module Attribute
Module attributes are processed by the compilation hooks. To enable @telemetria
module attributes, one should use Telemetria
. Below is the example that would send
two telemetry events to the configured Telemetria.Backend
.
defmodule Otel do
@moduledoc "`Telemetria` with :opentelemetry` example"
use Telemetria
@telemetria level: :info, group: :weather_reports, locals: [:celsius], messenger: :slack
def f_to_c(fahrenheit) do
celsius = do_f_to_c(fahrenheit)
round(celsius)
end
@telemetria level: :info, group: :weather_reports
defp do_f_to_c(fahrenheit), do: (fahrenheit - 32) * 5 / 9
end
Typical Config
Telemetría
requires an application-wide config to operate properly. Yes, I know
having a config in a library is discouraged by the core team. Unfortunately, for the
compiler to work properly, the static compile-time config is still required.
After all, even if running many OTP applications on the same node, one would barely want to have a different telemetry config for them.
import Config
config :telemetria,
purge_level: :debug,
level: :info,
events: [
[:tm, :f_to_c]
],
throttle: %{some_group: {1_000, :last}}
# create a slack app and put URL here
# messenger_channels: %{slack: {:slack, url: ""}}
Use in releases
:telemetria
compiler keeps track of the events in the compiler manifest file
to support incremental builds. Also it spits out config/.telemetria.config.json
config for convenience. It might be used in in the release configuration as shown below.
releases: [
configured: [
# ...,
config_providers: [{Telemetria.ConfigProvider, "/etc/telemetria.json"}]
]
]
Options
:otp_app
(atom/0
) - OTP application this telemetry is attached to. The default value is:telemetria
.:enabled
(boolean/0
) - Specifies whether telemetry should be enabled. The default value istrue
.:backend
(atom/0
) - The backend to be used as an actual implementation The default value isTelemetria.Backend.Telemetry
.:messenger_channels
(map/0
) - The messenger channels as a map%{name => {impl, opts}}
The default value is%{}
.:level
- Telemetria level to skip logging beyond, as in Logger The default value is:debug
.:purge_level
- Telemetria level to purge beyond, as in Logger The default value is:debug
.:throttle
- The throttling mechanism for throttling through too many events The default value is:none
.:strict
(boolean/0
) - Ignore@telemetria
tags withoutif
clause The default value isfalse
.:smart_log
(boolean/0
) - Log format to use; when true, custom json would be used The default value isfalse
.:applications
(keyword/0
) - List the applications to enable Telemetria support for, with parameters The default value is[]
.:json_config_path
(String.t/0
) - Relative path to JSON config The default value is"config/.telemetria.config.json"
.:events
- The application-specific events.See
Telemetria.event_prefix/0
andTelemetria.event_name/0
.The default value is
[]
.:handler
- Event handler for this application’s telemetry events. Arity must be 4. The default value is{Telemetria.Handler.Default, :handle_event}
.:polling
(keyword/0
) - The default value is[enabled: false, flush: 5000, poll: 5000]
.:enabled
(boolean/0
) - Specifies whether polling should be enabled. The default value istrue
.:flush
(non_neg_integer/0
) - Flush interval. The default value is5000
.:poll
(non_neg_integer/0
) - Poll interval. The default value is5000
.
:process_info
(boolean/0
) - Specifies whether each telemetry event should include process info. The default value isfalse
.
Summary
Functions
Declares a private function with a telemetry attached, measuring execution time
Declares a function with a telemetry attached, measuring execution time
Attaches telemetry to anonymous function (per clause,) or to expression(s)
Types
Functions
Declares a private function with a telemetry attached, measuring execution time
Declares a function with a telemetry attached, measuring execution time
Attaches telemetry to anonymous function (per clause,) or to expression(s)
@spec telemetry_prefix( Macro.Env.t(), {atom(), keyword(), tuple()} | nil | maybe_improper_list() ) :: [atom()]