Skip to content

Commit d43a1f5

Browse files
committed
Use explicit_histogram_buckets if not configured in view
1 parent 3b406dc commit d43a1f5

File tree

4 files changed

+101
-8
lines changed

4 files changed

+101
-8
lines changed

apps/opentelemetry_experimental/src/otel_meter_default.erl

+3-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ validate_name(Name) ->
8383
ok.
8484

8585
validate_opts(Name, Kind, #{advisory_params := AdvisoryParams} = Opts) ->
86-
ValidatedAdvisoryParams = maps:filtermap(fun(Key, Value) -> validate_advisory_param(Name, Kind, Key, Value) end, AdvisoryParams),
86+
% switch to maps:filtermap when we support only 24 onwards
87+
ValidatedAdvisoryParams = maps:from_list(lists:filtermap(fun({Key, Value}) -> validate_advisory_param(Name, Kind, Key, Value) end, maps:to_list(AdvisoryParams))),
8788
maps:put(advisory_params, ValidatedAdvisoryParams, Opts);
8889
validate_opts(_Name, _Kind, Opts) ->
8990
Opts.
@@ -100,7 +101,7 @@ validate_advisory_param(Name, _Kind, Opt, _Value) ->
100101
validate_explicit_bucket_boundaries(Name, [_ | _] = Value) ->
101102
case lists:all(fun is_number/1, Value) and (lists:sort(Value) == Value) of
102103
true ->
103-
{true, Value};
104+
{true, {explicit_bucket_boundaries, Value}};
104105
false ->
105106
?LOG_WARNING("[instrument '~s'] 'explicit_bucket_boundaries' advisory parameter should be a not empty ordered list of numbers, got ~p", [Name, Value]),
106107
false

apps/opentelemetry_experimental/src/otel_meter_server.erl

-2
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ view_aggregation_for_reader(Instrument=#instrument{kind=Kind}, ViewAggregation,
392392
reader=Id,
393393
attribute_keys=AttributeKeys,
394394
aggregation_module=AggregationModule,
395-
aggregation_options=#{},
396395
temporality=Temporality};
397396
view_aggregation_for_reader(Instrument=#instrument{kind=Kind}, ViewAggregation, View,
398397
Reader=#reader{id=Id,
@@ -404,7 +403,6 @@ view_aggregation_for_reader(Instrument=#instrument{kind=Kind}, ViewAggregation,
404403
reader=Id,
405404
attribute_keys=undefined,
406405
aggregation_module=AggregationModule,
407-
aggregation_options=#{},
408406
temporality=Temporality}.
409407

410408

apps/opentelemetry_experimental/src/otel_view.erl

+13-3
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ new(Name, Criteria, Config) ->
7878
-spec match_instrument_to_views(otel_instrument:t(), [t()]) -> [{t() | undefined, #view_aggregation{}}].
7979
match_instrument_to_views(Instrument=#instrument{name=InstrumentName,
8080
meter=Meter,
81-
description=Description}, Views) ->
81+
description=Description,
82+
advisory_params=AdvisoryParams}, Views) ->
8283
IsMonotonic = otel_instrument:is_monotonic(Instrument),
8384
Temporality = otel_instrument:temporality(Instrument),
8485
Scope = otel_meter:scope(Meter),
@@ -91,6 +92,7 @@ match_instrument_to_views(Instrument=#instrument{name=InstrumentName,
9192
[] ->
9293
false;
9394
_ ->
95+
AggregationOptions1 = aggragation_options(AggregationOptions, AdvisoryParams),
9496
%% `reader' needs to be undefined and is set
9597
%% for each in `otel_meter_server'
9698
%% eqwalizer:ignore see above
@@ -101,27 +103,35 @@ match_instrument_to_views(Instrument=#instrument{name=InstrumentName,
101103
temporality=Temporality,
102104
is_monotonic=IsMonotonic,
103105
attribute_keys=AttributeKeys,
104-
aggregation_options=AggregationOptions,
106+
aggregation_options=AggregationOptions1,
105107
description=value_or(ViewDescription,
106108
Description)
107109
}}}
108110
end
109111
end, Views) of
110112
[] ->
113+
AggregationOptions1 = aggragation_options(#{}, AdvisoryParams),
111114
[{undefined, #view_aggregation{name=InstrumentName,
112115
scope=Scope,
113116
instrument=Instrument,
114117
temporality=Temporality,
115118
is_monotonic=IsMonotonic,
116119
attribute_keys=undefined,
117-
aggregation_options=#{},
120+
aggregation_options=AggregationOptions1,
118121
description=Description}}];
119122
Aggs ->
120123
Aggs
121124
end.
122125

123126
%%
124127

