Skip to content
This repository was archived by the owner on Mar 4, 2026. It is now read-only.

Commit 1df28b9

Browse files
committed
fix(traces): fix traced otel supression
1 parent 9511431 commit 1df28b9

3 files changed

Lines changed: 188 additions & 4 deletions

File tree

‎.github/workflows/publish-dev.yml‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,14 @@ jobs:
6060
6161
Write-Output "Package version set to $DEV_VERSION"
6262
63+
$startMarker = "<!-- DEV_PACKAGE_START -->"
64+
$endMarker = "<!-- DEV_PACKAGE_END -->"
65+
6366
$dependencyMessage = @"
67+
$startMarker
6468
## Development Package
6569
70+
- Use ``uipath pack --nolock`` to get the latest dev build from this PR (requires version range).
6671
- Add this package as a dependency in your pyproject.toml:
6772
6873
``````toml
@@ -83,7 +88,13 @@ jobs:
8388
8489
[tool.uv.sources]
8590
$PROJECT_NAME = { index = "testpypi" }
91+
92+
[tool.uv]
93+
override-dependencies = [
94+
"$PROJECT_NAME>=$MIN_VERSION,<$MAX_VERSION",
95+
]
8696
``````
97+
$endMarker
8798
"@
8899
89100
# Get the owner and repo from the GitHub repository
@@ -101,10 +112,11 @@ jobs:
101112
$pr = Invoke-RestMethod -Uri $prUri -Method Get -Headers $headers
102113
$currentBody = $pr.body
103114
104-
# Check if there's already a development package section
105-
if ($currentBody -match '## Development Package') {
106-
# Replace the existing section with the new dependency message
107-
$newBody = $currentBody -replace '## Development Package(\r?\n|.)*?(?=##|$)', $dependencyMessage
115+
# Check if markers already exist in the PR description
116+
$markerPattern = "(?s)$([regex]::Escape($startMarker)).*?$([regex]::Escape($endMarker))"
117+
if ($currentBody -match $markerPattern) {
118+
# Replace everything between markers (including markers)
119+
$newBody = $currentBody -replace $markerPattern, $dependencyMessage
108120
} else {
109121
# Append the dependency message to the end of the description
110122
$newBody = if ($currentBody) { "$currentBody`n`n$dependencyMessage" } else { $dependencyMessage }

‎src/uipath/core/tracing/decorators.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
from functools import wraps
77
from typing import Any, Callable, Optional
88

9+
from opentelemetry import context as context_api
910
from opentelemetry import trace
11+
from opentelemetry.context import _SUPPRESS_INSTRUMENTATION_KEY
1012
from opentelemetry.trace import NonRecordingSpan, SpanContext, TraceFlags
1113
from opentelemetry.trace.status import StatusCode
1214

@@ -78,6 +80,8 @@ def get_span():
7880
# --------- Sync wrapper ---------
7981
@wraps(func)
8082
def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
83+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
84+
return func(*args, **kwargs)
8185
span_cm, span = get_span()
8286
try:
8387
# Set input attributes BEFORE execution
@@ -113,6 +117,8 @@ def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
113117
# --------- Async wrapper ---------
114118
@wraps(func)
115119
async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
120+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
121+
return await func(*args, **kwargs)
116122
span_cm, span = get_span()
117123
try:
118124
# Set input attributes BEFORE execution
@@ -148,6 +154,10 @@ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
148154
# --------- Generator wrapper ---------
149155
@wraps(func)
150156
def generator_wrapper(*args: Any, **kwargs: Any) -> Any:
157+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
158+
for item in func(*args, **kwargs):
159+
yield item
160+
return
151161
span_cm, span = get_span()
152162
try:
153163
# Set input attributes BEFORE execution
@@ -186,6 +196,10 @@ def generator_wrapper(*args: Any, **kwargs: Any) -> Any:
186196
# --------- Async generator wrapper ---------
187197
@wraps(func)
188198
async def async_generator_wrapper(*args: Any, **kwargs: Any) -> Any:
199+
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
200+
async for item in func(*args, **kwargs):
201+
yield item
202+
return
189203
span_cm, span = get_span()
190204
try:
191205
# Set input attributes BEFORE execution

‎tests/tracing/test_traced.py‎

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,3 +816,161 @@ async def sample_async_generator_function(n):
816816
spans = exporter.get_exported_spans()
817817

818818
assert len(spans) == 0
819+
820+
821+
# --------- Suppress Instrumentation Tests ---------
822+
823+
824+
def test_suppress_instrumentation_sync_function(setup_tracer):
825+
"""Test that suppress_instrumentation prevents spans from being created for sync functions."""
826+
from opentelemetry.instrumentation.utils import suppress_instrumentation
827+
828+
exporter, provider = setup_tracer
829+
830+
@traced()
831+
def sample_function(x, y):
832+
return x + y
833+
834+
# Call without suppression - should create span
835+
result = sample_function(2, 3)
836+
assert result == 5
837+
838+
spans = exporter.get_exported_spans()
839+
assert len(spans) == 1
840+
841+
exporter.clear_exported_spans()
842+
843+
# Call with suppression - should NOT create span
844+
with suppress_instrumentation():
845+
result = sample_function(4, 5)
846+
assert result == 9
847+
848+
provider.shutdown()
849+
spans = exporter.get_exported_spans()
850+
assert len(spans) == 0
851+
852+
853+
@pytest.mark.asyncio
854+
async def test_suppress_instrumentation_async_function(setup_tracer):
855+
"""Test that suppress_instrumentation prevents spans from being created for async functions."""
856+
from opentelemetry.instrumentation.utils import suppress_instrumentation
857+
858+
exporter, provider = setup_tracer
859+
860+
@traced()
861+
async def sample_async_function(x, y):
862+
return x * y
863+
864+
# Call without suppression - should create span
865+
result = await sample_async_function(2, 3)
866+
assert result == 6
867+
868+
await sleep(0.1)
869+
spans = exporter.get_exported_spans()
870+
assert len(spans) == 1
871+
872+
exporter.clear_exported_spans()
873+
874+
# Call with suppression - should NOT create span
875+
with suppress_instrumentation():
876+
result = await sample_async_function(4, 5)
877+
assert result == 20
878+
879+
provider.shutdown()
880+
await sleep(0.1)
881+
spans = exporter.get_exported_spans()
882+
assert len(spans) == 0
883+
884+
885+
def test_suppress_instrumentation_generator_function(setup_tracer):
886+
"""Test that suppress_instrumentation prevents spans from being created for generator functions."""
887+
from opentelemetry.instrumentation.utils import suppress_instrumentation
888+
889+
exporter, provider = setup_tracer
890+
891+
@traced()
892+
def sample_generator_function(n):
893+
for i in range(n):
894+
yield i
895+
896+
# Call without suppression - should create span
897+
results = list(sample_generator_function(3))
898+
assert results == [0, 1, 2]
899+
900+
spans = exporter.get_exported_spans()
901+
assert len(spans) == 1
902+
903+
exporter.clear_exported_spans()
904+
905+
# Call with suppression - should NOT create span
906+
with suppress_instrumentation():
907+
results = list(sample_generator_function(4))
908+
assert results == [0, 1, 2, 3]
909+
910+
provider.shutdown()
911+
spans = exporter.get_exported_spans()
912+
assert len(spans) == 0
913+
914+
915+
@pytest.mark.asyncio
916+
async def test_suppress_instrumentation_async_generator_function(setup_tracer):
917+
"""Test that suppress_instrumentation prevents spans from being created for async generator functions."""
918+
from opentelemetry.instrumentation.utils import suppress_instrumentation
919+
920+
exporter, provider = setup_tracer
921+
922+
@traced()
923+
async def sample_async_generator_function(n):
924+
for i in range(n):
925+
yield i
926+
927+
# Call without suppression - should create span
928+
results = [item async for item in sample_async_generator_function(3)]
929+
assert results == [0, 1, 2]
930+
931+
spans = exporter.get_exported_spans()
932+
assert len(spans) == 1
933+
934+
exporter.clear_exported_spans()
935+
936+
# Call with suppression - should NOT create span
937+
with suppress_instrumentation():
938+
results = [item async for item in sample_async_generator_function(4)]
939+
assert results == [0, 1, 2, 3]
940+
941+
provider.shutdown()
942+
spans = exporter.get_exported_spans()
943+
assert len(spans) == 0
944+
945+
946+
def test_suppress_instrumentation_nested_functions(setup_tracer):
947+
"""Test that suppress_instrumentation prevents spans for nested traced function calls."""
948+
from opentelemetry.instrumentation.utils import suppress_instrumentation
949+
950+
exporter, provider = setup_tracer
951+
952+
@traced()
953+
def inner_function(x):
954+
return x * 2
955+
956+
@traced()
957+
def outer_function(x):
958+
return inner_function(x) + 1
959+
960+
# Call without suppression - should create 2 spans
961+
result = outer_function(5)
962+
assert result == 11
963+
964+
spans = exporter.get_exported_spans()
965+
assert len(spans) == 2
966+
967+
exporter.clear_exported_spans()
968+
969+
# Call with suppression - should NOT create any spans
970+
with suppress_instrumentation():
971+
result = outer_function(10)
972+
assert result == 21
973+
974+
provider.shutdown()
975+
spans = exporter.get_exported_spans()
976+
assert len(spans) == 0

0 commit comments

Comments
 (0)