Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement span subtypes and actions #377

Closed
wants to merge 12 commits into from
2 changes: 1 addition & 1 deletion elasticapm/instrumentation/packages/botocore.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ def call(self, module, method, wrapped, instance, args, kwargs):

signature = "{}:{}".format(service, operation_name)

with capture_span(signature, "ext.http.aws", leaf=True):
with capture_span(signature, "aws", leaf=True, span_subtype=service, span_action=operation_name):
return wrapped(*args, **kwargs)
6 changes: 3 additions & 3 deletions elasticapm/instrumentation/packages/cassandra.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ def call(self, module, method, wrapped, instance, args, kwargs):
name = self.get_wrapped_name(wrapped, instance, method)
context = None
if method == "Cluster.connect":
span_type = "db.cassandra.connect"
span_action = "connect"
else:
span_type = "db.cassandra.query"
span_action = "query"
query = args[0] if args else kwargs.get("query")
if hasattr(query, "query_string"):
query_str = query.query_string
Expand All @@ -59,5 +59,5 @@ def call(self, module, method, wrapped, instance, args, kwargs):
name = extract_signature(query_str)
context = {"db": {"type": "sql", "statement": query_str}}

with capture_span(name, span_type, context):
with capture_span(name, span_type="db", span_subtype="cassandra", span_action=span_action, extra=context):
return wrapped(*args, **kwargs)
23 changes: 18 additions & 5 deletions elasticapm/instrumentation/packages/dbapi2.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,15 @@ def extract_signature(sql):
return signature


QUERY_ACTION = "query"
EXEC_ACTION = "exec"


class CursorProxy(wrapt.ObjectProxy):
provider_name = None

def callproc(self, procname, params=None):
return self._trace_sql(self.__wrapped__.callproc, procname, params)
return self._trace_sql(self.__wrapped__.callproc, procname, params, action=EXEC_ACTION)

