Skip to content

Commit

Permalink
Add span collection limit via env vars (#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 894e4a7
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 @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import importlib
# pylint: disable=too-many-lines
import shutil
import subprocess
Expand All @@ -20,7 +21,10 @@
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):
importlib.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 894e4a7

Please sign in to comment.