changedCHANGELOG.md
 
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
8
+## [1.2.0](https://github.com/elixir-telemetry/telemetry/tree/v1.2.0)
9
+
10
+### Added
11
+
12
+- Added `telemetry_test` module for testing telemetry events. (#118)
13
+
8
14
## [1.1.0](https://github.com/elixir-telemetry/telemetry/tree/v1.1.0)
9
15
10
16
### Added
changedREADME.md
 
@@ -12,7 +12,7 @@ custom handlers.
12
12
> Note: this library is agnostic to tooling and therefore is not directly related to
13
13
> OpenTelemetry. For OpenTelemetry in the Erlang VM, see
14
14
> [opentelemetry-erlang](https://github.com/open-telemetry/opentelemetry-erlang), and check
15
-> [opentelemetry_telemetry](https://github.com/opentelemetry-beam/opentelemetry_telemetry)
15
+> [opentelemetry_telemetry](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/utilities/opentelemetry_telemetry)
16
16
> to connect both libraries.
17
17
18
18
## Usage
changedhex_metadata.config
 
@@ -4,12 +4,13 @@
4
4
<<"Dynamic dispatching library for metrics and instrumentations">>}.
5
5
{<<"files">>,
6
6
[<<"CHANGELOG.md">>,<<"LICENSE">>,<<"NOTICE">>,<<"README.md">>,<<"mix.exs">>,
7
- <<"rebar.config">>,<<"rebar.lock">>,<<"src/telemetry.app.src">>,
7
+ <<"rebar.config">>,<<"rebar.lock">>,<<"src">>,<<"src/telemetry.app.src">>,
8
8
<<"src/telemetry.erl">>,<<"src/telemetry.hrl">>,<<"src/telemetry_app.erl">>,
9
- <<"src/telemetry_handler_table.erl">>,<<"src/telemetry_sup.erl">>]}.
9
+ <<"src/telemetry_handler_table.erl">>,<<"src/telemetry_sup.erl">>,
10
+ <<"src/telemetry_test.erl">>]}.
10
11
{<<"licenses">>,[<<"Apache-2.0">>]}.
11
12
{<<"links">>,
12
13
[{<<"Github">>,<<"https://github.com/beam-telemetry/telemetry">>}]}.
13
14
{<<"name">>,<<"telemetry">>}.
14
15
{<<"requirements">>,[]}.
15
-{<<"version">>,<<"1.1.0">>}.
16
+{<<"version">>,<<"1.2.0">>}.
changedsrc/telemetry.app.src
 
@@ -1,6 +1,6 @@
1
1
{application,telemetry,
2
2
[{description,"Dynamic dispatching library for metrics and instrumentations"},
3
- {vsn,"1.1.0"},
3
+ {vsn,"1.2.0"},
4
4
{registered,[]},
5
5
{mod,{telemetry_app,[]}},
6
6
{applications,[kernel,stdlib]},
changedsrc/telemetry.erl
 
@@ -193,14 +193,15 @@ execute([_ | _] = EventName, Measurements, Metadata) when is_map(Measurements) a
193
193
%%
194
194
%% When providing `StartMetadata' and `StopMetadata', these values will be sent independently to `start' and
195
195
%% `stop' events. If an exception occurs, exception metadata will be merged onto the `StartMetadata'. In general,
196
-%% `StopMetadata' should only provide values that are additive to `StartMetadata' so that handlers, such as those
197
-%% used for metrics, can rely entirely on the `stop' event.
196
+%% it is <strong>highly recommended</strong> that `StopMetadata' should include the values from `StartMetadata'
197
+%% so that handlers, such as those used for metrics, can rely entirely on the `stop' event. Failure to include
198
+%% all of `StartMetadata' in `StopMetadata' can add significant complexity to event handlers.
198
199
%%
199
200
%% A default span context is added to event metadata under the `telemetry_span_context' key if none is provided by
200
201
%% the user in the `StartMetadata'. This context is useful for tracing libraries to identify unique
201
-%% executions of span events within a process to match start, stop, and exception events. Users
202
-%% should ensure this value is unique within the context of a process at a minimum if overriding this key and
203
-%% that the same value is provided to both `StartMetadata' and `StopMetadata'.
202
+%% executions of span events within a process to match start, stop, and exception events. Metadata keys, which
203
+%% should be available to both `start' and `stop' events need to supplied separately for `StartMetadata' and
204
+%% `StopMetadata'.
204
205
%%
205
206
%% For `telemetry' events denoting the <strong>start</strong> of a larger event, the following data is provided:
206
207
%%
addedsrc/telemetry_test.erl
 
@@ -0,0 +1,59 @@
1
+%%%-------------------------------------------------------------------
2
+%% @doc Functions for testing execution of Telemetry events.
3
+%%
4
+%% Testing that the correct Telemetry events are emitted with the
5
+%% right measurements and metadata is essential for library authors.
6
+%% It helps to maintain stable APIs and avoid accidental changes
7
+%% to events.
8
+%% @end
9
+%%%-------------------------------------------------------------------
10
+
11
+-module(telemetry_test).
12
+
13
+-export([attach_event_handlers/2]).
14
+
15
+%% @doc Attaches a "message" handler to the given events.
16
+%%
17
+%% The attached handler sends a message to `destination_pid` every time it handles one of the
18
+%% events in `events`. The function returns a reference that you can use to make sure that
19
+%% messages come from this handler. This reference is also used as the handler ID, so you
20
+%% can use it to detach the handler with {link telemetry:detach/1}.
21
+%%
22
+%% The shape of messages sent to `destination_pid` is:
23
+%%
24
+%% ```
25
+%% {Event, Ref, Measurements, Metadata}
26
+%% '''
27
+%%
28
+%% For example, in Erlang a test could look like this:
29
+%%
30
+%% ```
31
+%% Ref = telemetry_test:attach_event_handlers(self(), [[some, event]]),
32
+%% function_that_emits_the_event(),
33
+%% receive
34
+%% {[some, event], Ref, #{measurement := _}, #{meta := _}} ->
35
+%% telemetry:detach(Ref)
36
+%% after 1000 ->
37
+%% ct:fail(timeout_receive_attach_event_handlers)
38
+%% end.
39
+%% '''
40
+%%
41
+%% In Elixir, a similar test would look like this:
42
+%%
43
+%% ```
44
+%% ref = :telemetry_test.attach_event_handlers(self(), [[:some, :event]])
45
+%% function_that_emits_the_event()
46
+%% assert_received {[:some, :event], ^ref, %{measurement: _}, %{meta: _}}
47
+%% '''
48
+%%
49
+-spec attach_event_handlers(DestinationPID, Events) -> reference() when
50
+ DestinationPID :: pid(),
51
+ Events :: [telemetry:event_name(), ...].
52
+attach_event_handlers(DestPID, Events) when is_pid(DestPID) and is_list(Events) ->
53
+ Ref = make_ref(),
54
+ Config = #{dest_pid => DestPID, ref => Ref},
55
+ telemetry:attach_many(Ref, Events, fun handle_event/4, Config),
56
+ Ref.
57
+
58
+handle_event(Event, Measurements, Metadata, #{dest_pid := DestPID, ref := Ref}) ->
59
+ DestPID ! {Event, Ref, Measurements, Metadata}.