128+
aggragation_options(#{boundaries := _} = AggregationOptions, _AdvisoryParams) ->
129+
AggregationOptions;
130+
aggragation_options(AggregationOptions, #{explicit_bucket_boundaries := Boundaries}) ->
131+
maps:put(boundaries, Boundaries, AggregationOptions);
132+
aggragation_options(AggregationOptions, _AdvisoryParams) ->
133+
AggregationOptions.
134+
125135
value_or(undefined, Other) ->
126136
Other;
127137
value_or(Value, _Other) ->

apps/opentelemetry_experimental/test/otel_metrics_SUITE.erl

+85-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ all() ->
8383
kill_reader, kill_server, observable_counter, observable_updown_counter, observable_gauge,
8484
multi_instrument_callback, using_macros, float_counter, float_updown_counter, float_histogram,
8585
sync_filtered_attributes, async_filtered_attributes, delta_observable_counter,
86-
bad_observable_return, default_resource
86+
bad_observable_return, default_resource, advisory_params
8787
].
8888

8989
init_per_suite(Config) ->
@@ -1130,3 +1130,87 @@ bad_observable_return(_Config) ->
11301130
?assertSumReceive(CounterName2, <<"observable counter 2 description">>, kb, [{8, #{}}]),
11311131

11321132
ok.
1133+
1134+
advisory_params(_Config) ->
1135+
DefaultMeter = otel_meter_default,
1136+
1137+
Meter = opentelemetry_experimental:get_meter(),
1138+
?assertMatch({DefaultMeter, _}, Meter),
1139+
1140+
% explicit_bucket_boundaries allowed only for histograms
1141+
Counter = otel_counter:create(Meter, invalid_1,
1142+
#{advisory_params => #{explicit_bucket_boundaries => [1, 2, 3]}}),
1143+
?assertEqual(Counter#instrument.advisory_params, #{}),
1144+
1145+
% advisory parameters different from explicit_bucket_boundaries are not allowed
1146+
Counter1 = otel_counter:create(Meter, invalid_2, #{advisory_params => #{invalid => invalid}}),
1147+
?assertEqual(Counter1#instrument.advisory_params, #{}),
1148+
1149+
% explicit_bucket_boundaries should be an ordered list of numbers
1150+
Histo1 = otel_histogram:create(Meter, invalid_3,
1151+
#{advisory_params => #{explicit_bucket_boundaries => invalid}}),
1152+
?assertEqual(Histo1#instrument.advisory_params, #{}),
1153+
1154+
Histo2 = otel_histogram:create(Meter, invalid_4,
1155+
#{advisory_params => #{explicit_bucket_boundaries => [2,1,4]}}),
1156+
?assertEqual(Histo2#instrument.advisory_params, #{}),
1157+
1158+
% when valid use the explicit_bucket_boundaries from advisory_params if not set in a view
1159+
Histogram = otel_histogram:create(Meter, a_histogram,
1160+
#{advisory_params => #{explicit_bucket_boundaries => [10, 20, 30]}}),
1161+
?assertEqual(Histogram#instrument.advisory_params, #{explicit_bucket_boundaries => [10, 20, 30]}),
1162+
1163+
?assertEqual(ok, otel_histogram:record(Histogram, 15, #{<<"a">> => <<"1">>})),
1164+
?assertEqual(ok, otel_histogram:record(Histogram, 50, #{<<"a">> => <<"1">>})),
1165+
?assertEqual(ok, otel_histogram:record(Histogram, 26, #{<<"a">> => <<"2">>})),
1166+
1167+
otel_meter_server:force_flush(),
1168+
1169+
receive
1170+
{otel_metric, #metric{name=a_histogram,
1171+
data=#histogram{datapoints=Datapoints}}} ->
1172+
AttributeBuckets =
1173+
lists:sort([{Attributes, Buckets, Min, Max, Sum} || #histogram_datapoint{bucket_counts=Buckets,
1174+
attributes=Attributes,
1175+
min=Min,
1176+
max=Max,
1177+
sum=Sum} <- Datapoints]),
1178+
?assertEqual([], [{#{<<"a">> => <<"1">>}, [0,1,0,1], 15, 50, 65},
1179+
{#{<<"a">> => <<"2">>}, [0,0,1,0], 26, 26, 26}]
1180+
-- AttributeBuckets, AttributeBuckets)
1181+
after
1182+
5000 ->
1183+
ct:fail(histogram_receive_timeout)
1184+
end,
1185+
1186+
% boundaries from view have precedence
1187+
?assert(otel_meter_server:add_view(view, #{instrument_name => b_histogram}, #{
1188+
aggregation_module => otel_aggregation_histogram_explicit,
1189+
aggregation_options => #{boundaries => [10, 100]}})),
1190+
1191+
HistogramB = otel_histogram:create(Meter, b_histogram,
1192+
#{advisory_params => #{explicit_bucket_boundaries => [10, 20, 30]}}),
1193+
?assertEqual(HistogramB#instrument.advisory_params, #{explicit_bucket_boundaries => [10, 20, 30]}),
1194+
1195+
?assertEqual(ok, otel_histogram:record(HistogramB, 15, #{<<"a">> => <<"1">>})),
1196+
?assertEqual(ok, otel_histogram:record(HistogramB, 50, #{<<"a">> => <<"1">>})),
1197+
?assertEqual(ok, otel_histogram:record(HistogramB, 26, #{<<"a">> => <<"2">>})),
1198+
1199+
otel_meter_server:force_flush(),
1200+
1201+
receive
1202+
{otel_metric, #metric{name=view,
1203+
data=#histogram{datapoints=DatapointsB}}} ->
1204+
AttributeBucketsB =
1205+
lists:sort([{Attributes, Buckets, Min, Max, Sum} || #histogram_datapoint{bucket_counts=Buckets,
1206+
attributes=Attributes,
1207+
min=Min,
1208+
max=Max,
1209+
sum=Sum} <- DatapointsB]),
1210+
?assertEqual([], [{#{<<"a">> => <<"1">>}, [0,2,0], 15, 50, 65},
1211+
{#{<<"a">> => <<"2">>}, [0,1,0], 26, 26, 26}]
1212+
-- AttributeBucketsB, AttributeBucketsB)
1213+
after
1214+
1000 ->
1215+
ct:fail(histogram_receive_timeout)
1216+
end.

0 commit comments

Comments
 (0)