def call(self, module, method, wrapped, instance, args, kwargs): signature = "psycopg2.connect" host = kwargs.get("host") if host: signature += " " + compat.text_type(host) port = kwargs.get("port") if port: port = str(port) if int(port) != default_ports.get("postgresql"): host += ":" + port signature += " " + compat.text_type(host) else: # Parse connection string and extract host/port pass destination_info = { "address": kwargs.get("host", "localhost"), "port": int(kwargs.get("port", default_ports.get("postgresql"))), "service": {"name": "postgresql", "resource": "postgresql", "type": "db"}, } with capture_span( signature, span_type="db", span_subtype="postgresql", span_action="connect", extra={"destination": destination_info}, ): return PGConnectionProxy(wrapped(*args, **kwargs), destination_info=destination_info)
async def test_aiomysql_select(instrument, aiomysql_connection, elasticapm_client): try: elasticapm_client.begin_transaction("web.django") async with aiomysql_connection.cursor() as cursor: query = "SELECT * FROM test WHERE `name` LIKE 't%' ORDER BY id" await cursor.execute(query) assert await cursor.fetchall() == ((2, "two"), (3, "three")) elasticapm_client.end_transaction(None, "test-transaction") finally: transactions = elasticapm_client.events[TRANSACTION] spans = elasticapm_client.spans_for_transaction(transactions[0]) span = spans[0] assert span["name"] == "SELECT FROM test" assert span["type"] == "db" assert span["subtype"] == "mysql" assert span["action"] == "query" assert "db" in span["context"] assert span["context"]["db"]["type"] == "sql" assert span["context"]["db"]["statement"] == query assert span["context"]["destination"] == { "address": os.environ.get("MYSQL_HOST", "localhost"), "port": default_ports.get("mysql"), "service": { "name": "mysql", "resource": "mysql", "type": "db" }, }
def call(self, module, method, wrapped, instance, args, kwargs): destination_info = { "address": kwargs.get("host", "localhost"), "port": int(kwargs.get("port", default_ports.get("mysql"))), } return MySQLConnectionProxy(wrapped(*args, **kwargs), destination_info=destination_info)
def get_host_from_url(url): parsed_url = urlparse.urlparse(url) host = parsed_url.hostname or " " if parsed_url.port and default_ports.get(parsed_url.scheme) != parsed_url.port: host += ":" + str(parsed_url.port) return host
def call(self, module, method, wrapped, instance, args, kwargs): if "method" in kwargs: method = kwargs["method"] else: method = args[0] headers = None if "headers" in kwargs: headers = kwargs["headers"] if headers is None: headers = {} kwargs["headers"] = headers host = instance.host if instance.port != default_ports.get(instance.scheme): host += ":" + str(instance.port) if "url" in kwargs: url = kwargs["url"] else: url = args[1] signature = method.upper() + " " + host url = "%s://%s%s" % (instance.scheme, host, url) destination = url_to_destination(url) transaction = execution_context.get_transaction() with capture_span( signature, span_type="external", span_subtype="http", extra={ "http": { "url": url }, "destination": destination }, leaf=True, ) as span: # if urllib3 has been called in a leaf span, this span might be a DroppedSpan. leaf_span = span while isinstance(leaf_span, DroppedSpan): leaf_span = leaf_span.parent if headers is not None: # It's possible that there are only dropped spans, e.g. if we started dropping spans. # In this case, the transaction.id is used parent_id = leaf_span.id if leaf_span else transaction.id trace_parent = transaction.trace_parent.copy_from( span_id=parent_id, trace_options=TracingOptions(recorded=True)) self._set_disttracing_headers(headers, trace_parent, transaction) return wrapped(*args, **kwargs)
def call(self, module, method, wrapped, instance, args, kwargs): if "method" in kwargs: method = kwargs["method"] else: method = args[0] host = instance.host if instance.port != default_ports.get(instance.scheme): host += ":" + str(instance.port) if "url" in kwargs: url = kwargs["url"] else: url = args[1] signature = method.upper() + " " + host url = "%s://%s%s" % (instance.scheme, host, url) destination = url_to_destination(url) transaction = execution_context.get_transaction() with capture_span( signature, span_type="external", span_subtype="http", extra={ "http": { "url": url }, "destination": destination }, leaf=True, ) as span: # if urllib3 has been called in a leaf span, this span might be a DroppedSpan. leaf_span = span while isinstance(leaf_span, DroppedSpan): leaf_span = leaf_span.parent parent_id = leaf_span.id if leaf_span else transaction.id trace_parent = transaction.trace_parent.copy_from( span_id=parent_id, trace_options=TracingOptions(recorded=True)) args, kwargs = update_headers(args, kwargs, instance, transaction, trace_parent) response = wrapped(*args, **kwargs) if response: if span.context: span.context["http"]["status_code"] = response.status span.set_success( ) if response.status < 400 else span.set_failure() return response
def get_host_port(args, kwargs): host = args[0] if args else kwargs.get("server") port = None if not host: host = kwargs.get("host", "localhost") for sep in (",", ":"): if sep in host: host, port = host.rsplit(sep, 1) port = int(port) break if not port: port = int(kwargs.get("port", default_ports.get("mssql"))) return host, port
def call(self, module, method, wrapped, instance, args, kwargs): if "method" in kwargs: method = kwargs["method"] else: method = args[0] headers = None if "headers" in kwargs: headers = kwargs["headers"] if headers is None: headers = {} kwargs["headers"] = headers host = instance.host if instance.port != default_ports.get(instance.scheme): host += ":" + str(instance.port) if "url" in kwargs: url = kwargs["url"] else: url = args[1] signature = method.upper() + " " + host # TODO: reconstruct URL more faithfully, e.g. include port url = instance.scheme + "://" + host + url transaction = execution_context.get_transaction() with capture_span(signature, span_type="external", span_subtype="http", extra={"http": { "url": url }}, leaf=True) as span: # if urllib3 has been called in a leaf span, this span might be a DroppedSpan. leaf_span = span while isinstance(leaf_span, DroppedSpan): leaf_span = leaf_span.parent if headers is not None: # It's possible that there are only dropped spans, e.g. if we started dropping spans. # In this case, the transaction.id is used parent_id = leaf_span.id if leaf_span else transaction.id trace_parent = transaction.trace_parent.copy_from( span_id=parent_id, trace_options=TracingOptions(recorded=True)) headers[constants. TRACEPARENT_HEADER_NAME] = trace_parent.to_string() return wrapped(*args, **kwargs)
def call(self, module, method, wrapped, instance, args, kwargs): destination_info = { "address": args[0] if len(args) else kwargs.get("host", "localhost"), "port": args[4] if len(args) > 4 else int( kwargs.get("port", default_ports.get("mysql"))), "service": { "name": "mysql", "resource": "mysql", "type": "db" }, } return MySQLConnectionProxy(wrapped(*args, **kwargs), destination_info=destination_info)
def get_destination_info(host: Optional[str], port: Union[None, str, int]) -> tuple: if host: if "," in host: # multiple hosts defined, take first host = host.split(",")[0] else: host = "localhost" if port: port = str(port) if "," in port: # multiple ports defined, take first port = port.split(",")[0] port = int(port) else: port = default_ports.get("postgresql") return host, port
def call(self, module, method, wrapped, instance, args, kwargs): signature = "psycopg2.connect" host = kwargs.get('host') if host: signature += " " + str(host) port = kwargs.get('port') if port: port = str(port) if int(port) != default_ports.get("postgresql"): signature += ":" + port else: # Parse connection string and extract host/port pass with capture_span(signature, "db.postgreql.connect"): return PGConnectionProxy(wrapped(*args, **kwargs))
def call(self, module, method, wrapped, instance, args, kwargs): url, method, headers = utils.get_request_data(args, kwargs) scheme, host, port, target = url if port != default_ports.get(scheme): host += ":" + str(port) signature = "%s %s" % (method.upper(), host) url = "%s://%s%s" % (scheme, host, target) transaction = execution_context.get_transaction() with capture_span( signature, span_type="external", span_subtype="http", extra={"http": { "url": url }}, leaf=True, ) as span: # if httpcore has been called in a leaf span, this span might be a DroppedSpan. leaf_span = span while isinstance(leaf_span, DroppedSpan): leaf_span = leaf_span.parent if headers is not None: # It's possible that there are only dropped spans, e.g. if we started dropping spans. # In this case, the transaction.id is used parent_id = leaf_span.id if leaf_span else transaction.id trace_parent = transaction.trace_parent.copy_from( span_id=parent_id, trace_options=TracingOptions(recorded=True)) utils.set_disttracing_headers(headers, trace_parent, transaction) if leaf_span: leaf_span.dist_tracing_propagated = True response = wrapped(*args, **kwargs) status_code = utils.get_status(response) if status_code: if span.context: span.context["http"]["status_code"] = status_code span.set_success() if status_code < 400 else span.set_failure() return response
def request_host(request): """Return request-host, as defined by RFC 2965. Variation from RFC: returned value is lowercased, for convenient comparison. """ url = request.get_full_url() parse_result = compat.urlparse.urlparse(url) scheme, host, port = parse_result.scheme, parse_result.hostname, parse_result.port try: port = int(port) except (ValueError, TypeError): pass if host == "": host = request.get_header("Host", "") if port and port != default_ports.get(scheme): host = "%s:%s" % (host, port) return host
def call(self, module, method, wrapped, instance, args, kwargs): if 'method' in kwargs: method = kwargs['method'] else: method = args[0] host = instance.host if instance.port != default_ports.get(instance.scheme): host += ":" + str(instance.port) if 'url' in kwargs: url = kwargs['url'] else: url = args[1] signature = method.upper() + " " + host url = instance.scheme + "://" + host + url with trace(signature, "ext.http.urllib3", {'url': url}, leaf=True): return wrapped(*args, **kwargs)
async def call(self, module, method, wrapped, instance, args, kwargs): query = args[0] if len(args) else kwargs["query"] name = extract_signature(query) context = {"db": {"type": "sql", "statement": query}} action = "query" destination_info = { "address": kwargs.get("host", "localhost"), "port": int(kwargs.get("port", default_ports.get("postgresql"))), "service": { "name": "postgres", "resource": "postgres", "type": "db" }, } context["destination"] = destination_info async with async_capture_span(name, leaf=True, span_type="db", span_subtype="postgres", span_action=action, extra=context): return await wrapped(*args, **kwargs)
async def call(self, module, method, wrapped, instance, args, kwargs): query = self.get_query(method, args) name = extract_signature(query) sql_string = shorten(query, string_length=10000) context = {"db": {"type": "sql", "statement": sql_string}} action = "query" destination_info = { "address": kwargs.get("host", "localhost"), "port": int(kwargs.get("port", default_ports.get("postgresql"))), "service": { "name": "", "resource": "postgresql", "type": "" }, } context["destination"] = destination_info async with async_capture_span(name, leaf=True, span_type="db", span_subtype="postgresql", span_action=action, extra=context): return await wrapped(*args, **kwargs)
def call(self, module, method, wrapped, instance, args, kwargs): if "method" in kwargs: method = kwargs["method"] else: method = args[0] host = instance.host if instance.port != default_ports.get(instance.scheme): host += ":" + str(instance.port) if "url" in kwargs: url = kwargs["url"] else: url = args[1] signature = method.upper() + " " + host url = instance.scheme + "://" + host + url with capture_span(signature, "ext.http.urllib3", {"url": url}, leaf=True): return wrapped(*args, **kwargs)
def call(self, module, method, wrapped, instance, args, kwargs): if "method" in kwargs: method = kwargs["method"].decode("utf-8") else: method = args[0].decode("utf-8") # URL is a tuple of (scheme, host, port, path), we want path if "url" in kwargs: url = kwargs["url"][3].decode("utf-8") else: url = args[1][3].decode("utf-8") headers = None if "headers" in kwargs: headers = kwargs["headers"] if headers is None: headers = [] kwargs["headers"] = headers scheme, host, port = instance.origin scheme = scheme.decode("utf-8") host = host.decode("utf-8") if port != default_ports.get(scheme): host += ":" + str(port) signature = "%s %s" % (method.upper(), host) url = "%s://%s%s" % (scheme, host, url) destination = url_to_destination(url) transaction = execution_context.get_transaction() with capture_span( signature, span_type="external", span_subtype="http", extra={ "http": { "url": url }, "destination": destination }, leaf=True, ) as span: # if httpcore has been called in a leaf span, this span might be a DroppedSpan. leaf_span = span while isinstance(leaf_span, DroppedSpan): leaf_span = leaf_span.parent if headers is not None: # It's possible that there are only dropped spans, e.g. if we started dropping spans. # In this case, the transaction.id is used parent_id = leaf_span.id if leaf_span else transaction.id trace_parent = transaction.trace_parent.copy_from( span_id=parent_id, trace_options=TracingOptions(recorded=True)) self._set_disttracing_headers(headers, trace_parent, transaction) response = wrapped(*args, **kwargs) if len(response) > 4: # httpcore < 0.11.0 # response = (http_version, status_code, reason_phrase, headers, stream) status_code = response[1] else: # httpcore >= 0.11.0 # response = (status_code, headers, stream, ext) status_code = response[0] if status_code: if span.context: span.context["http"]["status_code"] = status_code span.set_success() if status_code < 400 else span.set_failure() return response