def execute(self, sql, params=None):
return self._trace_sql(self.__wrapped__.execute, sql, params)
Expand All @@ -209,11 +213,20 @@ def _bake_sql(self, sql):
"""
return sql

def _trace_sql(self, method, sql, params):
def _trace_sql(self, method, sql, params, action=QUERY_ACTION):
sql_string = self._bake_sql(sql)
signature = self.extract_signature(sql_string)
kind = "db.{0}.sql".format(self.provider_name)
with capture_span(signature, kind, {"db": {"type": "sql", "statement": sql_string}}):
if action == EXEC_ACTION:
signature = sql_string + "()"
else:
signature = self.extract_signature(sql_string)
with capture_span(
signature,
span_type="db",
span_subtype=self.provider_name,
span_action=action,
extra={"db": {"type": "sql", "statement": sql_string}},
skip_frames=1,
):
if params is None:
return method(sql)
else:
Expand Down
2 changes: 1 addition & 1 deletion elasticapm/instrumentation/packages/django/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def call(self, module, method, wrapped, instance, args, kwargs):

if not name:
name = "<template string>"
with capture_span(name, "template.django"):
with capture_span(name, span_type="template", span_subtype="django", span_action="render"):
return wrapped(*args, **kwargs)


Expand Down
10 changes: 9 additions & 1 deletion elasticapm/instrumentation/packages/elasticsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ def call(self, module, method, wrapped, instance, args, kwargs):
# only get the `script` field from the body
context["db"]["statement"] = json.dumps({"script": body["script"]})
# TODO: add instance.base_url to context once we agreed on a format
with elasticapm.capture_span(signature, "db.elasticsearch", extra=context, skip_frames=2, leaf=True):
with elasticapm.capture_span(
signature,
span_type="db",
span_subtype="elasticsearch",
span_action="query",
extra=context,
skip_frames=2,
leaf=True,
):
return wrapped(*args, **kwargs)


Expand Down
2 changes: 1 addition & 1 deletion elasticapm/instrumentation/packages/jinja2.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ class Jinja2Instrumentation(AbstractInstrumentedModule):

def call(self, module, method, wrapped, instance, args, kwargs):
signature = instance.name or instance.filename
with capture_span(signature, "template.jinja2"):
with capture_span(signature, span_type="template", span_subtype="jinja2", span_action="render"):
return wrapped(*args, **kwargs)
2 changes: 1 addition & 1 deletion elasticapm/instrumentation/packages/psycopg2.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def call(self, module, method, wrapped, instance, args, kwargs):
# Parse connection string and extract host/port
pass

with capture_span(signature, "db.postgreql.connect"):
with capture_span(signature, span_type="db", span_subtype="postgresql", span_action="connect"):
return PGConnectionProxy(wrapped(*args, **kwargs))


Expand Down
2 changes: 1 addition & 1 deletion elasticapm/instrumentation/packages/pylibmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ class PyLibMcInstrumentation(AbstractInstrumentedModule):

def call(self, module, method, wrapped, instance, args, kwargs):
wrapped_name = self.get_wrapped_name(wrapped, instance, method)
with capture_span(wrapped_name, "cache.memcached"):
with capture_span(wrapped_name, span_type="cache", span_subtype="memcached", span_action="query"):
return wrapped(*args, **kwargs)
6 changes: 3 additions & 3 deletions elasticapm/instrumentation/packages/pymongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class PyMongoInstrumentation(AbstractInstrumentedModule):
def call(self, module, method, wrapped, instance, args, kwargs):
cls_name, method_name = method.split(".", 1)
signature = ".".join([instance.full_name, method_name])
with capture_span(signature, "db.mongodb.query", leaf=True):
with capture_span(signature, span_type="db", span_subtype="mongodb", span_action="query", leaf=True):
return wrapped(*args, **kwargs)


Expand All @@ -84,7 +84,7 @@ class PyMongoBulkInstrumentation(AbstractInstrumentedModule):
def call(self, module, method, wrapped, instance, args, kwargs):
collection = instance._BulkOperationBuilder__bulk.collection
signature = ".".join([collection.full_name, "bulk.execute"])
with capture_span(signature, "db.mongodb.query"):
with capture_span(signature, span_type="db", span_subtype="mongodb", span_action="query"):
return wrapped(*args, **kwargs)


Expand All @@ -96,5 +96,5 @@ class PyMongoCursorInstrumentation(AbstractInstrumentedModule):
def call(self, module, method, wrapped, instance, args, kwargs):
collection = instance.collection
signature = ".".join([collection.full_name, "cursor.refresh"])
with capture_span(signature, "db.mongodb.query"):
with capture_span(signature, span_type="db", span_subtype="mongodb", span_action="query"):
return wrapped(*args, **kwargs)
2 changes: 1 addition & 1 deletion elasticapm/instrumentation/packages/python_memcached.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ def get_instrument_list(self):
def call(self, module, method, wrapped, instance, args, kwargs):
name = self.get_wrapped_name(wrapped, instance, method)

with capture_span(name, "cache.memcached"):
with capture_span(name, span_type="cache", span_subtype="memcached", span_action="query"):
return wrapped(*args, **kwargs)
4 changes: 2 additions & 2 deletions elasticapm/instrumentation/packages/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def call(self, module, method, wrapped, instance, args, kwargs):
else:
wrapped_name = self.get_wrapped_name(wrapped, instance, method)

with capture_span(wrapped_name, "cache.redis", leaf=True):
with capture_span(wrapped_name, span_type="db", span_subtype="redis", span_action="query", leaf=True):
return wrapped(*args, **kwargs)


Expand All @@ -75,5 +75,5 @@ class RedisPipelineInstrumentation(Redis3CheckMixin, AbstractInstrumentedModule)

def call(self, module, method, wrapped, instance, args, kwargs):
wrapped_name = self.get_wrapped_name(wrapped, instance, method)
with capture_span(wrapped_name, "cache.redis", leaf=True):
with capture_span(wrapped_name, span_type="db", span_subtype="redis", span_action="query", leaf=True):
return wrapped(*args, **kwargs)
4 changes: 3 additions & 1 deletion elasticapm/instrumentation/packages/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,7 @@ def call(self, module, method, wrapped, instance, args, kwargs):
signature += " " + get_host_from_url(request.url)
url = sanitize_url(request.url)

with capture_span(signature, "ext.http.requests", {"http": {"url": url}}, leaf=True):
with capture_span(
signature, span_type="external", span_subtype="http", extra={"http": {"url": url}}, leaf=True
):
return wrapped(*args, **kwargs)
11 changes: 8 additions & 3 deletions elasticapm/instrumentation/packages/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,13 @@ class SQLiteConnectionProxy(ConnectionProxy):

def _trace_sql(self, method, sql, params):
signature = extract_signature(sql)
kind = "db.sqlite.sql"
with capture_span(signature, kind, {"db": {"type": "sql", "statement": sql}}):
with capture_span(
signature,
span_type="db",
span_subtype="sqlite",
span_action="query",
extra={"db": {"type": "sql", "statement": sql}},
):
if params is None:
return method(sql)
else:
Expand All @@ -77,5 +82,5 @@ def call(self, module, method, wrapped, instance, args, kwargs):
if len(args) == 1:
signature += " " + str(args[0])

with capture_span(signature, "db.sqlite.connect"):
with capture_span(signature, span_type="db", span_subtype="sqlite", span_action="connect"):
return SQLiteConnectionProxy(wrapped(*args, **kwargs))
4 changes: 3 additions & 1 deletion elasticapm/instrumentation/packages/urllib.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ def call(self, module, method, wrapped, instance, args, kwargs):

transaction = execution_context.get_transaction()

with capture_span(signature, "ext.http.urllib", {"http": {"url": url}}, leaf=True) as span:
with capture_span(
signature, span_type="external", span_subtype="http", extra={"http": {"url": url}}, leaf=True
) as span:
# if urllib has been called in a leaf span, this span might be a DroppedSpan.
leaf_span = span
while isinstance(leaf_span, DroppedSpan):
Expand Down
4 changes: 3 additions & 1 deletion elasticapm/instrumentation/packages/urllib3.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ def call(self, module, method, wrapped, instance, args, kwargs):
url = instance.scheme + "://" + host + url
transaction = execution_context.get_transaction()

with capture_span(signature, "ext.http.urllib3", {"http": {"url": url}}, leaf=True) as span:
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):
Expand Down
2 changes: 1 addition & 1 deletion elasticapm/instrumentation/packages/zlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ class ZLibInstrumentation(AbstractInstrumentedModule):

def call(self, module, method, wrapped, instance, args, kwargs):
wrapped_name = module + "." + method
with capture_span(wrapped_name, "compression.zlib"):
with capture_span(wrapped_name, span_type="compression", span_subtype="zlib"):
return wrapped(*args, **kwargs)
Loading