Skip to content

Commit 2a2127d

Browse files
danjuvtoddbaert
andauthored
fix: Align TracingHook with spec (#342)
* refactor: move after logic to finally_after so evaluation span is created on failure Signed-off-by: Danju Visvanathan <danju.visvanathan@gmail.com> * feat: optionally disable exceptions on evaluation errors Signed-off-by: Danju Visvanathan <danju.visvanathan@gmail.com> * fix: add provider metadata to hook exception Signed-off-by: Danju Visvanathan <danju.visvanathan@gmail.com> * chore: given/when/then comments Signed-off-by: Danju Visvanathan <danju.visvanathan@gmail.com> * fixup: formatting Signed-off-by: Todd Baert <todd.baert@dynatrace.com> --------- Signed-off-by: Danju Visvanathan <danju.visvanathan@gmail.com> Signed-off-by: Todd Baert <todd.baert@dynatrace.com> Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
1 parent c08b414 commit 2a2127d

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

hooks/openfeature-hooks-opentelemetry/src/openfeature/contrib/hook/opentelemetry/__init__.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ class EventAttributes:
2121

2222

2323
class TracingHook(Hook):
24-
def after(
24+
def __init__(self, exclude_exceptions: bool = False):
25+
self.exclude_exceptions = exclude_exceptions
26+
27+
def finally_after(
2528
self,
2629
hook_context: HookContext,
2730
details: FlagEvaluationDetails,
@@ -60,5 +63,15 @@ def after(
6063
def error(
6164
self, hook_context: HookContext, exception: Exception, hints: HookHints
6265
) -> None:
66+
if self.exclude_exceptions:
67+
return
68+
attributes = {
69+
EventAttributes.KEY: hook_context.flag_key,
70+
EventAttributes.RESULT_VALUE: json.dumps(hook_context.default_value),
71+
}
72+
if hook_context.provider_metadata:
73+
attributes[EventAttributes.PROVIDER_NAME] = (
74+
hook_context.provider_metadata.name
75+
)
6376
current_span = trace.get_current_span()
64-
current_span.record_exception(exception)
77+
current_span.record_exception(exception, attributes)

hooks/openfeature-hooks-opentelemetry/tests/test_otel.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def mock_get_current_span(monkeypatch):
1717
monkeypatch.setattr(trace, "get_current_span", Mock())
1818

1919

20-
def test_after(mock_get_current_span):
20+
def test_finally_after(mock_get_current_span):
2121
# Given
2222
hook = TracingHook()
2323
hook_context = HookContext(
@@ -40,7 +40,7 @@ def test_after(mock_get_current_span):
4040
trace.get_current_span.return_value = mock_span
4141

4242
# When
43-
hook.after(hook_context, details, hints={})
43+
hook.finally_after(hook_context, details, hints={})
4444

4545
# Then
4646
mock_span.add_event.assert_called_once_with(
@@ -79,7 +79,7 @@ def test_after_evaluation_error(mock_get_current_span):
7979
trace.get_current_span.return_value = mock_span
8080

8181
# When
82-
hook.after(hook_context, details, hints={})
82+
hook.finally_after(hook_context, details, hints={})
8383

8484
# Then
8585
mock_span.add_event.assert_called_once_with(
@@ -97,6 +97,33 @@ def test_after_evaluation_error(mock_get_current_span):
9797
def test_error(mock_get_current_span):
9898
# Given
9999
hook = TracingHook()
100+
hook_context = HookContext(
101+
flag_key="flag_key",
102+
flag_type=FlagType.BOOLEAN,
103+
default_value=False,
104+
evaluation_context=EvaluationContext(),
105+
provider_metadata=Metadata(name="test-provider"),
106+
)
107+
exception = Exception()
108+
attributes = {
109+
"feature_flag.key": "flag_key",
110+
"feature_flag.result.value": "false",
111+
"feature_flag.provider.name": "test-provider",
112+
}
113+
114+
mock_span = Mock(spec=Span)
115+
trace.get_current_span.return_value = mock_span
116+
117+
# When
118+
hook.error(hook_context, exception, hints={})
119+
120+
# Then
121+
mock_span.record_exception.assert_called_once_with(exception, attributes)
122+
123+
124+
def test_error_exclude_exceptions(mock_get_current_span):
125+
# Given
126+
hook = TracingHook(exclude_exceptions=True)
100127
hook_context = HookContext(
101128
flag_key="flag_key",
102129
flag_type=FlagType.BOOLEAN,
@@ -110,6 +137,29 @@ def test_error(mock_get_current_span):
110137

111138
# When
112139
hook.error(hook_context, exception, hints={})
140+
# Then
141+
mock_span.record_exception.assert_not_called()
142+
143+
144+
def test_error_no_provider_metadata(mock_get_current_span):
145+
# Given
146+
hook = TracingHook()
147+
hook_context = HookContext(
148+
flag_key="flag_key",
149+
flag_type=FlagType.BOOLEAN,
150+
default_value=False,
151+
evaluation_context=EvaluationContext(),
152+
)
153+
exception = Exception()
154+
attributes = {
155+
"feature_flag.key": "flag_key",
156+
"feature_flag.result.value": "false",
157+
}
113158

159+
mock_span = Mock(spec=Span)
160+
trace.get_current_span.return_value = mock_span
161+
162+
# When
163+
hook.error(hook_context, exception, hints={})
114164
# Then
115-
mock_span.record_exception.assert_called_once_with(exception)
165+
mock_span.record_exception.assert_called_once_with(exception, attributes)

0 commit comments

Comments
 (0)