|
1 | 1 | import urllib
|
2 | 2 | from aiohttp import web
|
3 | 3 | from multidict import CIMultiDictProxy
|
4 |
| -from opentelemetry import context, trace |
| 4 | +from timeit import default_timer |
| 5 | + |
| 6 | +from opentelemetry import context, trace, metrics |
5 | 7 | from opentelemetry.instrumentation.aiohttp_server.package import _instruments
|
| 8 | +from opentelemetry.instrumentation.aiohttp_server.version import __version__ |
6 | 9 | from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
7 | 10 | from opentelemetry.instrumentation.utils import http_status_to_status_code
|
8 | 11 | from opentelemetry.propagators.textmap import Getter
|
9 | 12 | from opentelemetry.semconv.trace import SpanAttributes
|
| 13 | +from opentelemetry.semconv.metrics import MetricInstruments |
10 | 14 | from opentelemetry.trace.status import Status, StatusCode
|
11 | 15 | from opentelemetry.util.http import get_excluded_urls
|
12 | 16 | from opentelemetry.util.http import remove_url_credentials
|
|
16 | 20 |
|
17 | 21 | _SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation"
|
18 | 22 |
|
| 23 | +_duration_attrs = [ |
| 24 | + SpanAttributes.HTTP_METHOD, |
| 25 | + SpanAttributes.HTTP_HOST, |
| 26 | + SpanAttributes.HTTP_SCHEME, |
| 27 | + SpanAttributes.HTTP_STATUS_CODE, |
| 28 | + SpanAttributes.HTTP_FLAVOR, |
| 29 | + SpanAttributes.HTTP_SERVER_NAME, |
| 30 | + SpanAttributes.NET_HOST_NAME, |
| 31 | + SpanAttributes.NET_HOST_PORT, |
| 32 | + SpanAttributes.HTTP_ROUTE, |
| 33 | +] |
| 34 | + |
| 35 | +_active_requests_count_attrs = [ |
| 36 | + SpanAttributes.HTTP_METHOD, |
| 37 | + SpanAttributes.HTTP_HOST, |
| 38 | + SpanAttributes.HTTP_SCHEME, |
| 39 | + SpanAttributes.HTTP_FLAVOR, |
| 40 | + SpanAttributes.HTTP_SERVER_NAME, |
| 41 | +] |
| 42 | + |
19 | 43 | tracer = trace.get_tracer(__name__)
|
| 44 | +meter = metrics.get_meter(__name__, __version__) |
20 | 45 | _excluded_urls = get_excluded_urls("AIOHTTP_SERVER")
|
21 | 46 |
|
22 | 47 |
|
| 48 | +def _parse_duration_attrs(req_attrs): |
| 49 | + duration_attrs = {} |
| 50 | + for attr_key in _duration_attrs: |
| 51 | + if req_attrs.get(attr_key) is not None: |
| 52 | + duration_attrs[attr_key] = req_attrs[attr_key] |
| 53 | + return duration_attrs |
| 54 | + |
| 55 | + |
| 56 | +def _parse_active_request_count_attrs(req_attrs): |
| 57 | + active_requests_count_attrs = {} |
| 58 | + for attr_key in _active_requests_count_attrs: |
| 59 | + if req_attrs.get(attr_key) is not None: |
| 60 | + active_requests_count_attrs[attr_key] = req_attrs[attr_key] |
| 61 | + return active_requests_count_attrs |
| 62 | + |
| 63 | + |
23 | 64 | def get_default_span_details(request: web.Request) -> Tuple[str, dict]:
|
24 | 65 | """Default implementation for get_default_span_details
|
25 | 66 | Args:
|
@@ -143,19 +184,41 @@ async def middleware(request, handler):
|
143 | 184 |
|
144 | 185 | span_name, additional_attributes = get_default_span_details(request)
|
145 | 186 |
|
| 187 | + req_attrs = collect_request_attributes(request) |
| 188 | + duration_attrs = _parse_duration_attrs(req_attrs) |
| 189 | + active_requests_count_attrs = _parse_active_request_count_attrs(req_attrs) |
| 190 | + |
| 191 | + duration_histogram = meter.create_histogram( |
| 192 | + name=MetricInstruments.HTTP_SERVER_DURATION, |
| 193 | + unit="ms", |
| 194 | + description="measures the duration of the inbound HTTP request", |
| 195 | + ) |
| 196 | + |
| 197 | + active_requests_counter = meter.create_up_down_counter( |
| 198 | + name=MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS, |
| 199 | + unit="requests", |
| 200 | + description="measures the number of concurrent HTTP requests those are currently in flight", |
| 201 | + ) |
| 202 | + |
146 | 203 | with tracer.start_as_current_span(
|
147 | 204 | span_name,
|
148 | 205 | kind=trace.SpanKind.SERVER,
|
149 | 206 | ) as span:
|
150 | 207 | attributes = collect_request_attributes(request)
|
151 | 208 | attributes.update(additional_attributes)
|
152 | 209 | span.set_attributes(attributes)
|
| 210 | + start = default_timer() |
| 211 | + active_requests_counter.add(1, active_requests_count_attrs) |
153 | 212 | try:
|
154 | 213 | resp = await handler(request)
|
155 | 214 | set_status_code(span, resp.status)
|
156 | 215 | except web.HTTPException as ex:
|
157 | 216 | set_status_code(span, ex.status_code)
|
158 | 217 | raise
|
| 218 | + finally: |
| 219 | + duration = max(round((default_timer() - start) * 1000), 0) |
| 220 | + duration_histogram.record(duration, duration_attrs) |
| 221 | + active_requests_counter.add(-1, active_requests_count_attrs) |
159 | 222 | return resp
|
160 | 223 |
|
161 | 224 |
|
|
0 commit comments