Skip to content

Commit c72b11a

Browse files
committed
feat: add TraceAccessLogger
1 parent 66d382c commit c72b11a

File tree

5 files changed

+62
-4
lines changed

5 files changed

+62
-4
lines changed

examples/aiohttp_app.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from asgi_monitor.integrations.aiohttp import MetricsConfig, TracingConfig, setup_metrics, setup_tracing
1111
from asgi_monitor.logging import configure_logging
12+
from asgi_monitor.logging.aiohttp import TraceAccessLogger
1213

1314
logger = logging.getLogger(__name__)
1415

@@ -35,14 +36,14 @@ def create_app() -> Application:
3536
trace.set_tracer_provider(tracer_provider)
3637

3738
trace_config = TracingConfig(tracer_provider=tracer_provider)
38-
metrics_config = MetricsConfig(app_name="aiohttp", include_trace_exemplar=True)
39+
metrics_config = MetricsConfig(app_name="aiohttp")
3940

40-
setup_metrics(app=app, config=metrics_config)
4141
setup_tracing(app=app, config=trace_config)
42+
setup_metrics(app=app, config=metrics_config)
4243

4344
return app
4445

4546

4647
if __name__ == "__main__":
4748
app = create_app()
48-
run_app(app=app, host="127.0.0.1", port=8000)
49+
run_app(app=app, host="127.0.0.1", port=8000, access_log_class=TraceAccessLogger, access_log=logger)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ lint.ignore = [
9393
"ISC001",
9494
"UP035",
9595
"COM812",
96+
"G002"
9697
]
9798

9899
[tool.ruff.lint.per-file-ignores]

src/asgi_monitor/integrations/aiohttp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def build_metrics_middleware(
113113
) -> Callable[..., Coroutine]:
114114
@middleware
115115
async def metrics_middleware(request: Request, handler: Callable) -> Any:
116-
status_code = HTTPInternalServerError().status_code
116+
status_code = HTTPInternalServerError.status_code
117117

118118
method = request.method
119119
path = request.url.path
@@ -193,6 +193,7 @@ async def tracing_middleware(request: Request, handler: Callable) -> Any:
193193
context=extract(request, getter=getter),
194194
kind=trace.SpanKind.SERVER,
195195
) as span:
196+
request.span = span
196197
span.set_attributes(attributes)
197198
start = default_timer()
198199
active_requests_counter.add(1, active_requests_count_attrs)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .logger import TraceAccessLogger
2+
3+
__all__ = ("TraceAccessLogger",)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import contextlib
2+
import logging
3+
from typing import TYPE_CHECKING, Any
4+
5+
from aiohttp.web_log import AccessLogger
6+
from aiohttp.web_request import BaseRequest
7+
from aiohttp.web_response import StreamResponse
8+
from opentelemetry import trace
9+
10+
if TYPE_CHECKING:
11+
from opentelemetry.trace import Span
12+
13+
__all__ = ("TraceAccessLogger",)
14+
15+
16+
class TraceAccessLogger(AccessLogger):
17+
def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None:
18+
if not self.logger.isEnabledFor(logging.INFO):
19+
# Avoid formatting the log line if it will not be emitted.
20+
return
21+
try:
22+
fmt_info = self._format_line(request, response, time)
23+
24+
values = []
25+
extra: dict[str, Any] = {}
26+
for key, value in fmt_info:
27+
values.append(value)
28+
29+
if key.__class__ is str:
30+
extra[key] = value
31+
else:
32+
k1, k2 = key # type: ignore[misc]
33+
dct = extra.get(k1, {}) # type: ignore[has-type]
34+
dct[k2] = value # type: ignore[has-type]
35+
extra[k1] = dct # type: ignore[has-type]
36+
37+
with contextlib.suppress(KeyError, ValueError):
38+
span: Span = request.span # type: ignore[attr-defined]
39+
ctx = span.get_span_context()
40+
service_name = trace.get_tracer_provider().resource.attributes["service.name"] # type: ignore[attr-defined]
41+
parent = getattr(span, "parent", None)
42+
43+
extra["span_id"] = trace.format_span_id(ctx.span_id)
44+
extra["trace_id"] = trace.format_trace_id(ctx.trace_id)
45+
extra["service.name"] = service_name
46+
47+
if parent:
48+
extra["parent_span_id"] = trace.format_span_id(parent.span_id)
49+
50+
self.logger.info(self._log_format % tuple(values), extra=extra)
51+
except Exception:
52+
self.logger.exception("Error in logging")

0 commit comments

Comments
 (0)