Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert attributes to record before storing in ETS for metrics #633

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions apps/opentelemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,21 +199,23 @@ in the Resource.
The default detectors read resource attributes from the OS environment variable
`OTEL_RESOURCE_ATTRIBUTES` and Application environment variable `resource`.

### Span Limits
### Limits

The number of Attributes, Events and Links on a Span are limited, as well as the
length of an Attribute's value. When the limit is reached any additional
Attributes, Events or Links are dropped and Attribute values larger than the
length limit are truncated.

| OS | Application | Default | Type |
|:---------------------------------------|:-----------------------------|:---------|:------------------------|
| OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT | attribute_count_limit | 128 | integer |
| OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT | attribute_value_length_limit | infinity | integer | infinity |
| OTEL_SPAN_EVENT_COUNT_LIMIT | event_count_limit | 128 | integer |
| OTEL_SPAN_LINK_COUNT_LIMIT | link_count_limit | 128 | integer |
| OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT | attribute_per_event_limit | 128 | integer |
| OTEL_LINK_ATTRIBUTE_COUNT_LIMIT | attribute_per_link_limit | 128 | integer
| OS | Application | Default | Type |
|:---------------------------------------|:----------------------------------|:---------|:------------------------|
| OTEL_ATTRIBUTE_COUNT_LIMIT | attribute_count_limit | 128 | integer |
| OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT | attribute_value_length_limit | infinity | integer | infinity |
| OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT | span_attribute_count_limit | 128 | integer |
| OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT | span_attribute_value_length_limit | infinity | integer | infinity |
| OTEL_SPAN_EVENT_COUNT_LIMIT | event_count_limit | 128 | integer |
| OTEL_SPAN_LINK_COUNT_LIMIT | link_count_limit | 128 | integer |
| OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT | attribute_per_event_limit | 128 | integer |
| OTEL_LINK_ATTRIBUTE_COUNT_LIMIT | attribute_per_link_limit | 128 | integer

Read more in the specification about [Span
limits](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#span-limits)
Expand Down
16 changes: 9 additions & 7 deletions apps/opentelemetry/include/otel_span.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,15 @@
instrumentation_scope :: opentelemetry:instrumentation_scope() | undefined | '_'
}).

