Skip to content

Commit

Permalink
Add span collection limit via env vars (open-telemetry#1377)
Browse files Browse the repository at this point in the history
This adds support for the following env variables:
* OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT (Maximum allowed span attribute count)
* OTEL_SPAN_EVENT_COUNT_LIMIT (Maximum allowed span event count)
* OTEL_SPAN_LINK_COUNT_LIMIT (Maximum allowed span link count)
  • Loading branch information
LetzNico committed Dec 4, 2020
1 parent 00578e3 commit fd460de
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 8 deletions.
2 changes: 2 additions & 0 deletions opentelemetry-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Released 2020-11-25
- Fix `ParentBased` sampler for implicit parent spans. Fix also `trace_state`
erasure for dropped spans or spans sampled by the `TraceIdRatioBased` sampler.
([#1394](https://github.com/open-telemetry/opentelemetry-python/pull/1394))
- Add support for OTEL_SPAN_{ATTRIBUTE_COUNT_LIMIT,EVENT_COUNT_LIMIT,LINK_COUNT_LIMIT}
([#1377](https://github.com/open-telemetry/opentelemetry-python/pull/1377))

## Version 0.15b0

Expand Down
19 changes: 11 additions & 8 deletions opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

from opentelemetry import context as context_api
from opentelemetry import trace as trace_api
from opentelemetry.configuration import Configuration
from opentelemetry.sdk import util
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import sampling
Expand All @@ -49,9 +50,11 @@

logger = logging.getLogger(__name__)

MAX_NUM_ATTRIBUTES = 1000
MAX_NUM_EVENTS = 1000
MAX_NUM_LINKS = 1000
SPAN_ATTRIBUTE_COUNT_LIMIT = Configuration().get(
"SPAN_ATTRIBUTE_COUNT_LIMIT", 1000
)
SPAN_EVENT_COUNT_LIMIT = Configuration().get("SPAN_EVENT_COUNT_LIMIT", 1000)
SPAN_LINK_COUNT_LIMIT = Configuration().get("SPAN_LINK_COUNT_LIMIT", 1000)
VALID_ATTR_VALUE_TYPES = (bool, str, int, float)


Expand Down Expand Up @@ -446,7 +449,7 @@ def __init__(
self.attributes = self._new_attributes()
else:
self.attributes = BoundedDict.from_map(
MAX_NUM_ATTRIBUTES, attributes
SPAN_ATTRIBUTE_COUNT_LIMIT, attributes
)

self.events = self._new_events()
Expand All @@ -462,7 +465,7 @@ def __init__(
if links is None:
self.links = self._new_links()
else:
self.links = BoundedList.from_seq(MAX_NUM_LINKS, links)
self.links = BoundedList.from_seq(SPAN_LINK_COUNT_LIMIT, links)

self._end_time = None # type: Optional[int]
self._start_time = None # type: Optional[int]
Expand All @@ -483,15 +486,15 @@ def __repr__(self):

@staticmethod
def _new_attributes():
return BoundedDict(MAX_NUM_ATTRIBUTES)
return BoundedDict(SPAN_ATTRIBUTE_COUNT_LIMIT)

@staticmethod
def _new_events():
return BoundedList(MAX_NUM_EVENTS)
return BoundedList(SPAN_EVENT_COUNT_LIMIT)

@staticmethod
def _new_links():
return BoundedList(MAX_NUM_LINKS)
return BoundedList(SPAN_LINK_COUNT_LIMIT)

@staticmethod
def _format_context(context):
Expand Down
50 changes: 50 additions & 0 deletions opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
import shutil
import subprocess
import unittest
from importlib import reload
from logging import ERROR, WARNING
from typing import Optional
from unittest import mock

import pytest

from opentelemetry import trace as trace_api
from opentelemetry.configuration import Configuration
from opentelemetry.context import Context
from opentelemetry.sdk import resources, trace
from opentelemetry.sdk.trace import Resource, sampling
Expand Down Expand Up @@ -1182,3 +1186,49 @@ def test_attributes_to_json(self):
+ date_str
+ '", "attributes": {"key2": "value2"}}], "links": [], "resource": {}}',
)


class TestSpanLimits(unittest.TestCase):
def setUp(self):
# reset global state of configuration object
# pylint: disable=protected-access
Configuration._reset()

def tearDown(self):
# reset global state of configuration object
# pylint: disable=protected-access
Configuration._reset()

@mock.patch.dict(
"os.environ",
{
"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT": "10",
"OTEL_SPAN_EVENT_COUNT_LIMIT": "20",
"OTEL_SPAN_LINK_COUNT_LIMIT": "30",
},
)
def test_span_environment_limits(self):
reload(trace)
tracer = new_tracer()
ids_generator = trace_api.RandomIdsGenerator()
some_links = [
trace_api.Link(
trace_api.SpanContext(
trace_id=ids_generator.generate_trace_id(),
span_id=ids_generator.generate_span_id(),
is_remote=False,
)
)
for _ in range(100)
]
with pytest.raises(ValueError):
with tracer.start_as_current_span("root", links=some_links):
pass

with tracer.start_as_current_span("root") as root:
for idx in range(100):
root.set_attribute("my_attribute_{}".format(idx), 0)
root.add_event("my_event_{}".format(idx))

self.assertEqual(len(root.attributes), 10)
self.assertEqual(len(root.events), 20)

0 comments on commit fd460de

Please sign in to comment.