def instrument_stdlib_urllib(self, module): def wrapper(wrapped, instance, args, kwargs): http_class, req = args status = None if ((capture_hosts.get("*", False) or capture_hosts.get(req.host.lower(), False)) and not ignore_hosts.get(req.host.lower(), False)): with self.span("http") as span: try: response = wrapped(*args, **kwargs) return response finally: if response: status = response.code span.set_tag("requestHostname", req.host.lower()) span.set_tag("requestPath", urlparse(req.get_full_url()).path) span.set_tag("httpMethod", req.get_method()) span.set_tag("httpStatus", status) else: return wrapped(*args, **kwargs) try: wrapt.wrap_function_wrapper(module, "AbstractHTTPHandler.do_open", wrapper) except ImportError: pass
def instrument_botocore(self): def wrapper(wrapped, instance, args, kwargs): with self.span("aws") as span: try: response = wrapped(*args, **kwargs) return response except Exception as error: response = error.response raise error finally: span.set_tag("requestHostname", instance._endpoint.host.split("://")[1]) span.set_tag( "aws", { "region": instance.meta.region_name, "service": instance._service_model.service_name, "operation": args[0], "requestId": response.get("ResponseMetadata", {}).get("RequestId"), "errorCode": response.get("Error", {}).get("Code"), }, ) try: wrapt.wrap_function_wrapper("botocore.client", "BaseClient._make_api_call", wrapper) except ImportError: pass
def instrument_urllib3(self): def wrapper(wrapped, instance, args, kwargs): if "method" in kwargs: method = kwargs["method"] else: method = args[0] if "url" in kwargs: path = kwargs["url"] else: path = args[1] user_agent = kwargs.get("headers", {}).get("User-Agent", "") # sometimes ua is binary string sometimes a normal string :/ if hasattr(user_agent, "decode"): user_agent = user_agent.decode() status = None if ( ( # Ignore http calls from boto not user_agent.startswith("Boto3") or os.environ.get( "SERVERLESS_ENTERPRISE_SPANS_CAPTURE_AWS_SDK_HTTP" ) ) and ( capture_hosts.get("*", False) or capture_hosts.get(instance.host.lower(), False) ) and not ignore_hosts.get(instance.host.lower(), False) ): with self.span("http") as span: span.set_tag("requestHostname", instance.host) span.set_tag("requestPath", path) span.set_tag("httpMethod", method) try: response = wrapped(*args, **kwargs) return response except Exception as e: response = None span.set_tag("httpStatus", "Exc") raise e finally: if response: span.set_tag("httpStatus", response.status) else: return wrapped(*args, **kwargs) try: wrapt.wrap_function_wrapper( "urllib3.connectionpool", "HTTPConnectionPool.urlopen", wrapper ) except ImportError: pass try: wrapt.wrap_function_wrapper( "botocore.vendored.requests.packages.urllib3.connectionpool", "HTTPConnectionPool.urlopen", wrapper, ) except ImportError: pass
def instrument_flask(self, module): def wrap_add_url_rule(wrapped, app, args, kwargs): args = list(args) rule = args.pop(0) try: endpoint = kwargs.pop('endpoint') except KeyError: endpoint = args.pop(0) try: view_func = kwargs.pop('view_func') except KeyError: view_func = args.pop(0) def wrap_view_func(**req_args): try: return view_func(**req_args) finally: try: from flask import request set_endpoint(rule, http_method=request.method, meta={"mechanism": "flask-middleware"}) except: pass wrap_view_func.__name__ = view_func.__name__ return wrapped(rule, endpoint, wrap_view_func, *args, **kwargs) def wrap_init(wrapped, app, args, kwargs): wrapped(*args, **kwargs) try: def after(response): try: from flask import request try: status = response.status_code.value # http.HTTPStatus? except: status = response.status_code or response.default_status path = request.path if status == 404 or status >= 500 else None set_endpoint(path, http_method=request.method, http_status_code=status, meta={"mechanism": "flask-middleware"}) except: pass return response app.after_request(after) except: pass try: wrapt.wrap_function_wrapper(module, "Flask.add_url_rule", wrap_add_url_rule) wrapt.wrap_function_wrapper(module, "Flask.__init__", wrap_init) except ImportError: pass
def instrument_botocore(self): def wrapper(wrapped, instance, args, kwargs): start_isoformat = datetime.utcnow().isoformat() + 'Z' start = time.time() try: response = wrapped(*args, **kwargs) return response except Exception as error: response = error.response raise error finally: end_isoformat = datetime.utcnow().isoformat() + 'Z' self.spans.append({ "tags": { "type": "aws", "requestHostname": instance._endpoint.host.split("://")[1], "aws": { "region": instance.meta.region_name, "service": instance._service_model.service_name, "operation": args[0], "requestId": response.get("ResponseMetadata", {}).get("RequestId"), "errorCode": response.get("Error", {}).get("Code"), }, }, "startTime": start_isoformat, "endTime": end_isoformat, "duration": int((time.time() - start) * 1000), }) wrapt.wrap_function_wrapper( 'botocore.client', 'BaseClient._make_api_call', wrapper, )
def instrument_flask(self, module): def wrap_init(wrapped, app, args, kwargs): wrapped(*args, **kwargs) app_dispatch_request = app.dispatch_request def dispatch_request(self): try: from flask import _request_ctx_stack req = _request_ctx_stack.top.request set_endpoint(endpoint=req.url_rule.rule, meta={"mechanism": "flask-middleware"}) except: pass return app_dispatch_request() from types import MethodType app.dispatch_request = MethodType(dispatch_request, app) try: def after(response): try: from flask import request try: status = response.status_code.value # http.HTTPStatus? except: status = response.status_code or response.default_status set_endpoint(endpoint=None, http_method=request.method, http_status_code=status, meta={"mechanism": "flask-middleware"}) except: pass return response app.after_request(after) except: pass try: wrapt.wrap_function_wrapper(module, "Flask.__init__", wrap_init) except ImportError: pass