Skip to content

Commit 6d073e7

Browse files
authored
Merge pull request #837 from tsloughter/metric-docs
simplify metrics API and add metrics READMEs
2 parents 9a913d0 + 4a89bc2 commit 6d073e7

30 files changed

+678
-521
lines changed

apps/opentelemetry/src/otel_span_ets.erl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
update_name/2]).
3838

3939
%% since `span_ctx' and `span' are in the API the `span_sdk' has to be term()
40-
-eqwalizer({nowarn_function, end_span/1}).
41-
-eqwalizer({nowarn_function, end_span/2}).
4240
-eqwalizer({nowarn_function, get_ctx/1}).
4341

4442
-include_lib("opentelemetry_api/include/opentelemetry.hrl").

apps/opentelemetry_api/docs.config

Lines changed: 0 additions & 20 deletions
This file was deleted.

apps/opentelemetry_api/include/opentelemetry.hrl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@
4242

4343
%% Holds information about the instrumentation scope specified when
4444
%% getting a Tracer from the TracerProvider.
45-
-record(instrumentation_scope, {name :: unicode:unicode_binary() | undefined | '_',
46-
version :: unicode:unicode_binary() | undefined | '_',
47-
schema_url :: uri_string:uri_string() | undefined | '_'}).
45+
-record(instrumentation_scope, {name :: unicode:unicode_binary() | undefined,
46+
version :: unicode:unicode_binary() | undefined,
47+
schema_url :: uri_string:uri_string() | undefined}).
4848

4949
-record(span_ctx, {
5050
%% 128 bit int trace id

apps/opentelemetry_api/mix.exs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,48 @@ defmodule OpenTelemetry.MixProject do
1818
only: [:dev],
1919
runtime: false},
2020
{:dialyxir, "~> 1.0", only: [:dev], runtime: false},
21-
{:covertool, ">= 0.0.0", only: :test}
21+
{:covertool, ">= 0.0.0", only: :test},
22+
{:ex_doc, "~> 0.37", only: :dev, runtime: false}
2223
],
2324
name: "OpenTelemetry API",
2425
test_coverage: [tool: :covertool],
2526
package: package(),
26-
aliases: [docs: & &1],
2727
dialyzer: [
2828
ignore_warnings: "dialyzer.ignore-warnings",
2929
remove_defaults: [:unknown],
3030
plt_add_apps: [:eqwalizer_support],
3131
list_unused_filters: true
32+
],
33+
source_url: "https://github.com/open-telemetry/opentelemetry-erlang",
34+
homepage_url: "https://github.com/open-telemetry/opentelemetry-erlang",
35+
docs: [
36+
main: "readme",
37+
source_url_pattern:
38+
"https://github.com/open-telemetry/opentelemetry-erlang/blob/main/apps/opentelemetry_api/%{path}#L%{line}",
39+
extras: ["README.md", "LICENSE"],
40+
groups_for_modules: [
41+
Context: [:otel_ctx, OpenTelemetry.Ctx],
42+
Baggage: [:otel_baggage, OpenTelemetry.Baggage],
43+
Tracer: [
44+
:otel_tracer,
45+
:otel_tracer_noop,
46+
:otel_tracer_provider,
47+
:otel_tracestate,
48+
OpenTelemetry.Tracer,
49+
OpenTelemetry.Span
50+
],
51+
Propagators: [
52+
:otel_propagator,
53+
:otel_propagator_baggage,
54+
:otel_propagator_b3,
55+
:otel_propagator_b3multi,
56+
:otel_propagator_b3single,
57+
:otel_propagator_text_map,
58+
:otel_propagator_text_map_composite,
59+
:otel_propagator_text_map_noop,
60+
:otel_propagator_trace_context
61+
]
62+
]
3263
]
3364
]
3465
end

apps/opentelemetry_api/mix.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
%{
22
"covertool": {:hex, :covertool, "2.0.6", "4a291b4e3449025b0595d8f44c8d7635d4f48f033be2ce88d22a329f36f94a91", [:rebar3], [], "hexpm", "5db3fcd82180d8ea4ad857d4d1ab21a8d31b5aee0d60d2f6c0f9e25a411d1e21"},
33
"dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"},
4+
"earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"},
45
"eqwalizer_support": {:git, "https://github.com/whatsapp/eqwalizer.git", "1a787cb604f6083ebe8763e358ea362e4677e500", [branch: "main", sparse: "eqwalizer_support"]},
56
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
7+
"ex_doc": {:hex, :ex_doc, "0.37.1", "65ca30d242082b95aa852b3b73c9d9914279fff56db5dc7b3859be5504417980", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "6774f75477733ea88ce861476db031f9399c110640752ca2b400dbbb50491224"},
8+
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
9+
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
10+
"makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"},
11+
"nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"},
612
}

