Skip to content

Commit 1f9c110

Browse files
🎨 Tracing: instrument logs and ensure traces are propagated through asyncio.Queues (#6857)
1 parent e05d046 commit 1f9c110

File tree

47 files changed

+216
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+216
-20
lines changed

packages/aws-library/requirements/_base.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ opentelemetry-api==1.27.0
142142
# opentelemetry-exporter-otlp-proto-http
143143
# opentelemetry-instrumentation
144144
# opentelemetry-instrumentation-botocore
145+
# opentelemetry-instrumentation-logging
145146
# opentelemetry-instrumentation-redis
146147
# opentelemetry-instrumentation-requests
147148
# opentelemetry-propagator-aws-xray
@@ -160,10 +161,13 @@ opentelemetry-exporter-otlp-proto-http==1.27.0
160161
opentelemetry-instrumentation==0.48b0
161162
# via
162163
# opentelemetry-instrumentation-botocore
164+
# opentelemetry-instrumentation-logging
163165
# opentelemetry-instrumentation-redis
164166
# opentelemetry-instrumentation-requests
165167
opentelemetry-instrumentation-botocore==0.48b0
166168
# via -r requirements/_base.in
169+
opentelemetry-instrumentation-logging==0.48b0
170+
# via -r requirements/../../../packages/service-library/requirements/_base.in
167171
opentelemetry-instrumentation-redis==0.48b0
168172
# via -r requirements/../../../packages/service-library/requirements/_base.in
169173
opentelemetry-instrumentation-requests==0.48b0

packages/service-library/requirements/_base.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ opentelemetry-api
2020
opentelemetry-exporter-otlp
2121
opentelemetry-instrumentation-requests
2222
opentelemetry-instrumentation-redis
23+
opentelemetry-instrumentation-logging
2324
opentelemetry-sdk
2425
psutil
2526
pydantic

packages/service-library/requirements/_base.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ opentelemetry-api==1.27.0
101101
# opentelemetry-exporter-otlp-proto-grpc
102102
# opentelemetry-exporter-otlp-proto-http
103103
# opentelemetry-instrumentation
104+
# opentelemetry-instrumentation-logging
104105
# opentelemetry-instrumentation-redis
105106
# opentelemetry-instrumentation-requests
106107
# opentelemetry-sdk
@@ -117,8 +118,11 @@ opentelemetry-exporter-otlp-proto-http==1.27.0
117118
# via opentelemetry-exporter-otlp
118119
opentelemetry-instrumentation==0.48b0
119120
# via
121+
# opentelemetry-instrumentation-logging
120122
# opentelemetry-instrumentation-redis
121123
# opentelemetry-instrumentation-requests
124+
opentelemetry-instrumentation-logging==0.48b0
125+
# via -r requirements/_base.in
122126
opentelemetry-instrumentation-redis==0.48b0
123127
# via -r requirements/_base.in
124128
opentelemetry-instrumentation-requests==0.48b0

packages/service-library/src/servicelib/async_utils.py

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

9+
from . import tracing
910
from .utils_profiling_middleware import dont_profile, is_profiling, profile_context
1011

1112
logger = logging.getLogger(__name__)
@@ -34,6 +35,7 @@ class Context:
3435

3536
@dataclass
3637
class QueueElement:
38+
tracing_context: tracing.TracingContext
3739
do_profile: bool = False
3840
input: Awaitable | None = None
3941
output: Any | None = None
@@ -162,16 +164,17 @@ async def worker(in_q: Queue[QueueElement], out_q: Queue) -> None:
162164
while True:
163165
element = await in_q.get()
164166
in_q.task_done()
165-
# check if requested to shutdown
166-
try:
167-
do_profile = element.do_profile
168-
awaitable = element.input
169-
if awaitable is None:
170-
break
171-
with profile_context(do_profile):
172-
result = await awaitable
173-
except Exception as e: # pylint: disable=broad-except
174-
result = e
167+
with tracing.use_tracing_context(element.tracing_context):
168+
# check if requested to shutdown
169+
try:
170+
do_profile = element.do_profile
171+
awaitable = element.input
172+
if awaitable is None:
173+
break
174+
with profile_context(do_profile):
175+
result = await awaitable
176+
except Exception as e: # pylint: disable=broad-except
177+
result = e
175178
await out_q.put(result)
176179

177180
logging.info(
@@ -189,6 +192,7 @@ async def worker(in_q: Queue[QueueElement], out_q: Queue) -> None:
189192
queue_input = QueueElement(
190193
input=decorated_function(*args, **kwargs),
191194
do_profile=is_profiling(),
195+
tracing_context=tracing.get_context(),
192196
)
193197
await context.in_queue.put(queue_input)
194198
wrapped_result = await context.out_queue.get()

packages/service-library/src/servicelib/fastapi/tracing.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ def setup_tracing(
7070
):
7171
_logger.warning("Skipping opentelemetry tracing setup")
7272
return
73-
7473
# Set up the tracer provider
7574
resource = Resource(attributes={"service.name": service_name})
7675
trace.set_tracer_provider(TracerProvider(resource=resource))

packages/service-library/src/servicelib/logging_utils.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
from pathlib import Path
1717
from typing import Any, NotRequired, TypeAlias, TypedDict, TypeVar
1818

19+
from settings_library.tracing import TracingSettings
20+
1921
from .logging_utils_filtering import GeneralLogFilter, LoggerName, MessageSubstring
22+
from .tracing import setup_log_tracing
2023
from .utils_secrets import mask_sensitive_data
2124

2225
_logger = logging.getLogger(__name__)
@@ -121,20 +124,41 @@ def config_all_loggers(
121124
*,
122125
log_format_local_dev_enabled: bool,
123126
logger_filter_mapping: dict[LoggerName, list[MessageSubstring]],
127+
tracing_settings: TracingSettings | None,
124128
) -> None:
125129
"""
126130
Applies common configuration to ALL registered loggers
127131
"""
128-
fmt = DEFAULT_FORMATTING
129132
the_manager: logging.Manager = logging.Logger.manager
130133
root_logger = logging.getLogger()
131134

132135
loggers = [root_logger] + [
133136
logging.getLogger(name) for name in the_manager.loggerDict
134137
]
135138

139+
fmt = DEFAULT_FORMATTING
140+
if tracing_settings is not None:
141+
fmt = (
142+
"log_level=%(levelname)s "
143+
"| log_timestamp=%(asctime)s "
144+
"| log_source=%(name)s:%(funcName)s(%(lineno)d) "
145+
"| log_uid=%(log_uid)s "
146+
"| log_oec=%(log_oec)s"
147+
"| log_trace_id=%(otelTraceID)s "
148+
"| log_span_id=%(otelSpanID)s "
149+
"| log_resource.service.name=%(otelServiceName)s "
150+
"| log_trace_sampled=%(otelTraceSampled)s] "
151+
"| log_msg=%(message)s"
152+
)
153+
setup_log_tracing(tracing_settings=tracing_settings)
136154
if log_format_local_dev_enabled:
137155
fmt = LOCAL_FORMATTING
156+
if tracing_settings is not None:
157+
fmt = (
158+
"%(levelname)s: [%(asctime)s/%(processName)s] "
159+
"[log_trace_id=%(otelTraceID)s log_span_id=%(otelSpanID)s log_resource.service.name=%(otelServiceName)s log_trace_sampled=%(otelTraceSampled)s] "
160+
"[%(name)s:%(funcName)s(%(lineno)d)] - %(message)s"
161+
)
138162

139163
for logger in loggers:
140164
_set_logging_handler(
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from contextlib import contextmanager
2+
from typing import TypeAlias
3+
4+
from opentelemetry import context as otcontext
5+
from opentelemetry import trace
6+
from opentelemetry.instrumentation.logging import LoggingInstrumentor
7+
from settings_library.tracing import TracingSettings
8+
9+
TracingContext: TypeAlias = otcontext.Context | None
10+
11+
12+
def _is_tracing() -> bool:
13+
return trace.get_current_span().is_recording()
14+
15+
16+
def get_context() -> TracingContext:
17+
if not _is_tracing():
18+
return None
19+
return otcontext.get_current()
20+
21+
22+
@contextmanager
23+
def use_tracing_context(context: TracingContext):
24+
if context is not None:
25+
otcontext.attach(context)
26+
try:
27+
yield
28+
finally:
29+
if context is not None:
30+
otcontext.detach(context)
31+
32+
33+
def setup_log_tracing(tracing_settings: TracingSettings):
34+
_ = tracing_settings
35+
LoggingInstrumentor().instrument(set_logging_format=False)

packages/simcore-sdk/requirements/_base.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ opentelemetry-api==1.27.0
165165
# opentelemetry-instrumentation-aiopg
166166
# opentelemetry-instrumentation-asyncpg
167167
# opentelemetry-instrumentation-dbapi
168+
# opentelemetry-instrumentation-logging
168169
# opentelemetry-instrumentation-redis
169170
# opentelemetry-instrumentation-requests
170171
# opentelemetry-sdk
@@ -184,6 +185,7 @@ opentelemetry-instrumentation==0.48b0
184185
# opentelemetry-instrumentation-aiopg
185186
# opentelemetry-instrumentation-asyncpg
186187
# opentelemetry-instrumentation-dbapi
188+
# opentelemetry-instrumentation-logging
187189
# opentelemetry-instrumentation-redis
188190
# opentelemetry-instrumentation-requests
189191
opentelemetry-instrumentation-aiopg==0.48b0
@@ -192,6 +194,8 @@ opentelemetry-instrumentation-asyncpg==0.48b0
192194
# via -r requirements/../../../packages/postgres-database/requirements/_base.in
193195
opentelemetry-instrumentation-dbapi==0.48b0
194196
# via opentelemetry-instrumentation-aiopg
197+
opentelemetry-instrumentation-logging==0.48b0
198+
# via -r requirements/../../../packages/service-library/requirements/_base.in
195199
opentelemetry-instrumentation-redis==0.48b0
196200
# via -r requirements/../../../packages/service-library/requirements/_base.in
197201
opentelemetry-instrumentation-requests==0.48b0

services/agent/requirements/_base.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ opentelemetry-api==1.28.2
157157
# opentelemetry-instrumentation-asgi
158158
# opentelemetry-instrumentation-fastapi
159159
# opentelemetry-instrumentation-httpx
160+
# opentelemetry-instrumentation-logging
160161
# opentelemetry-instrumentation-redis
161162
# opentelemetry-instrumentation-requests
162163
# opentelemetry-sdk
@@ -176,6 +177,7 @@ opentelemetry-instrumentation==0.49b2
176177
# opentelemetry-instrumentation-asgi
177178
# opentelemetry-instrumentation-fastapi
178179
# opentelemetry-instrumentation-httpx
180+
# opentelemetry-instrumentation-logging
179181
# opentelemetry-instrumentation-redis
180182
# opentelemetry-instrumentation-requests
181183
opentelemetry-instrumentation-asgi==0.49b2
@@ -184,7 +186,9 @@ opentelemetry-instrumentation-fastapi==0.49b2
184186
# via -r requirements/../../../packages/service-library/requirements/_fastapi.in
185187
opentelemetry-instrumentation-httpx==0.49b2
186188
# via -r requirements/../../../packages/service-library/requirements/_fastapi.in
187-
opentelemetry-instrumentation-redis==0.49b2
189+
opentelemetry-instrumentation-logging==0.48b0
190+
# via -r requirements/../../../packages/service-library/requirements/_base.in
191+
opentelemetry-instrumentation-redis==0.48b0
188192
# via -r requirements/../../../packages/service-library/requirements/_base.in
189193
opentelemetry-instrumentation-requests==0.49b2
190194
# via -r requirements/../../../packages/service-library/requirements/_base.in

services/agent/src/simcore_service_agent/core/application.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def _setup_logger(settings: ApplicationSettings):
3333
config_all_loggers(
3434
log_format_local_dev_enabled=settings.AGENT_VOLUMES_LOG_FORMAT_LOCAL_DEV_ENABLED,
3535
logger_filter_mapping=settings.AGENT_VOLUMES_LOG_FILTER_MAPPING,
36+
tracing_settings=settings.AGENT_TRACING,
3637
)
3738

3839

0 commit comments

Comments
 (0)