From 2a7078744f7d3bc01545e886a2df74c07a6c7d0d Mon Sep 17 00:00:00 2001 From: Matt Millar Date: Mon, 25 Jul 2022 17:53:17 +0100 Subject: [PATCH 1/3] Add annotations --- README.md | 7 +++++++ aws_xray_sdk/ext/django/middleware.py | 21 +++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb31e5cf..b71f8b8e 100644 --- a/README.md +++ b/README.md @@ -383,6 +383,13 @@ If `AUTO_PATCH_PARENT_SEGMENT_NAME` is also specified, then a segment parent wil with the supplied name, wrapping the automatic patching so that it captures any dangling subsegments created on the import patching. +### Django in Lambda +X-Ray can't search on http annotations in subsegments. To enable searching the middleware adds the http values as annotations +This allows searching in the X-Ray console like so +``` +annotation.url BEGINSWITH "https://your.url.com/here" +``` + ### Add Flask middleware ```python diff --git a/aws_xray_sdk/ext/django/middleware.py b/aws_xray_sdk/ext/django/middleware.py index bb0c8a3a..9f71eadd 100644 --- a/aws_xray_sdk/ext/django/middleware.py +++ b/aws_xray_sdk/ext/django/middleware.py @@ -50,9 +50,12 @@ def __call__(self, request): recorder=xray_recorder, sampling_req=sampling_req, ) - + http_as_annotations = False if self.in_lambda_ctx: - segment = xray_recorder.begin_subsegment(name) + segment = xray_recorder.begin_subsegment(name, namespace="remote") + # X-Ray can't search/filter subsegments on URL but it can search annotations + # So for lambda to be able to filter by annotation we add these as annotations + http_as_annotations = True else: segment = xray_recorder.begin_segment( name=name, @@ -64,23 +67,37 @@ def __call__(self, request): segment.save_origin_trace_header(xray_header) segment.put_http_meta(http.URL, request.build_absolute_uri()) segment.put_http_meta(http.METHOD, request.method) + if http_as_annotations: + segment.put_annotation(http.URL, request.build_absolute_uri()) + segment.put_annotation(http.METHOD, request.method) if meta.get(USER_AGENT_KEY): segment.put_http_meta(http.USER_AGENT, meta.get(USER_AGENT_KEY)) + if http_as_annotations: + segment.put_annotation(http.USER_AGENT, meta.get(USER_AGENT_KEY)) if meta.get(X_FORWARDED_KEY): # X_FORWARDED_FOR may come from untrusted source so we # need to set the flag to true as additional information segment.put_http_meta(http.CLIENT_IP, meta.get(X_FORWARDED_KEY)) segment.put_http_meta(http.X_FORWARDED_FOR, True) + if http_as_annotations: + segment.put_annotation(http.CLIENT_IP, meta.get(X_FORWARDED_KEY)) + segment.put_annotation(http.X_FORWARDED_FOR, True) elif meta.get(REMOTE_ADDR_KEY): segment.put_http_meta(http.CLIENT_IP, meta.get(REMOTE_ADDR_KEY)) + if http_as_annotations: + segment.put_annotation(http.CLIENT_IP, meta.get(REMOTE_ADDR_KEY)) response = self.get_response(request) segment.put_http_meta(http.STATUS, response.status_code) + if http_as_annotations: + segment.put_annotation(http.STATUS, response.status_code) if response.has_header(CONTENT_LENGTH_KEY): length = int(response[CONTENT_LENGTH_KEY]) segment.put_http_meta(http.CONTENT_LENGTH, length) + if http_as_annotations: + segment.put_annotation(http.CONTENT_LENGTH, length) response[http.XRAY_HEADER] = prepare_response_header(xray_header, segment) if self.in_lambda_ctx: From 3ddb808bc6363b6609caf4608b470fd87185214d Mon Sep 17 00:00:00 2001 From: Matt Millar Date: Tue, 2 Aug 2022 11:37:20 +0100 Subject: [PATCH 2/3] Update based on PR discussions --- README.md | 6 ++++++ aws_xray_sdk/ext/django/conf.py | 1 + aws_xray_sdk/ext/django/middleware.py | 23 +++++++++++++++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b71f8b8e..0788d13e 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,12 @@ subsegments created on the import patching. ### Django in Lambda X-Ray can't search on http annotations in subsegments. To enable searching the middleware adds the http values as annotations This allows searching in the X-Ray console like so + +This is configurable in settings with `URLS_AS_ANNOTATION` that has 3 valid values +`LAMBDA` - the default, which uses URLs as annotations by default if running in a lambda context +`ALL` - do this for every request (useful if running in a mixed lambda/other deployment) +`NONE` - don't do this for any (avoiding hitting the 50 annotation limit) + ``` annotation.url BEGINSWITH "https://your.url.com/here" ``` diff --git a/aws_xray_sdk/ext/django/conf.py b/aws_xray_sdk/ext/django/conf.py index a1b51c0a..1b5c23d0 100644 --- a/aws_xray_sdk/ext/django/conf.py +++ b/aws_xray_sdk/ext/django/conf.py @@ -19,6 +19,7 @@ 'PATCH_MODULES': [], 'AUTO_PATCH_PARENT_SEGMENT_NAME': None, 'IGNORE_MODULE_PATTERNS': [], + 'URLS_AS_ANNOTATION': 'LAMBDA', # 3 valid values, NONE -> don't ever, LAMBDA -> only for AWS Lambdas, ALL -> every time } XRAY_NAMESPACE = 'XRAY_RECORDER' diff --git a/aws_xray_sdk/ext/django/middleware.py b/aws_xray_sdk/ext/django/middleware.py index 9f71eadd..20f3e875 100644 --- a/aws_xray_sdk/ext/django/middleware.py +++ b/aws_xray_sdk/ext/django/middleware.py @@ -1,4 +1,5 @@ import logging +from .conf import settings from aws_xray_sdk.core import xray_recorder from aws_xray_sdk.core.models import http @@ -30,6 +31,14 @@ def __init__(self, get_response): if check_in_lambda() and type(xray_recorder.context) == LambdaContext: self.in_lambda_ctx = True + def _urls_as_annotation(self): + if settings.URLS_AS_ANNOTATION == "LAMBDA" and self.in_lambda_ctx: + return True + elif settings.URLS_AS_ANNOTATION == "ALL": + return True + return False + + # hooks for django version >= 1.10 def __call__(self, request): @@ -50,12 +59,10 @@ def __call__(self, request): recorder=xray_recorder, sampling_req=sampling_req, ) - http_as_annotations = False if self.in_lambda_ctx: segment = xray_recorder.begin_subsegment(name, namespace="remote") # X-Ray can't search/filter subsegments on URL but it can search annotations # So for lambda to be able to filter by annotation we add these as annotations - http_as_annotations = True else: segment = xray_recorder.begin_segment( name=name, @@ -67,36 +74,36 @@ def __call__(self, request): segment.save_origin_trace_header(xray_header) segment.put_http_meta(http.URL, request.build_absolute_uri()) segment.put_http_meta(http.METHOD, request.method) - if http_as_annotations: + if self._urls_as_annotation(): segment.put_annotation(http.URL, request.build_absolute_uri()) segment.put_annotation(http.METHOD, request.method) if meta.get(USER_AGENT_KEY): segment.put_http_meta(http.USER_AGENT, meta.get(USER_AGENT_KEY)) - if http_as_annotations: + if self._urls_as_annotation(): segment.put_annotation(http.USER_AGENT, meta.get(USER_AGENT_KEY)) if meta.get(X_FORWARDED_KEY): # X_FORWARDED_FOR may come from untrusted source so we # need to set the flag to true as additional information segment.put_http_meta(http.CLIENT_IP, meta.get(X_FORWARDED_KEY)) segment.put_http_meta(http.X_FORWARDED_FOR, True) - if http_as_annotations: + if self._urls_as_annotation(): segment.put_annotation(http.CLIENT_IP, meta.get(X_FORWARDED_KEY)) segment.put_annotation(http.X_FORWARDED_FOR, True) elif meta.get(REMOTE_ADDR_KEY): segment.put_http_meta(http.CLIENT_IP, meta.get(REMOTE_ADDR_KEY)) - if http_as_annotations: + if self._urls_as_annotation(): segment.put_annotation(http.CLIENT_IP, meta.get(REMOTE_ADDR_KEY)) response = self.get_response(request) segment.put_http_meta(http.STATUS, response.status_code) - if http_as_annotations: + if self._urls_as_annotation(): segment.put_annotation(http.STATUS, response.status_code) if response.has_header(CONTENT_LENGTH_KEY): length = int(response[CONTENT_LENGTH_KEY]) segment.put_http_meta(http.CONTENT_LENGTH, length) - if http_as_annotations: + if self._urls_as_annotation(): segment.put_annotation(http.CONTENT_LENGTH, length) response[http.XRAY_HEADER] = prepare_response_header(xray_header, segment) From 21cc7fca2ddf3507bab8cf6bdc201b8ffa9e8a1b Mon Sep 17 00:00:00 2001 From: Matt Millar Date: Mon, 8 Aug 2022 17:42:20 +0100 Subject: [PATCH 3/3] Remove namespace='remote' as it's not necessary for indexing --- aws_xray_sdk/ext/django/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_xray_sdk/ext/django/middleware.py b/aws_xray_sdk/ext/django/middleware.py index 20f3e875..d565be61 100644 --- a/aws_xray_sdk/ext/django/middleware.py +++ b/aws_xray_sdk/ext/django/middleware.py @@ -60,7 +60,7 @@ def __call__(self, request): sampling_req=sampling_req, ) if self.in_lambda_ctx: - segment = xray_recorder.begin_subsegment(name, namespace="remote") + segment = xray_recorder.begin_subsegment(name) # X-Ray can't search/filter subsegments on URL but it can search annotations # So for lambda to be able to filter by annotation we add these as annotations else: