Skip to content

Commit 39660af

Browse files
committed
refactor: AIOHTTP server and client instrumentation
Signed-off-by: Paulo Vital <[email protected]>
1 parent cfb61dc commit 39660af

File tree

4 files changed

+131
-87
lines changed

4 files changed

+131
-87
lines changed

src/instana/__init__.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,10 @@ def boot_agent():
184184
# sanic_inst, # noqa: F401
185185
urllib3, # noqa: F401
186186
)
187-
188-
# from instana.instrumentation.aiohttp import (
189-
# client, # noqa: F401
190-
# server, # noqa: F401
191-
# )
187+
from instana.instrumentation.aiohttp import (
188+
client, # noqa: F401
189+
server, # noqa: F401
190+
)
192191
# from instana.instrumentation.aws import lambda_inst # noqa: F401
193192
# from instana.instrumentation.celery import hooks # noqa: F401
194193
from instana.instrumentation.django import middleware # noqa: F401

src/instana/instrumentation/aiohttp/client.py

Lines changed: 71 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,85 +2,111 @@
22
# (c) Copyright Instana Inc. 2019
33

44

5-
import opentracing
5+
from types import SimpleNamespace
6+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Tuple
67
import wrapt
78

8-
from ...log import logger
9-
from ...singletons import agent, async_tracer
10-
from ...util.secrets import strip_secrets_from_query
11-
from ...util.traceutils import tracing_is_off
9+
from opentelemetry.semconv.trace import SpanAttributes
10+
11+
from instana.log import logger
12+
from instana.propagators.format import Format
13+
from instana.singletons import agent
14+
from instana.util.secrets import strip_secrets_from_query
15+
from instana.util.traceutils import get_tracer_tuple, tracing_is_off
1216

1317
try:
1418
import aiohttp
15-
import asyncio
1619

20+
if TYPE_CHECKING:
21+
from aiohttp.client import ClientSession
22+
from instana.span.span import InstanaSpan
1723

18-
async def stan_request_start(session, trace_config_ctx, params):
24+
async def stan_request_start(
25+
session: "ClientSession", trace_config_ctx: SimpleNamespace, params
26+
) -> Awaitable[None]:
1927
try:
2028
# If we're not tracing, just return
2129
if tracing_is_off():
22-
trace_config_ctx.scope = None
30+
trace_config_ctx.span_context = None
2331
return
2432

25-
scope = async_tracer.start_active_span("aiohttp-client", child_of=async_tracer.active_span)
26-
trace_config_ctx.scope = scope
33+
tracer, parent_span, _ = get_tracer_tuple()
34+
parent_context = parent_span.get_span_context() if parent_span else None
35+
36+
span = tracer.start_span("aiohttp-client", span_context=parent_context)
2737

28-
async_tracer.inject(scope.span.context, opentracing.Format.HTTP_HEADERS, params.headers)
38+
tracer.inject(span.context, Format.HTTP_HEADERS, params.headers)
2939

30-
parts = str(params.url).split('?')
40+
parts = str(params.url).split("?")
3141
if len(parts) > 1:
32-
cleaned_qp = strip_secrets_from_query(parts[1], agent.options.secrets_matcher,
33-
agent.options.secrets_list)
34-
scope.span.set_tag("http.params", cleaned_qp)
35-
scope.span.set_tag("http.url", parts[0])
36-
scope.span.set_tag('http.method', params.method)
42+
cleaned_qp = strip_secrets_from_query(
43+
parts[1], agent.options.secrets_matcher, agent.options.secrets_list
44+
)
45+
span.set_attribute("http.params", cleaned_qp)
46+
span.set_attribute(SpanAttributes.HTTP_URL, parts[0])
47+
span.set_attribute(SpanAttributes.HTTP_METHOD, params.method)
48+
trace_config_ctx.span_context = span
3749
except Exception:
38-
logger.debug("stan_request_start", exc_info=True)
50+
logger.debug("aiohttp-client stan_request_start error:", exc_info=True)
3951

40-
41-
async def stan_request_end(session, trace_config_ctx, params):
52+
async def stan_request_end(
53+
session: "ClientSession", trace_config_ctx: SimpleNamespace, params
54+
) -> Awaitable[None]:
4255
try:
43-
scope = trace_config_ctx.scope
44-
if scope is not None:
45-
scope.span.set_tag('http.status_code', params.response.status)
56+
span: "InstanaSpan" = trace_config_ctx.span_context
57+
if span:
58+
span.set_attribute(
59+
SpanAttributes.HTTP_STATUS_CODE, params.response.status
60+
)
4661

47-
if agent.options.extra_http_headers is not None:
62+
if agent.options.extra_http_headers:
4863
for custom_header in agent.options.extra_http_headers:
4964
if custom_header in params.response.headers:
50-
scope.span.set_tag("http.header.%s" % custom_header, params.response.headers[custom_header])
65+
span.set_attribute(
66+
"http.header.%s" % custom_header,
67+
params.response.headers[custom_header],
68+
)
5169

5270
if 500 <= params.response.status:
53-
scope.span.mark_as_errored({"http.error": params.response.reason})
71+
span.mark_as_errored({"http.error": params.response.reason})
5472

55-
scope.close()
73+
if span.is_recording():
74+
span.end()
75+
trace_config_ctx = None
5676
except Exception:
57-
logger.debug("stan_request_end", exc_info=True)
58-
77+
logger.debug("aiohttp-client stan_request_end error:", exc_info=True)
5978

60-
async def stan_request_exception(session, trace_config_ctx, params):
79+
async def stan_request_exception(
80+
session: "ClientSession", trace_config_ctx: SimpleNamespace, params
81+
) -> Awaitable[None]:
6182
try:
62-
scope = trace_config_ctx.scope
63-
if scope is not None:
64-
scope.span.log_exception(params.exception)
65-
scope.span.set_tag("http.error", str(params.exception))
66-
scope.close()
83+
span: "InstanaSpan" = trace_config_ctx.span_context
84+
if span:
85+
span.record_exception(params.exception)
86+
span.set_attribute("http.error", str(params.exception))
87+
if span.is_recording():
88+
span.end()
89+
trace_config_ctx = None
6790
except Exception:
68-
logger.debug("stan_request_exception", exc_info=True)
69-
70-
71-
@wrapt.patch_function_wrapper('aiohttp.client', 'ClientSession.__init__')
72-
def init_with_instana(wrapped, instance, argv, kwargs):
91+
logger.debug("aiohttp-client stan_request_exception error:", exc_info=True)
92+
93+
@wrapt.patch_function_wrapper("aiohttp.client", "ClientSession.__init__")
94+
def init_with_instana(
95+
wrapped: Callable[..., Awaitable["ClientSession"]],
96+
instance: aiohttp.client.ClientSession,
97+
args: Tuple[int, str, Tuple[object, ...]],
98+
kwargs: Dict[str, Any],
99+
) -> object:
73100
instana_trace_config = aiohttp.TraceConfig()
74101
instana_trace_config.on_request_start.append(stan_request_start)
75102
instana_trace_config.on_request_end.append(stan_request_end)
76103
instana_trace_config.on_request_exception.append(stan_request_exception)
77-
if 'trace_configs' in kwargs:
78-
kwargs['trace_configs'].append(instana_trace_config)
104+
if "trace_configs" in kwargs:
105+
kwargs["trace_configs"].append(instana_trace_config)
79106
else:
80-
kwargs['trace_configs'] = [instana_trace_config]
81-
82-
return wrapped(*argv, **kwargs)
107+
kwargs["trace_configs"] = [instana_trace_config]
83108

109+
return wrapped(*args, **kwargs)
84110

85111
logger.debug("Instrumenting aiohttp client")
86112
except ImportError:

src/instana/instrumentation/aiohttp/server.py

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,58 @@
22
# (c) Copyright Instana Inc. 2019
33

44

5-
import opentracing
5+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Tuple
6+
67
import wrapt
8+
from opentelemetry.semconv.trace import SpanAttributes
9+
10+
from instana.log import logger
11+
from instana.propagators.format import Format
12+
from instana.singletons import agent, tracer
13+
from instana.util.secrets import strip_secrets_from_query
714

8-
from ...log import logger
9-
from ...singletons import agent, async_tracer
10-
from ...util.secrets import strip_secrets_from_query
15+
if TYPE_CHECKING:
16+
from instana.span.span import InstanaSpan
1117

1218
try:
1319
import aiohttp
14-
import asyncio
15-
1620
from aiohttp.web import middleware
1721

22+
if TYPE_CHECKING:
23+
import aiohttp.web
1824

1925
@middleware
20-
async def stan_middleware(request, handler):
26+
async def stan_middleware(
27+
request: "aiohttp.web.Request",
28+
handler: Callable[..., object],
29+
) -> Awaitable["aiohttp.web.Response"]:
2130
try:
22-
ctx = async_tracer.extract(opentracing.Format.HTTP_HEADERS, request.headers)
23-
request['scope'] = async_tracer.start_active_span('aiohttp-server', child_of=ctx)
24-
scope = request['scope']
31+
span_context = tracer.extract(Format.HTTP_HEADERS, request.headers)
32+
span: "InstanaSpan" = tracer.start_span(
33+
"aiohttp-server", span_context=span_context
34+
)
35+
request["span"] = span
2536

