Skip to content

Commit 5760c0e

Browse files
author
Eoin Noble
authored
Make event attributes immutable (#1195)
1 parent c7cc4d9 commit 5760c0e

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

opentelemetry-sdk/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
([#1105](https://github.com/open-telemetry/opentelemetry-python/pull/1120))
1111
- Allow for Custom Trace and Span IDs Generation - `IdsGenerator` for TracerProvider
1212
([#1153](https://github.com/open-telemetry/opentelemetry-python/pull/1153))
13+
- Event attributes are now immutable
14+
([#1195](https://github.com/open-telemetry/opentelemetry-python/pull/1195))
1315
- Renaming metrics Batcher to Processor
1416
([#1203](https://github.com/open-telemetry/opentelemetry-python/pull/1203))
1517
- Protect access to Span implementation

opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@
1818
import concurrent.futures
1919
import json
2020
import logging
21-
import random
2221
import threading
2322
import traceback
2423
from collections import OrderedDict
2524
from contextlib import contextmanager
26-
from types import TracebackType
25+
from types import MappingProxyType, TracebackType
2726
from typing import (
2827
Any,
2928
Callable,
@@ -340,6 +339,10 @@ def _filter_attribute_values(attributes: types.Attributes):
340339
attributes.pop(attr_key)
341340

342341

342+
def _create_immutable_attributes(attributes):
343+
return MappingProxyType(attributes.copy() if attributes else {})
344+
345+
343346
class Span(trace_api.Span):
344347
"""See `opentelemetry.trace.Span`.
345348
@@ -408,6 +411,10 @@ def __init__(
408411
if events:
409412
for event in events:
410413
_filter_attribute_values(event.attributes)
414+
# pylint: disable=protected-access
415+
event._attributes = _create_immutable_attributes(
416+
event.attributes
417+
)
411418
self.events.append(event)
412419

413420
if links is None:
@@ -566,8 +573,7 @@ def add_event(
566573
timestamp: Optional[int] = None,
567574
) -> None:
568575
_filter_attribute_values(attributes)
569-
if not attributes:
570-
attributes = self._new_attributes()
576+
attributes = _create_immutable_attributes(attributes)
571577
self._add_event(
572578
Event(
573579
name=name,

opentelemetry-sdk/tests/trace/test_trace.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,6 @@ def test_events(self):
590590
root.add_event("event0")
591591

592592
# event name and attributes
593-
now = time_ns()
594593
root.add_event(
595594
"event1", {"name": "pluto", "some_bools": [True, False]}
596595
)
@@ -628,6 +627,30 @@ def test_events(self):
628627
root.events[3].attributes, {"name": ("original_contents",)}
629628
)
630629

630+
def test_events_are_immutable(self):
631+
event_properties = [
632+
prop for prop in dir(trace.EventBase) if not prop.startswith("_")
633+
]
634+
635+
with self.tracer.start_as_current_span("root") as root:
636+
root.add_event("event0", {"name": ["birthday"]})
637+
event = root.events[0]
638+
639+
for prop in event_properties:
640+
with self.assertRaises(AttributeError):
641+
setattr(event, prop, "something")
642+
643+
def test_event_attributes_are_immutable(self):
644+
with self.tracer.start_as_current_span("root") as root:
645+
root.add_event("event0", {"name": ["birthday"]})
646+
event = root.events[0]
647+
648+
with self.assertRaises(TypeError):
649+
event.attributes["name"][0] = "happy"
650+
651+
with self.assertRaises(TypeError):
652+
event.attributes["name"] = "hello"
653+
631654
def test_invalid_event_attributes(self):
632655
self.assertEqual(trace_api.get_current_span(), trace_api.INVALID_SPAN)
633656

0 commit comments

Comments
 (0)