Skip to content

Commit b0f07cd

Browse files
authored
Only set up logger and tracer if the lists are not none (#510)
It fixed a minor bug.
1 parent fd94e3c commit b0f07cd

File tree

6 files changed

+105
-79
lines changed

6 files changed

+105
-79
lines changed

dbos/_dbos_config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,7 @@ def load_config(
264264
data["telemetry"]["OTLPExporter"]["tracesEndpoint"]
265265
]
266266

267-
data = cast(ConfigFile, data)
268-
return data
267+
return cast(ConfigFile, data)
269268

270269

271270
def process_config(

dbos/_logger.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def config_logger(config: "ConfigFile") -> None:
7979

8080
# Only set up OTLP provider and exporter if endpoints are provided
8181
log_provider = get_logger_provider()
82-
if otlp_logs_endpoints is not None:
82+
if otlp_logs_endpoints is not None and len(otlp_logs_endpoints) > 0:
8383
if not isinstance(log_provider, LoggerProvider):
8484
log_provider = LoggerProvider(
8585
Resource.create(
@@ -100,10 +100,11 @@ def config_logger(config: "ConfigFile") -> None:
100100

101101
# Even if no endpoints are provided, we still need a LoggerProvider to create the LoggingHandler
102102
global _otlp_handler
103-
_otlp_handler = LoggingHandler(logger_provider=log_provider)
103+
if _otlp_handler is None:
104+
_otlp_handler = LoggingHandler(logger_provider=log_provider)
104105

105-
# Direct DBOS logs to OTLP
106-
dbos_logger.addHandler(_otlp_handler)
106+
# Direct DBOS logs to OTLP
107+
dbos_logger.addHandler(_otlp_handler)
107108

108109
# Attach DBOS-specific attributes to all log entries.
109110
global _dbos_log_transformer

dbos/_tracer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def config(self, config: ConfigFile) -> None:
4545
tracer_provider = trace.get_tracer_provider()
4646

4747
# Only set up OTLP provider and exporter if endpoints are provided
48-
if otlp_traces_endpoints is not None:
48+
if otlp_traces_endpoints is not None and len(otlp_traces_endpoints) > 0:
4949
if not isinstance(tracer_provider, TracerProvider):
5050
resource = Resource(
5151
attributes={

tests/conftest.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
import sqlalchemy as sa
1111
from fastapi import FastAPI
1212
from flask import Flask
13+
from opentelemetry import trace
14+
from opentelemetry._logs import set_logger_provider
15+
from opentelemetry.sdk import trace as tracesdk
16+
from opentelemetry.sdk._logs import LoggerProvider
17+
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, InMemoryLogExporter
18+
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
19+
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
1320

1421
from dbos import DBOS, DBOSClient, DBOSConfig
1522
from dbos._schemas.system_database import SystemSchema
@@ -54,7 +61,7 @@ def default_config() -> DBOSConfig:
5461
if using_sqlite()
5562
else f"postgresql+psycopg://postgres:{quote(os.environ.get('PGPASSWORD', 'dbos'), safe='')}@localhost:5432/dbostestpy_dbos_sys"
5663
),
57-
"enable_otlp": True,
64+
"enable_otlp": False,
5865
}
5966

6067

@@ -150,9 +157,11 @@ def client(config: DBOSConfig, dbos: DBOS) -> Generator[DBOSClient, Any, None]:
150157

151158

152159
@pytest.fixture()
153-
def dbos_fastapi(
154-
config: DBOSConfig, cleanup_test_databases: None
160+
def dbos_fastapi( # type: ignore
161+
config: DBOSConfig, cleanup_test_databases: None, setup_in_memory_otlp_collector
155162
) -> Generator[Tuple[DBOS, FastAPI], Any, None]:
163+
exporter, log_processor, log_exporter = setup_in_memory_otlp_collector
164+
config["enable_otlp"] = True
156165
DBOS.destroy(destroy_registry=True)
157166
app = FastAPI()
158167
dbos = DBOS(fastapi=app, config=config)
@@ -182,6 +191,37 @@ def dbos_flask(
182191
DBOS.destroy(destroy_registry=True)
183192

184193

194+
# Type for mypy
195+
# define type
196+
TestOtelType = Tuple[
197+
InMemorySpanExporter,
198+
BatchLogRecordProcessor,
199+
InMemoryLogExporter,
200+
]
201+
202+
203+
@pytest.fixture(scope="session")
204+
def setup_in_memory_otlp_collector() -> Generator[
205+
TestOtelType,
206+
Any,
207+
None,
208+
]:
209+
exporter = InMemorySpanExporter()
210+
span_processor = SimpleSpanProcessor(exporter)
211+
provider = tracesdk.TracerProvider()
212+
provider.add_span_processor(span_processor)
213+
trace.set_tracer_provider(provider)
214+
215+
# Set up in-memory log exporter
216+
log_exporter = InMemoryLogExporter() # type: ignore
217+
log_processor = BatchLogRecordProcessor(log_exporter)
218+
log_provider = LoggerProvider()
219+
log_provider.add_log_record_processor(log_processor)
220+
set_logger_provider(log_provider)
221+
222+
yield exporter, log_processor, log_exporter
223+
224+
185225
# Pretty-print test names
186226
def pytest_collection_modifyitems(session: Any, config: Any, items: Any) -> None:
187227
for item in items:

tests/test_fastapi_roles.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,15 @@
1818
from dbos._context import assert_current_dbos_context
1919
from dbos._error import DBOSInitializationError, DBOSNotAuthorizedError
2020
from dbos._sys_db import GetWorkflowsInput
21-
from dbos._tracer import dbos_tracer
21+
from tests.conftest import TestOtelType
2222

2323

2424
@pytest.mark.order(1)
25-
def test_simple_endpoint(dbos_fastapi: Tuple[DBOS, FastAPI]) -> None:
26-
# Set up a simple in-memory span exporter for testing
27-
exporter = InMemorySpanExporter()
28-
span_processor = SimpleSpanProcessor(exporter)
29-
provider = tracesdk.TracerProvider()
30-
provider.add_span_processor(span_processor)
31-
dbos_tracer.set_provider(provider)
25+
def test_simple_endpoint(
26+
dbos_fastapi: Tuple[DBOS, FastAPI], setup_in_memory_otlp_collector: TestOtelType
27+
) -> None:
3228

29+
exporter, log_processor, log_exporter = setup_in_memory_otlp_collector
3330
dbos, app = dbos_fastapi
3431

3532
@app.middleware("http")
@@ -100,6 +97,7 @@ def test_error() -> None:
10097
raise HTTPException(status_code=401)
10198

10299
client = TestClient(app)
100+
exporter.clear()
103101

104102
response = client.get("/user/b")
105103
assert response.status_code == 200

tests/test_spans.py

Lines changed: 49 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
from dataclasses import dataclass, field
2-
from typing import Optional, Tuple
2+
from typing import Optional
33

44
import pytest
55
from fastapi import FastAPI
66
from fastapi.testclient import TestClient
77
from inline_snapshot import snapshot
8-
from opentelemetry.sdk import trace as tracesdk
9-
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
10-
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, InMemoryLogExporter
11-
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
12-
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
8+
from opentelemetry import trace
139
from opentelemetry.trace.span import format_trace_id
1410

1511
from dbos import DBOS, DBOSConfig
16-
from dbos._logger import dbos_logger
17-
from dbos._tracer import dbos_tracer
1812
from dbos._utils import GlobalParams
19-
from tests.conftest import default_config
13+
from tests.conftest import TestOtelType
2014

2115

2216
@dataclass
@@ -26,18 +20,18 @@ class BasicSpan:
2620
parent_id: Optional[int] = field(repr=False, compare=False, default=None)
2721

2822

29-
def test_spans(config: DBOSConfig) -> None:
30-
exporter = InMemorySpanExporter()
31-
span_processor = SimpleSpanProcessor(exporter)
32-
provider = tracesdk.TracerProvider()
33-
provider.add_span_processor(span_processor)
34-
dbos_tracer.set_provider(provider)
23+
def test_spans(
24+
config: DBOSConfig, setup_in_memory_otlp_collector: TestOtelType
25+
) -> None:
26+
exporter, log_processor, log_exporter = setup_in_memory_otlp_collector
3527

3628
DBOS.destroy(destroy_registry=True)
3729
config["otlp_attributes"] = {"foo": "bar"}
30+
config["enable_otlp"] = True
3831
DBOS(config=config)
3932
DBOS.launch()
4033

34+
provider = trace.get_tracer_provider()
4135
my_tracer = provider.get_tracer("dbos")
4236

4337
@DBOS.workflow()
@@ -60,12 +54,9 @@ def test_step() -> None:
6054
DBOS.logger.info("This is a test_step")
6155
return
6256

63-
# Set up in-memory log exporter
64-
log_exporter = InMemoryLogExporter() # type: ignore
65-
log_processor = BatchLogRecordProcessor(log_exporter)
66-
log_provider = LoggerProvider()
67-
log_provider.add_log_record_processor(log_processor)
68-
dbos_logger.addHandler(LoggingHandler(logger_provider=log_provider))
57+
log_processor.force_flush(timeout_millis=5000)
58+
log_exporter.clear() # Clear any logs generated during setup
59+
exporter.clear()
6960

7061
test_workflow()
7162

@@ -157,13 +148,18 @@ def test_step() -> None:
157148

158149

159150
@pytest.mark.asyncio
160-
async def test_spans_async(dbos: DBOS) -> None:
161-
exporter = InMemorySpanExporter()
162-
span_processor = SimpleSpanProcessor(exporter)
163-
provider = tracesdk.TracerProvider()
164-
provider.add_span_processor(span_processor)
165-
dbos_tracer.set_provider(provider)
151+
async def test_spans_async(
152+
config: DBOSConfig, setup_in_memory_otlp_collector: TestOtelType
153+
) -> None:
154+
exporter, log_processor, log_exporter = setup_in_memory_otlp_collector
155+
156+
DBOS.destroy(destroy_registry=True)
157+
config["otlp_attributes"] = {"foo": "bar"}
158+
config["enable_otlp"] = True
159+
DBOS(config=config)
160+
DBOS.launch()
166161

162+
provider = trace.get_tracer_provider()
167163
my_tracer = provider.get_tracer("dbos")
168164

169165
@DBOS.workflow()
@@ -186,12 +182,9 @@ async def test_step() -> None:
186182
DBOS.logger.info("This is a test_step")
187183
return
188184

189-
# Set up in-memory log exporter
190-
log_exporter = InMemoryLogExporter() # type: ignore
191-
log_processor = BatchLogRecordProcessor(log_exporter)
192-
log_provider = LoggerProvider()
193-
log_provider.add_log_record_processor(log_processor)
194-
dbos_logger.addHandler(LoggingHandler(logger_provider=log_provider))
185+
log_processor.force_flush(timeout_millis=5000)
186+
log_exporter.clear() # Clear any logs generated during setup
187+
exporter.clear()
195188

196189
await test_workflow()
197190

@@ -281,27 +274,26 @@ async def test_step() -> None:
281274
)
282275

283276

284-
def test_wf_fastapi(dbos_fastapi: Tuple[DBOS, FastAPI]) -> None:
285-
dbos, app = dbos_fastapi
277+
def test_wf_fastapi(
278+
config: DBOSConfig, setup_in_memory_otlp_collector: TestOtelType
279+
) -> None:
280+
exporter, log_processor, log_exporter = setup_in_memory_otlp_collector
281+
282+
DBOS.destroy(destroy_registry=True)
283+
config["enable_otlp"] = True
284+
app = FastAPI()
285+
dbos = DBOS(fastapi=app, config=config)
286+
DBOS.launch()
286287

287288
@app.get("/wf")
288289
@DBOS.workflow()
289290
def test_workflow_endpoint() -> str:
290291
dbos.logger.info("This is a test_workflow_endpoint")
291292
return "test"
292293

293-
exporter = InMemorySpanExporter()
294-
span_processor = SimpleSpanProcessor(exporter)
295-
provider = tracesdk.TracerProvider()
296-
provider.add_span_processor(span_processor)
297-
dbos_tracer.set_provider(provider)
298-
299-
# Set up in-memory log exporter
300-
log_exporter = InMemoryLogExporter() # type: ignore
301-
log_processor = BatchLogRecordProcessor(log_exporter)
302-
log_provider = LoggerProvider()
303-
log_provider.add_log_record_processor(log_processor)
304-
dbos_logger.addHandler(LoggingHandler(logger_provider=log_provider))
294+
log_processor.force_flush(timeout_millis=5000)
295+
log_exporter.clear() # Clear any logs generated during setup
296+
exporter.clear()
305297

306298
client = TestClient(app)
307299
response = client.get("/wf")
@@ -310,7 +302,8 @@ def test_workflow_endpoint() -> str:
310302

311303
log_processor.force_flush(timeout_millis=5000)
312304
logs = log_exporter.get_finished_logs()
313-
assert len(logs) == 1
305+
306+
assert len(logs) == 2
314307
assert logs[0].log_record.attributes is not None
315308
assert (
316309
logs[0].log_record.attributes["applicationVersion"] == DBOS.application_version
@@ -347,7 +340,11 @@ def test_workflow_endpoint() -> str:
347340
assert logs[0].log_record.trace_id == spans[0].context.trace_id
348341

349342

350-
def test_disable_otlp_no_spans(config: DBOSConfig) -> None:
343+
def test_disable_otlp_no_spans(
344+
config: DBOSConfig, setup_in_memory_otlp_collector: TestOtelType
345+
) -> None:
346+
exporter, log_processor, log_exporter = setup_in_memory_otlp_collector
347+
351348
DBOS.destroy(destroy_registry=True)
352349
config["otlp_attributes"] = {"foo": "bar"}
353350
config["enable_otlp"] = False
@@ -364,18 +361,9 @@ def test_step() -> None:
364361
DBOS.logger.info("This is a test_step")
365362
return
366363

367-
exporter = InMemorySpanExporter()
368-
span_processor = SimpleSpanProcessor(exporter)
369-
provider = tracesdk.TracerProvider()
370-
provider.add_span_processor(span_processor)
371-
dbos_tracer.set_provider(provider)
372-
373-
# Set up in-memory log exporter
374-
log_exporter = InMemoryLogExporter() # type: ignore
375-
log_processor = BatchLogRecordProcessor(log_exporter)
376-
log_provider = LoggerProvider()
377-
log_provider.add_log_record_processor(log_processor)
378-
dbos_logger.addHandler(LoggingHandler(logger_provider=log_provider))
364+
log_processor.force_flush(timeout_millis=5000)
365+
log_exporter.clear() # Clear any logs generated during setup
366+
exporter.clear()
379367

380368
test_workflow()
381369

0 commit comments

Comments
 (0)