2637
# Query param scrubbing
2738
url = str(request.url)
28-
parts = url.split('?')
39+
parts = url.split("?")
2940
if len(parts) > 1:
30-
cleaned_qp = strip_secrets_from_query(parts[1],
31-
agent.options.secrets_matcher,
32-
agent.options.secrets_list)
33-
scope.span.set_tag("http.params", cleaned_qp)
41+
cleaned_qp = strip_secrets_from_query(
42+
parts[1], agent.options.secrets_matcher, agent.options.secrets_list
43+
)
44+
span.set_attribute("http.params", cleaned_qp)
3445

35-
scope.span.set_tag("http.url", parts[0])
36-
scope.span.set_tag("http.method", request.method)
46+
span.set_attribute(SpanAttributes.HTTP_URL, parts[0])
47+
span.set_attribute(SpanAttributes.HTTP_METHOD, request.method)
3748

3849
# Custom header tracking support
39-
if agent.options.extra_http_headers is not None:
50+
if agent.options.extra_http_headers:
4051
for custom_header in agent.options.extra_http_headers:
4152
if custom_header in request.headers:
42-
scope.span.set_tag("http.header.%s" % custom_header, request.headers[custom_header])
53+
span.set_attribute(
54+
"http.header.%s" % custom_header,
55+
request.headers[custom_header],
56+
)
4357

4458
response = None
4559
try:
@@ -52,33 +66,38 @@ async def stan_middleware(request, handler):
5266
if response is not None:
5367
# Mark 500 responses as errored
5468
if 500 <= response.status:
55-
scope.span.mark_as_errored()
69+
span.mark_as_errored()
5670

57-
scope.span.set_tag("http.status_code", response.status)
58-
async_tracer.inject(scope.span.context, opentracing.Format.HTTP_HEADERS, response.headers)
59-
response.headers['Server-Timing'] = "intid;desc=%s" % scope.span.context.trace_id
71+
span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, response.status)
72+
tracer.inject(span.context, Format.HTTP_HEADERS, response.headers)
73+
response.headers["Server-Timing"] = (
74+
f"intid;desc={span.context.trace_id}"
75+
)
6076

6177
return response
6278
except Exception as exc:
63-
logger.debug("aiohttp stan_middleware", exc_info=True)
64-
if scope is not None:
65-
scope.span.set_tag("http.status_code", 500)
66-
scope.span.log_exception(exc)
79+
logger.debug("aiohttp server stan_middleware:", exc_info=True)
80+
if span:
81+
span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, 500)
82+
span.record_exception(exc)
6783
raise
6884
finally:
69-
if scope is not None:
70-
scope.close()
71-
72-
73-
@wrapt.patch_function_wrapper('aiohttp.web', 'Application.__init__')
74-
def init_with_instana(wrapped, instance, argv, kwargs):
85+
if span and span.is_recording():
86+
span.end()
87+
88+
@wrapt.patch_function_wrapper("aiohttp.web", "Application.__init__")
89+
def init_with_instana(
90+
wrapped: Callable[..., "aiohttp.web.Application.__init__"],
91+
instance: "aiohttp.web.Application",
92+
args: Tuple[int, str, Tuple[Any, ...]],
93+
kwargs: Dict[str, Any],
94+
) -> object:
7595
if "middlewares" in kwargs:
7696
kwargs["middlewares"].insert(0, stan_middleware)
7797
else:
7898
kwargs["middlewares"] = [stan_middleware]
7999

80-
return wrapped(*argv, **kwargs)
81-
100+
return wrapped(*args, **kwargs)
82101

83102
logger.debug("Instrumenting aiohttp server")
84103
except ImportError:

src/instana/propagators/http_propagator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ def inject_key_value(carrier, key, value):
5353
if span_context.suppression:
5454
return
5555

56-
inject_key_value(carrier, self.HEADER_KEY_T, trace_id)
57-
inject_key_value(carrier, self.HEADER_KEY_S, span_id)
56+
inject_key_value(carrier, self.HEADER_KEY_T, str(trace_id))
57+
inject_key_value(carrier, self.HEADER_KEY_S, str(span_id))
5858

5959
except Exception:
6060
logger.debug("inject error:", exc_info=True)

0 commit comments

Comments
 (0)