apps/opentelemetry_api/rebar.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
{doclet, edoc_doclet_chunks},
88
{layout, edoc_layout_chunks},
99
{preprocess, true},
10-
{dir, "apps/opentelemetry_api/_build/dev/lib/opentelemetry_api/doc"},
10+
{dir, "_build/dev/lib/opentelemetry_api/doc"},
1111
{subpackages, true}]}]}]}.

apps/opentelemetry_api/src/opentelemetry.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ link(_, _) ->
394394
TraceId :: trace_id(),
395395
SpanId :: span_id(),
396396
Attributes :: attributes_map(),
397-
TraceState :: otel_tracestate:t() | otel_tracestate:members().
397+
TraceState :: otel_tracestate:t().
398398
link(TraceId, SpanId, Attributes, TraceState) when is_integer(TraceId),
399399
is_integer(SpanId),
400400
(is_list(Attributes) orelse is_map(Attributes)) ->

apps/opentelemetry_api/src/otel_propagator_text_map.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
%% '''
2525
%%
2626
%% The propagators are then used at the points that cross-service
27-
%% communication is performed. By default, {@link inject/3} and {@link extract/3} work on a
27+
%% communication is performed. By default, {@link inject/2} and {@link extract/2} work on a
2828
%% generic list of 2-tuple's with binary string keys and values. You can pass (as an argument)
2929
%% a user-defined function for setting a key/value in the carrier and for getting
3030
%% the value of a key. For example, injecting and extracting to and from

apps/opentelemetry_api/src/otel_tracestate.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ update(Key, Value, Tracestate=#tracestate{members=TracestateList}) ->
115115
Tracestate
116116
end.
117117

118-
-spec decode_header(string() | undefined) -> t().
118+
-spec decode_header(unicode:latin1_binary() | undefined) -> t().
119119
decode_header(undefined) ->
120120
new();
121121
decode_header(Value) ->
Lines changed: 161 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,166 @@
11
opentelemetry_api_experimental
22
=====
33

4-
An OTP library
4+
Signals still in experimental status in the Erlang/Elixir API.
55

6-
Build
7-
-----
6+
# Metrics
87

9-
$ rebar3 compile
8+
For configuration of the Experimental SDK for Metrics see the experimental SDK
9+
`opentelemtry_experimental`. Without the SDK all operations for instruments and
10+
recording to them will be no-ops and nothing will be created or exported.
11+
12+
## Quickstart
13+
14+
The metrics API is used for instrumenting application code through the creation
15+
of instruments and calls to record data points with them.
16+
17+
### Instrument Creation
18+
19+
#### Supported Instruments
20+
21+
There are 3 synchronous instrument types and 3 observable instruments that are
22+
tied to a callback function. The list below gives each instrument type supported
23+
and details on the default aggregation used for the measurements recorded for
24+
that instrument:
25+
26+
- Counter: An always increasing value.
27+
- Updown Counter: A non-monotonic counter.
28+
- Histogram: A histogram with explicit bucket boundaries.
29+
- Observable Counter: A counter that is tied to a callback for recording measurements.
30+
- Observable Updown Counter: An updown counter that is tied to a callback for recording measurements.
31+
- Observable Gauge: An instrument tied to a callback who's default aggregated
32+
value is the last value recorded by the last call of the callback.
33+
34+
#### Macros
35+
36+
The header `otel_meter.hrl` contains macros for working with Instruments. This
37+
includes creation in the form `create_<instrument type>` and recording
38+
measurements like `counter_add` and `histogram_record`.
39+
40+
Below is example creation found in the [`dice_roll_elli`
41+
example](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/examples/roll_dice_elli):
42+
43+
```erlang
44+
-include_lib("opentelemetry_api_experimental/include/otel_meter.hrl").
45+
46+
?create_counter(?ROLL_COUNTER, #{description => <<"The number of rolls by roll value.">>,
47+
unit => '1'}).
48+
```
49+
### Instrument Recording
50+
51+
Measurements are taken on an instrument through recordings. Each type of
52+
instrument has functions and macros specific to its type for recording
53+
measurements. Counters can be added to so have the `counter_add` macro, UpDown
54+
counters can also be added to (but with the addition of accepting negative
55+
numbers) so have `updown_counter_add` and Histograms are passed recordings so
56+
have the macro `histogram_record`.
57+
58+
59+
An example from [`dice_roll_elli`
60+
example](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/examples/roll_dice_elli)
61+
of recording an addition to a counter with an attribute:
62+
63+
```erlang
64+
?counter_add(?ROLL_COUNTER, 1, #{'roll.value' => Roll}),
65+
```
66+
67+
See the Experimental SDK's `README.md` for how to setup Views for aggregation
68+
and then the exporting of metrics.
69+
70+
## Details
71+
72+
### Meter Provider
73+
74+
The Meter Provider (here the default implementation is in the module
75+
`otel_meter_server` in the SDK) is responsible for creating Meters and stores
76+
their shared configuration along with the shared
77+
[Resource](https://opentelemetry.io/docs/concepts/resources/) of the telemetry
78+
created for those Meters. Including the SDK application ensures a default
79+
Provider is created and used during Meter creation.
80+
81+
### Meter
82+
83+
Meters (default implementation found in `otel_meter_default` in the SDK) are
84+
used to create Instruments. Direct interaction with a Meter is not required
85+
except for special cases where the provided macros aren't enough to get the job
86+
done. The majority of use is done behind the macros.
87+
88+
### Measurement
89+
90+
Measurements are individual data points and their associated attributes.
91+
92+
### Instrument
93+
94+
An instrument is used to capture measurements.
95+
96+
Supported instrument kinds:
97+
98+
- Counter: Defaults to using a monotonic sum aggregation type in the SDK.
99+
- Updown Counter: Defaults to a non-monotonic sum aggregation type in the SDK.
100+
- Histogram: Defaults to an explicit histogram aggregation type in the SDK.
101+
- Observable Counter: Defaults to using a monotonic sum aggregation type in the SDK.
102+
- Observable Updown counter: Defaults to a non-monotonic sum aggregation type in the SDK.
103+
- Observable Gauge: Defaults to a last value aggregation type in the SDK.
104+
105+
The first 3 are synchronous instruments while the latter 3 must be associated
106+
with a callback function.
107+
108+
To record measurements an instrument must first be created. Each instrument kind
109+
has a `?create_<kind>` macro in Erlang for creation:
110+
111+
```erlang
112+
_RequestCounter = ?create_counter(app_request_counter, #{description => ~"Count of number of requests"})
113+
```
114+
115+
Now the instrument can be used to record measurements either by passing the
116+
atom name `app_request_counter`:
117+
118+
```erlang
119+
?counter_add(app_request_counter, 5, #{<<"a">> => <<"b">>}),
120+
```
121+
122+
For synchronous instruments the available macros are:
123+
124+
- `?counter_add(Name, Number, Attributes)`
125+
- `?updown_counter_add(Name, Number, Attributes)`
126+
- `?histogram_record(Name, Number, Attributes)`
127+
128+
The asynchronous (observable) instruments can be created with their callback or
129+
be later registered with a callback that supports multiple instruments.
130+
131+
When created with a callback for the instrument the callback returns a list of
132+
values and attributes to record for that instrument:
133+
134+
```erlang
135+
?create_observable_counter(my_observable_counter,
136+
fun(_Args) ->
137+
[{4, #{a => <<"b">>}},
138+
{12, #{c => <<"d">>}]
139+
end,
140+
[],
141+
#{description => <<"Describe your instrument">>,
142+
unit => kb})
143+
```
144+
145+
When the measurements are taken from the same source it is more efficient to
146+
create a single callback for multiple instruments:
147+
148+
```erlang
149+
ProcessCountName = 'beam_processes',
150+
AtomCountName = 'beam_atoms',
151+
152+
ProcessGauge = ?create_observable_gauge(ProcessCountName, #{description => <<"Number of currently running processes">>, unit => '1'}),
153+
AtomGauge = ?create_observable_gauge(AtomCountName, #{description => <<"Number of created atoms">>, unit => '1'}),
154+
155+
?register_callback([ProcessGauge, AtomGauge],
156+
fun(_) ->
157+
ProcessCount = erlang:system_info(process_count),
158+
AtomCount = erlang:system_info(atom_count),
159+
[{ProcessCountName, [{ProcessCount, #{}}]},
160+
{AtomCountName, [{AtomCount, #{}}]}]
161+
end, [])
162+
```
163+
164+
The callbacks are run when the Metric Reader collects metrics for export. See
165+
the Experimental SDK's `README.md` for more details on Metric Readers and their
166+
configuration.

0 commit comments

Comments
 (0)