Skip to content

Commit e51a6b3

Browse files
authored
Fix log creation issues related to updating the upstream sdk version (#683)
* Update to latest versions of upstream otel-python * Adjust profile log emission and tests, collaboration with Codex * formatting fix * Instrumentation scope was not set correctly
1 parent d461778 commit e51a6b3

File tree

3 files changed

+72
-15
lines changed

3 files changed

+72
-15
lines changed

pyproject.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ classifiers = [
2323
"Programming Language :: Python :: Implementation :: PyPy",
2424
]
2525
dependencies = [
26-
"opentelemetry-api==1.38.0",
27-
"opentelemetry-sdk==1.38.0",
28-
"opentelemetry-propagator-b3==1.38.0",
29-
"opentelemetry-exporter-otlp-proto-grpc==1.38.0",
30-
"opentelemetry-exporter-otlp-proto-http==1.38.0",
31-
"opentelemetry-instrumentation==0.59b0",
32-
"opentelemetry-instrumentation-system-metrics==0.59b0",
33-
"opentelemetry-semantic-conventions==0.59b0",
26+
"opentelemetry-api==1.39.1",
27+
"opentelemetry-sdk==1.39.1",
28+
"opentelemetry-propagator-b3==1.39.1",
29+
"opentelemetry-exporter-otlp-proto-grpc==1.39.1",
30+
"opentelemetry-exporter-otlp-proto-http==1.39.1",
31+
"opentelemetry-instrumentation==0.60b1",
32+
"opentelemetry-instrumentation-system-metrics==0.60b1",
33+
"opentelemetry-semantic-conventions==0.60b1",
3434
"protobuf>=6.31.1", # not our direct dep, prevents installing vulnerable proto versions (CVE‑2025‑4565)
3535
]
3636

src/splunk_otel/profile.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@
1010

1111
import opentelemetry.context
1212
import wrapt
13-
from opentelemetry._logs import Logger, SeverityNumber, get_logger
13+
from opentelemetry._logs import Logger, LogRecord, SeverityNumber, get_logger
1414
from opentelemetry.context import Context
1515
from opentelemetry.instrumentation.version import __version__ as version
16-
from opentelemetry.sdk._logs import LogRecord
16+
from opentelemetry.sdk._logs import ReadWriteLogRecord
1717
from opentelemetry.sdk.environment_variables import OTEL_SERVICE_NAME
1818
from opentelemetry.sdk.resources import Resource
19-
from opentelemetry.trace import TraceFlags
19+
from opentelemetry.trace import (
20+
NonRecordingSpan,
21+
SpanContext,
22+
TraceFlags,
23+
set_span_in_context,
24+
)
2025
from opentelemetry.trace.propagation import _SPAN_KEY
2126

2227
from splunk_otel import profile_pb2
@@ -178,21 +183,40 @@ def mk_log_record(self, stacktraces):
178183
pb_profile = _stacktraces_to_cpu_profile(stacktraces, self.thread_states, self.interval_millis, time_seconds)
179184
pb_profile_str = _pb_profile_to_str(pb_profile)
180185

181-
return LogRecord(
182-
timestamp=int(time_seconds * 1e9),
186+
span_context = SpanContext(
183187
trace_id=0,
184188
span_id=0,
189+
is_remote=False,
185190
trace_flags=TraceFlags(0x01),
191+
)
192+
# Build an explicit Context so LogRecord doesn't fall back to the current span
193+
# (trace_id/span_id=0 are falsy) and keeps the wire format unchanged.
194+
log_context = set_span_in_context(
195+
NonRecordingSpan(span_context),
196+
Context(),
197+
)
198+
log_record = LogRecord(
199+
timestamp=int(time_seconds * 1e9),
200+
context=log_context,
186201
severity_number=SeverityNumber.UNSPECIFIED,
187202
body=pb_profile_str,
188-
resource=self.resource,
189203
attributes={
190204
"profiling.data.format": "pprof-gzip-base64",
191205
"profiling.data.type": "cpu",
192206
"com.splunk.sourcetype": "otel.profiling",
193207
"profiling.data.total.frame.count": total_frame_count,
194208
},
195209
)
210+
instrumentation_scope = getattr(
211+
self.logger,
212+
"_instrumentation_scope",
213+
None,
214+
)
215+
return ReadWriteLogRecord(
216+
log_record=log_record,
217+
resource=self.resource,
218+
instrumentation_scope=instrumentation_scope,
219+
)
196220

197221

198222
def _pb_profile_to_str(pb_profile) -> str:

tests/test_profile.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
import pytest
1010
from google.protobuf.json_format import MessageToDict
1111
from opentelemetry._logs import Logger
12+
from opentelemetry.context import attach, detach
1213
from opentelemetry.sdk.resources import Resource
14+
from opentelemetry.trace import (
15+
NonRecordingSpan,
16+
SpanContext,
17+
TraceFlags,
18+
get_current_span,
19+
set_span_in_context,
20+
)
1321
from splunk_otel import profile_pb2
1422
from splunk_otel.profile import (
1523
_get_line,
@@ -83,13 +91,38 @@ def test_profile_scraper(stacktraces_fixture):
8391
)
8492
ps.tick()
8593

86-
log_record = logger.log_records[0]
94+
log_record = logger.log_records[0].log_record
8795

8896
assert log_record.timestamp == int(time_seconds * 1e9)
8997
assert len(MessageToDict(_pb_profile_from_str(log_record.body))) == 4 # sanity check
9098
assert log_record.attributes["profiling.data.total.frame.count"] == 30
9199

92100

101+
# The "override the current context" stuff for the log record is weird,
102+
# so test it more thorougly
103+
def test_profile_scraper_log_context_overrides_current_span():
104+
logger = _FakeLogger()
105+
ps = _ProfileScraper(Resource({}), {}, 100, logger, time_func=lambda: 1726760000)
106+
span_context = SpanContext(
107+
trace_id=1,
108+
span_id=2,
109+
is_remote=False,
110+
trace_flags=TraceFlags(0x00),
111+
)
112+
token = attach(set_span_in_context(NonRecordingSpan(span_context)))
113+
try:
114+
log_record = ps.mk_log_record([])
115+
# make sure that the fake log emission context set didn't affect "reality"
116+
assert get_current_span().get_span_context().trace_id == 1
117+
finally:
118+
detach(token)
119+
120+
record = log_record.log_record
121+
assert record.trace_id == 0
122+
assert record.span_id == 0
123+
assert record.trace_flags == TraceFlags(0x01)
124+
125+
93126
def _pb_profile_from_str(stringified: str) -> profile_pb2.Profile:
94127
byte_array = base64.b64decode(stringified)
95128
decompressed = gzip.decompress(byte_array)

0 commit comments

Comments
 (0)