-record(span_limits, {
attribute_count_limit = 128 :: integer(), %% Maximum allowed attribute count per span;
attribute_value_length_limit = infinity :: integer() | infinity, %% Maximum allowed attribute value length
event_count_limit = 128 :: integer(), %% Maximum allowed span event count
link_count_limit = 128 :: integer(), %% Maximum allowed span link count
attribute_per_event_limit = 128 :: integer(), %% Maximum allowed attribute per span event count
attribute_per_link_limit = 128 :: integer() %% Maximum allowed attribute per span link count
-record(limits, {
attribute_count_limit = 128 :: integer(), %% Maximum allowed attribute count;
attribute_value_length_limit = infinity :: integer() | infinity, %% Maximum allowed attribute value length
span_attribute_count_limit = undefined :: integer() | undefined, %% Maximum allowed attribute count per span;
span_attribute_value_length_limit = undefined :: integer() | infinity | undefined, %% Maximum allowed attribute value length on span attributes
event_count_limit = 128 :: integer(), %% Maximum allowed span event count
link_count_limit = 128 :: integer(), %% Maximum allowed span link count
attribute_per_event_limit = 128 :: integer(), %% Maximum allowed attribute per span event count
attribute_per_link_limit = 128 :: integer() %% Maximum allowed attribute per span link count
}).

-record(link, {
Expand Down
2 changes: 1 addition & 1 deletion apps/opentelemetry/src/opentelemetry_app.erl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ start(_StartType, _StartArgs) ->
SupResult;
_ ->
%% set global span limits record based on configuration
otel_span_limits:set(Config),
otel_limits:set(Config),

Resource = otel_resource_detector:get_resource(),
_ = otel_tracer_provider_sup:start(?GLOBAL_TRACER_PROVIDER_NAME, Resource, Config),
Expand Down
24 changes: 14 additions & 10 deletions apps/opentelemetry/src/otel_configuration.erl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
storage_size => integer() | infinity},
attribute_count_limit := integer(),
attribute_value_length_limit := integer() | infinity,
span_attribute_count_limit := integer(),
span_attribute_value_length_limit := integer() | infinity,
event_count_limit := integer(),
link_count_limit := integer(),
attribute_per_event_limit := integer(),
Expand Down Expand Up @@ -97,6 +99,8 @@ new() ->
storage_size => infinity},
attribute_count_limit => 128,
attribute_value_length_limit => infinity,
span_attribute_count_limit => undefined,
span_attribute_value_length_limit => undefined,
event_count_limit => 128,
link_count_limit => 128,
attribute_per_event_limit => 128,
Expand All @@ -108,15 +112,15 @@ merge_with_os(AppEnv) ->

lists:foldl(fun(F, Acc) ->
F(AppEnv, Acc)
end, ConfigMap, [fun span_limits/2,
end, ConfigMap, [fun limits/2,
fun general/2,
fun sampler/2,
fun processors/2,
fun sweeper/2]).

-spec span_limits(list(), t()) -> t().
span_limits(AppEnv, ConfigMap) ->
merge_list_with_environment(config_mappings(span_limits), AppEnv, ConfigMap).
-spec limits(list(), t()) -> t().
limits(AppEnv, ConfigMap) ->
merge_list_with_environment(config_mappings(limits), AppEnv, ConfigMap).

-spec general(list(), t()) -> t().
general(AppEnv, ConfigMap) ->
Expand Down Expand Up @@ -322,15 +326,15 @@ config_mappings(general_sdk) ->

{"OTEL_SSP_EXPORT_TIMEOUT_MILLIS", ssp_exporting_timeout_ms, integer}
];
config_mappings(span_limits) ->
[{"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", attribute_count_limit, integer},
{"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", attribute_value_length_limit, integer_infinity},
config_mappings(limits) ->
[{"OTEL_ATTRIBUTE_COUNT_LIMIT", attribute_count_limit, integer},
{"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", attribute_value_length_limit, integer_infinity},
{"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", span_attribute_count_limit, integer},
{"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", span_attribute_value_length_limit, integer_infinity},
{"OTEL_SPAN_EVENT_COUNT_LIMIT", event_count_limit, integer},
{"OTEL_SPAN_LINK_COUNT_LIMIT", link_count_limit, integer},
{"OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT", attribute_per_event_limit, integer},
{"OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", attribute_per_link_limit, integer}%% ,
%% {"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", attribute_value_length_limit, integer},
%% {"OTEL_ATTRIBUTE_COUNT_LIMIT", attribute_per_link_limit, integer}
{"OTEL_LINK_ATTRIBUTE_COUNT_LIMIT", attribute_per_link_limit, integer}
];
config_mappings(sweeper) ->
[{"OTEL_SPAN_SWEEPER_INTERVAL", interval, integer_infinity},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,61 @@
%% limitations under the License.
%%
%% @doc Module for setting the global limits for the number of attributes,
%% events and links on a Span.
%% events and links.
%% @end
%%%-------------------------------------------------------------------------
-module(otel_span_limits).
-module(otel_limits).

-export([get/0,
set/1,
attribute_count_limit/0,
attribute_value_length_limit/0,
span_attribute_count_limit/0,
span_attribute_value_length_limit/0,
event_count_limit/0,
link_count_limit/0,
attribute_per_event_limit/0,
attribute_per_link_limit/0]).

-include("otel_span.hrl").

-define(SPAN_LIMITS_KEY, {?MODULE, span_limits}).
-define(LIMITS_KEY, {?MODULE, limits}).

-spec get() -> #span_limits{}.
-spec get() -> #limits{}.
get() ->
persistent_term:get(?SPAN_LIMITS_KEY).
persistent_term:get(?LIMITS_KEY).

-spec set(otel_configuration:t()) -> ok.
set(#{attribute_count_limit := AttributeCountLimit,
attribute_value_length_limit := AttributeValueLengthLimit,
span_attribute_count_limit := SpanAttributeCountLimit,
span_attribute_value_length_limit := SpanAttributeValueLengthLimit,
event_count_limit := EventCountLimit,
link_count_limit := LinkCountLimit,
attribute_per_event_limit := AttributePerEventLimit,
attribute_per_link_limit := AttributePerLinkLimit}) ->
SpanLimits = #span_limits{attribute_count_limit=AttributeCountLimit,
Limits = #limits{attribute_count_limit=AttributeCountLimit,
attribute_value_length_limit=AttributeValueLengthLimit,
span_attribute_count_limit=SpanAttributeCountLimit,
span_attribute_value_length_limit=SpanAttributeValueLengthLimit,
event_count_limit=EventCountLimit,
link_count_limit=LinkCountLimit,
attribute_per_event_limit=AttributePerEventLimit,
attribute_per_link_limit=AttributePerLinkLimit},
persistent_term:put(?SPAN_LIMITS_KEY, SpanLimits).
persistent_term:put(?LIMITS_KEY, Limits).

attribute_count_limit() ->
get_limit(attribute_count_limit, ?MODULE:get()).

attribute_value_length_limit() ->
get_limit(attribute_value_length_limit, ?MODULE:get()).

span_attribute_count_limit() ->
get_limit(span_attribute_count_limit, ?MODULE:get()).

span_attribute_value_length_limit() ->
get_limit(span_attribute_value_length_limit, ?MODULE:get()).

event_count_limit() ->
get_limit(event_count_limit, ?MODULE:get()).

Expand All @@ -68,15 +80,23 @@
attribute_per_link_limit() ->
get_limit(attribute_per_link_limit, ?MODULE:get()).

get_limit(attribute_count_limit, #span_limits{attribute_count_limit=AttributeCountLimit}) ->
get_limit(attribute_count_limit, #limits{attribute_count_limit=AttributeCountLimit}) ->
AttributeCountLimit;
get_limit(attribute_value_length_limit, #limits{attribute_value_length_limit=AttributeValueLengthLimit}) ->
AttributeValueLengthLimit;
get_limit(span_attribute_count_limit, #limits{span_attribute_count_limit=undefined, attribute_count_limit=AttributeCountLimit}) ->
AttributeCountLimit;
get_limit(attribute_value_length_limit, #span_limits{attribute_value_length_limit=AttributeValueLengthLimit}) ->
get_limit(span_attribute_count_limit, #limits{span_attribute_count_limit=SpanAttributeCountLimit}) ->
SpanAttributeCountLimit;
get_limit(span_attribute_value_length_limit, #limits{span_attribute_value_length_limit=undefined, attribute_value_length_limit=AttributeValueLengthLimit}) ->
AttributeValueLengthLimit;
get_limit(event_count_limit, #span_limits{event_count_limit=EventCountLimit}) ->
get_limit(span_attribute_value_length_limit, #limits{span_attribute_value_length_limit=SpanAttributeValueLengthLimit}) ->
SpanAttributeValueLengthLimit;

Check warning on line 94 in apps/opentelemetry/src/otel_limits.erl

View check run for this annotation

Codecov / codecov/patch

apps/opentelemetry/src/otel_limits.erl#L94

Added line #L94 was not covered by tests
get_limit(event_count_limit, #limits{event_count_limit=EventCountLimit}) ->
EventCountLimit;
get_limit(link_count_limit, #span_limits{link_count_limit=LinkCountLimit}) ->
get_limit(link_count_limit, #limits{link_count_limit=LinkCountLimit}) ->
LinkCountLimit;
get_limit(attribute_per_event_limit, #span_limits{attribute_per_event_limit=AttributePerEventLimit}) ->
get_limit(attribute_per_event_limit, #limits{attribute_per_event_limit=AttributePerEventLimit}) ->
AttributePerEventLimit;
get_limit(attribute_per_link_limit, #span_limits{attribute_per_link_limit=AttributePerLinkLimit}) ->
get_limit(attribute_per_link_limit, #limits{attribute_per_link_limit=AttributePerLinkLimit}) ->
AttributePerLinkLimit.
12 changes: 6 additions & 6 deletions apps/opentelemetry/src/otel_span_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@
-spec start_span(otel_ctx:t(), opentelemetry:span_name(), otel_sampler:t(), otel_id_generator:t(),
otel_span:start_opts()) -> {opentelemetry:span_ctx(), opentelemetry:span() | undefined}.
start_span(Ctx, Name, Sampler, IdGenerator, Opts) ->
SpanAttributeCountLimit = otel_span_limits:attribute_count_limit(),
SpanAttributeValueLengthLimit= otel_span_limits:attribute_value_length_limit(),
EventCountLimit = otel_span_limits:event_count_limit(),
LinkCountLimit = otel_span_limits:link_count_limit(),
AttributePerEventLimit = otel_span_limits:attribute_per_event_limit(),
AttributePerLinkLimit = otel_span_limits:attribute_per_link_limit(),
SpanAttributeCountLimit = otel_limits:span_attribute_count_limit(),
SpanAttributeValueLengthLimit = otel_limits:span_attribute_value_length_limit(),
EventCountLimit = otel_limits:event_count_limit(),
LinkCountLimit = otel_limits:link_count_limit(),
AttributePerEventLimit = otel_limits:attribute_per_event_limit(),
AttributePerLinkLimit = otel_limits:attribute_per_link_limit(),


Attributes = otel_attributes:new(maps:get(attributes, Opts, #{}),
Expand Down
4 changes: 3 additions & 1 deletion apps/opentelemetry/test/opentelemetry_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ init_per_testcase(dropped_attributes, Config) ->
Config1;
init_per_testcase(too_many_attributes, Config) ->
Config1 = set_batch_tab_processor(Config),
application:set_env(opentelemetry, attribute_count_limit, 2),
application:set_env(opentelemetry, attribute_count_limit, 5),
%% this will override the previous one
application:set_env(opentelemetry, span_attribute_count_limit, 2),
{ok, _} = application:ensure_all_started(opentelemetry),
Config1;
init_per_testcase(tracer_instrumentation_scope, Config) ->
Expand Down
62 changes: 36 additions & 26 deletions apps/opentelemetry/test/otel_configuration_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ all() ->
sampler_trace_id, sampler_trace_id_default, sampler_parent_based_one,
log_level, propagators, propagators_b3, propagators_b3multi, otlp_exporter,
jaeger_exporter, zipkin_exporter, none_exporter, app_env_exporter,
otlp_metrics_exporter, none_metrics_exporter, span_limits, bad_span_limits,
otlp_metrics_exporter, none_metrics_exporter, limits, bad_limits,
bad_app_config, deny_list, resource_detectors, span_processors].

init_per_testcase(empty_os_environment, Config) ->
Expand Down Expand Up @@ -139,8 +139,10 @@ init_per_testcase(resource_detectors, Config) ->
setup_env(Vars),

[{os_vars, Vars} | Config];
init_per_testcase(span_limits, Config) ->
Vars = [{"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "111"},
init_per_testcase(limits, Config) ->
Vars = [{"OTEL_ATTRIBUTE_COUNT_LIMIT", "123"},
{"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "4"},
{"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "111"},
{"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "009"},
{"OTEL_SPAN_EVENT_COUNT_LIMIT", "200"},
{"OTEL_SPAN_LINK_COUNT_LIMIT", "1101"},
Expand All @@ -149,22 +151,28 @@ init_per_testcase(span_limits, Config) ->

setup_env(Vars),

ExpectedOpts = #{attribute_count_limit => 111,
attribute_value_length_limit => 9,
ExpectedOpts = #{attribute_count_limit => 123,
attribute_value_length_limit => 4,
span_attribute_count_limit => 111,
span_attribute_value_length_limit => 9,
event_count_limit => 200,
link_count_limit => 1101,
attribute_per_event_limit => 400,
attribute_per_link_limit => 500},
ExpectedRecord = #span_limits{attribute_count_limit=111,
attribute_value_length_limit=9,
event_count_limit=200,
link_count_limit=1101,
attribute_per_event_limit=400,
attribute_per_link_limit=500},
ExpectedRecord = #limits{attribute_count_limit=123,
attribute_value_length_limit=4,
span_attribute_count_limit=111,
span_attribute_value_length_limit=9,
event_count_limit=200,
link_count_limit=1101,
attribute_per_event_limit=400,
attribute_per_link_limit=500},

[{expected_opts, ExpectedOpts}, {expected_record, ExpectedRecord}, {os_vars, Vars} | Config];
init_per_testcase(bad_span_limits, Config) ->
Vars = [{"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "aaa"},
init_per_testcase(bad_limits, Config) ->
Vars = [{"OTEL_ATTRIBUTE_COUNT_LIMIT", "foo"},
{"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT", "4a"},
{"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT", "aaa"},
{"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT", "bbb"},
{"OTEL_SPAN_EVENT_COUNT_LIMIT", "1d4"},
{"OTEL_SPAN_LINK_COUNT_LIMIT", "eee"},
Expand All @@ -174,12 +182,14 @@ init_per_testcase(bad_span_limits, Config) ->
setup_env(Vars),

ExpectedOpts = #{},
ExpectedRecord = #span_limits{attribute_count_limit=128,
attribute_value_length_limit=infinity,
event_count_limit=128,
link_count_limit=128,
attribute_per_event_limit=128,
attribute_per_link_limit=128},
ExpectedRecord = #limits{attribute_count_limit=128,
attribute_value_length_limit=infinity,
span_attribute_count_limit=undefined,
span_attribute_value_length_limit=undefined,
event_count_limit=128,
link_count_limit=128,
attribute_per_event_limit=128,
attribute_per_link_limit=128},

[{expected_opts, ExpectedOpts}, {expected_record, ExpectedRecord}, {os_vars, Vars} | Config];
init_per_testcase(bad_app_config, Config) ->
Expand Down Expand Up @@ -344,28 +354,28 @@ resource_detectors(_Config) ->

ok.

span_limits(Config) ->
compare_span_limits(Config).
limits(Config) ->
compare_limits(Config).

bad_span_limits(Config) ->
compare_span_limits(Config).
bad_limits(Config) ->
compare_limits(Config).

bad_app_config(_Config) ->
?assertMatch(#{attribute_value_length_limit := infinity},
otel_configuration:merge_with_os([{attribute_value_length_limit, "aaa"}])),

ok.

compare_span_limits(Config) ->
compare_limits(Config) ->
ExpectedRecord = ?config(expected_record, Config),
ExpectedOpts = maps:to_list(?config(expected_opts, Config)),
Opts = maps:to_list(otel_configuration:merge_with_os([])),

?assertIsSubset(ExpectedOpts, Opts),

otel_span_limits:set(maps:from_list(Opts)),
otel_limits:set(maps:from_list(Opts)),

SpanLimits = otel_span_limits:get(),
SpanLimits = otel_limits:get(),

%% verifies the defaults because the base record has the defaults set as well
?assertEqual(ExpectedRecord, SpanLimits),
Expand Down
7 changes: 7 additions & 0 deletions apps/opentelemetry_api/include/opentelemetry.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,10 @@
%% developer-facing error message
message = <<"">> :: unicode:unicode_binary()
}).

-record(attributes, {
count_limit :: integer(),
value_length_limit :: integer() | infinity,
dropped :: integer(),
map :: map()
}).
Loading
Loading