Skip to content

Commit 231a336

Browse files
authored
Add an option to disable OTLP tracing (#439)
1 parent d4f718c commit 231a336

File tree

5 files changed

+76
-2
lines changed

5 files changed

+76
-2
lines changed

dbos/_context.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ def get_current_span(self) -> Optional[Span]:
221221
return None
222222

223223
def _start_span(self, attributes: TracedAttributes) -> None:
224+
if dbos_tracer.disable_otlp:
225+
return
224226
attributes["operationUUID"] = (
225227
self.workflow_id if len(self.workflow_id) > 0 else None
226228
)
@@ -246,6 +248,8 @@ def _start_span(self, attributes: TracedAttributes) -> None:
246248
cm.__enter__()
247249

248250
def _end_span(self, exc_value: Optional[BaseException]) -> None:
251+
if dbos_tracer.disable_otlp:
252+
return
249253
context_span = self.context_spans.pop()
250254
if exc_value is None:
251255
context_span.span.set_status(Status(StatusCode.OK))

dbos/_dbos_config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class DBOSConfig(TypedDict, total=False):
3333
admin_port (int): Admin port
3434
run_admin_server (bool): Whether to run the DBOS admin server
3535
otlp_attributes (dict[str, str]): A set of custom attributes to apply OTLP-exported logs and traces
36+
application_version (str): Application version
37+
executor_id (str): Executor ID, used to identify the application instance in distributed environments
38+
disable_otlp (bool): If True, disables OTLP tracing and logging. Defaults to False.
3639
"""
3740

3841
name: str
@@ -49,6 +52,7 @@ class DBOSConfig(TypedDict, total=False):
4952
otlp_attributes: Optional[dict[str, str]]
5053
application_version: Optional[str]
5154
executor_id: Optional[str]
55+
disable_otlp: Optional[bool]
5256

5357

5458
class RuntimeConfig(TypedDict, total=False):
@@ -91,6 +95,7 @@ class TelemetryConfig(TypedDict, total=False):
9195
logs: Optional[LoggerConfig]
9296
OTLPExporter: Optional[OTLPExporterConfig]
9397
otlp_attributes: Optional[dict[str, str]]
98+
disable_otlp: Optional[bool]
9499

95100

96101
class ConfigFile(TypedDict, total=False):
@@ -157,6 +162,7 @@ def translate_dbos_config_to_config_file(config: DBOSConfig) -> ConfigFile:
157162
telemetry: TelemetryConfig = {
158163
"OTLPExporter": {"tracesEndpoint": [], "logsEndpoint": []},
159164
"otlp_attributes": config.get("otlp_attributes", {}),
165+
"disable_otlp": config.get("disable_otlp", False),
160166
}
161167
# For mypy
162168
assert telemetry["OTLPExporter"] is not None

dbos/_logger.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ def config_logger(config: "ConfigFile") -> None:
7777
otlp_logs_endpoints = (
7878
config.get("telemetry", {}).get("OTLPExporter", {}).get("logsEndpoint") # type: ignore
7979
)
80-
if otlp_logs_endpoints:
80+
disable_otlp = config.get("telemetry", {}).get("disable_otlp", False) # type: ignore
81+
82+
if not disable_otlp and otlp_logs_endpoints:
8183
log_provider = PatchedOTLPLoggerProvider(
8284
Resource.create(
8385
attributes={

dbos/_tracer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,14 @@ class DBOSTracer:
2424
def __init__(self) -> None:
2525
self.app_id = os.environ.get("DBOS__APPID", None)
2626
self.provider: Optional[TracerProvider] = None
27+
self.disable_otlp: bool = False
2728

2829
def config(self, config: ConfigFile) -> None:
2930
self.otlp_attributes = config.get("telemetry", {}).get("otlp_attributes", {}) # type: ignore
30-
if not isinstance(trace.get_tracer_provider(), TracerProvider):
31+
self.disable_otlp = config.get("telemetry", {}).get("disable_otlp", False) # type: ignore
32+
if not self.disable_otlp and not isinstance(
33+
trace.get_tracer_provider(), TracerProvider
34+
):
3135
resource = Resource(
3236
attributes={
3337
ResourceAttributes.SERVICE_NAME: config["name"],

tests/test_spans.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,61 @@ def test_workflow_endpoint() -> str:
254254
assert spans[0].context is not None
255255
assert logs[0].log_record.span_id == spans[0].context.span_id
256256
assert logs[0].log_record.trace_id == spans[0].context.trace_id
257+
258+
259+
def test_disable_otlp_no_spans(config: DBOSConfig) -> None:
260+
DBOS.destroy(destroy_registry=True)
261+
config["otlp_attributes"] = {"foo": "bar"}
262+
config["disable_otlp"] = True
263+
DBOS(config=config)
264+
DBOS.launch()
265+
266+
@DBOS.workflow()
267+
def test_workflow() -> None:
268+
test_step()
269+
DBOS.logger.info("This is a test_workflow")
270+
271+
@DBOS.step()
272+
def test_step() -> None:
273+
DBOS.logger.info("This is a test_step")
274+
return
275+
276+
exporter = InMemorySpanExporter()
277+
span_processor = SimpleSpanProcessor(exporter)
278+
provider = tracesdk.TracerProvider()
279+
provider.add_span_processor(span_processor)
280+
dbos_tracer.set_provider(provider)
281+
282+
# Set up in-memory log exporter
283+
log_exporter = InMemoryLogExporter() # type: ignore
284+
log_processor = BatchLogRecordProcessor(log_exporter)
285+
log_provider = LoggerProvider()
286+
log_provider.add_log_record_processor(log_processor)
287+
set_logger_provider(log_provider)
288+
dbos_logger.addHandler(LoggingHandler(logger_provider=log_provider))
289+
290+
test_workflow()
291+
292+
log_processor.force_flush(timeout_millis=5000)
293+
logs = log_exporter.get_finished_logs()
294+
assert len(logs) == 2
295+
for log in logs:
296+
assert log.log_record.attributes is not None
297+
assert (
298+
log.log_record.attributes["applicationVersion"] == GlobalParams.app_version
299+
)
300+
assert log.log_record.attributes["executorID"] == GlobalParams.executor_id
301+
assert log.log_record.attributes["foo"] == "bar"
302+
# We disable OTLP, so no span_id or trace_id should be present
303+
assert log.log_record.span_id is not None and log.log_record.span_id == 0
304+
assert log.log_record.trace_id is not None and log.log_record.trace_id == 0
305+
assert (
306+
log.log_record.body == "This is a test_step"
307+
or log.log_record.body == "This is a test_workflow"
308+
)
309+
assert log.log_record.attributes.get("traceId") is None
310+
311+
spans = exporter.get_finished_spans()
312+
313+
# No spans should be created since OTLP is disabled
314+
assert len(spans) == 0

0 commit comments

Comments
 (0)