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

Update dbapi and its dependant instrumentations to follow semantic conventions #195

Merged
merged 11 commits into from
Nov 23, 2020
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var
sdist
develop-eggs
.installed.cfg
pyvenv.cfg
lib
lib64
__pycache__
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,16 @@ async def traced_execution(
*args: typing.Tuple[typing.Any, typing.Any],
**kwargs: typing.Dict[typing.Any, typing.Any]
):
name = ""
if len(args) > 0 and args[0]:
name = args[0]
elif self._db_api_integration.database:
name = self._db_api_integration.database
else:
name = self._db_api_integration.name

with self._db_api_integration.get_tracer().start_as_current_span(
self._db_api_integration.name, kind=SpanKind.CLIENT
name, kind=SpanKind.CLIENT
) as span:
self._populate_span(span, *args)
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,12 @@ def test_span_succeeded(self):
spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 1)
span = spans_list[0]
self.assertEqual(span.name, "testcomponent.testdatabase")
self.assertEqual(span.name, "Test query")
self.assertIs(span.kind, trace_api.SpanKind.CLIENT)

self.assertEqual(span.attributes["component"], "testcomponent")
self.assertEqual(span.attributes["db.type"], "testtype")
self.assertEqual(span.attributes["db.instance"], "testdatabase")
self.assertEqual(span.attributes["db.system"], "testcomponent")
self.assertEqual(span.attributes["db.name"], "testdatabase")
self.assertEqual(span.attributes["db.statement"], "Test query")
self.assertEqual(
span.attributes["db.statement.parameters"],
Expand All @@ -230,7 +230,7 @@ def test_span_succeeded(self):
self.assertEqual(span.attributes["net.peer.name"], "testhost")
self.assertEqual(span.attributes["net.peer.port"], 123)
self.assertIs(
span.status.status_code, trace_api.status.StatusCode.UNSET,
span.status.status_code, trace_api.status.StatusCode.UNSET
)

def test_span_not_recording(self):
Expand Down Expand Up @@ -281,7 +281,7 @@ def test_span_failed(self):
span = spans_list[0]
self.assertEqual(span.attributes["db.statement"], "Test query")
self.assertIs(
span.status.status_code, trace_api.status.StatusCode.ERROR,
span.status.status_code, trace_api.status.StatusCode.ERROR
)
self.assertEqual(span.status.description, "Test Exception")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

## Unreleased

Stop capturing query parameters by default
- Update dbapi and its dependant instrumentations to follow semantic conventions
([#195](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/195))

- Stop capturing query parameters by default
([#156](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/156))

## Version 0.13b0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ def trace_integration(
capture_parameters: bool = False,
):
"""Integrate with DB API library.
https://www.python.org/dev/peps/pep-0249/

Args:
connect_module: Module name where connect method is available.
connect_method_name: The connect method name.
database_component: Database driver name or database name "JDBI",
"jdbc", "odbc", "postgreSQL".
database_type: The Database type. For any SQL database, "sql".
connection_attributes: Attribute names for database, port, host and
user in Connection object.
tracer_provider: The :class:`opentelemetry.trace.TracerProvider` to
use. If ommited the current configured one is used.
capture_parameters: Configure if db.statement.parameters should be captured.
https://www.python.org/dev/peps/pep-0249/

Args:
connect_module: Module name where connect method is available.
connect_method_name: The connect method name.
database_component: Database driver name or database name "JDBI",
"jdbc", "odbc", "postgreSQL".
database_type: The Database type. For any SQL database, "sql".
connection_attributes: Attribute names for database, port, host and
user in Connection object.
tracer_provider: The :class:`opentelemetry.trace.TracerProvider` to
use. If ommited the current configured one is used.
capture_parameters: Configure if db.statement.parameters should be captured.
"""
wrap_connect(
__name__,
Expand All @@ -101,18 +101,18 @@ def wrap_connect(
capture_parameters: bool = False,
):
"""Integrate with DB API library.
https://www.python.org/dev/peps/pep-0249/

Args:
tracer: The :class:`opentelemetry.trace.Tracer` to use.
connect_module: Module name where connect method is available.
connect_method_name: The connect method name.
database_component: Database driver name or database name "JDBI",
"jdbc", "odbc", "postgreSQL".
database_type: The Database type. For any SQL database, "sql".
connection_attributes: Attribute names for database, port, host and
user in Connection object.
capture_parameters: Configure if db.statement.parameters should be captured.
https://www.python.org/dev/peps/pep-0249/

Args:
tracer: The :class:`opentelemetry.trace.Tracer` to use.
connect_module: Module name where connect method is available.
connect_method_name: The connect method name.
database_component: Database driver name or database name "JDBI",
"jdbc", "odbc", "postgreSQL".
database_type: The Database type. For any SQL database, "sql".
connection_attributes: Attribute names for database, port, host and
user in Connection object.
capture_parameters: Configure if db.statement.parameters should be captured.

"""

Expand Down Expand Up @@ -143,14 +143,14 @@ def wrap_connect_(


def unwrap_connect(
connect_module: typing.Callable[..., typing.Any], connect_method_name: str,
connect_module: typing.Callable[..., typing.Any], connect_method_name: str
):
"""Disable integration with DB API library.
https://www.python.org/dev/peps/pep-0249/
https://www.python.org/dev/peps/pep-0249/

Args:
connect_module: Module name where the connect method is available.
connect_method_name: The connect method name.
Args:
connect_module: Module name where the connect method is available.
connect_method_name: The connect method name.
"""
unwrap(connect_module, connect_method_name)

Expand Down Expand Up @@ -251,8 +251,7 @@ def wrapped_connection(
args: typing.Tuple[typing.Any, typing.Any],
kwargs: typing.Dict[typing.Any, typing.Any],
):
"""Add object proxy to connection object.
"""
"""Add object proxy to connection object."""
connection = connect_method(*args, **kwargs)
self.get_connection_attributes(connection)
return get_traced_connection_proxy(connection, self)
Expand All @@ -278,6 +277,9 @@ def get_connection_attributes(self, connection):
self.database = self.database.decode(errors="ignore")
self.name += "." + self.database
user = self.connection_props.get("user")
# PyMySQL encodes this data
if user and isinstance(user, bytes):
user = user.decode()
if user is not None:
self.span_attributes["db.user"] = str(user)
host = self.connection_props.get("host")
Expand Down Expand Up @@ -325,8 +327,10 @@ def _populate_span(
span.set_attribute(
"component", self._db_api_integration.database_component
)
span.set_attribute("db.type", self._db_api_integration.database_type)
span.set_attribute("db.instance", self._db_api_integration.database)
span.set_attribute(
"db.system", self._db_api_integration.database_component
)
span.set_attribute("db.name", self._db_api_integration.database)
span.set_attribute("db.statement", statement)

for (
Expand All @@ -344,9 +348,16 @@ def traced_execution(
*args: typing.Tuple[typing.Any, typing.Any],
**kwargs: typing.Dict[typing.Any, typing.Any]
):
name = ""
if args:
name = args[0]
elif self._db_api_integration.database:
name = self._db_api_integration.database
else:
name = self._db_api_integration.name

with self._db_api_integration.get_tracer().start_as_current_span(
self._db_api_integration.name, kind=SpanKind.CLIENT
name, kind=SpanKind.CLIENT
) as span:
self._populate_span(span, *args)
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,19 @@ def test_span_succeeded(self):
spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 1)
span = spans_list[0]
self.assertEqual(span.name, "testcomponent.testdatabase")
self.assertEqual(span.name, "Test query")
self.assertIs(span.kind, trace_api.SpanKind.CLIENT)

self.assertEqual(span.attributes["component"], "testcomponent")
self.assertEqual(span.attributes["db.type"], "testtype")
self.assertEqual(span.attributes["db.instance"], "testdatabase")
self.assertEqual(span.attributes["db.system"], "testcomponent")
self.assertEqual(span.attributes["db.name"], "testdatabase")
self.assertEqual(span.attributes["db.statement"], "Test query")
self.assertFalse("db.statement.parameters" in span.attributes)
self.assertEqual(span.attributes["db.user"], "testuser")
self.assertEqual(span.attributes["net.peer.name"], "testhost")
self.assertEqual(span.attributes["net.peer.port"], 123)
self.assertIs(
span.status.status_code, trace_api.status.StatusCode.UNSET,
span.status.status_code, trace_api.status.StatusCode.UNSET
)

def test_span_succeeded_with_capture_of_statement_parameters(self):
Expand Down Expand Up @@ -93,12 +93,12 @@ def test_span_succeeded_with_capture_of_statement_parameters(self):
spans_list = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans_list), 1)
span = spans_list[0]
self.assertEqual(span.name, "testcomponent.testdatabase")
self.assertEqual(span.name, "Test query")
self.assertIs(span.kind, trace_api.SpanKind.CLIENT)

self.assertEqual(span.attributes["component"], "testcomponent")
self.assertEqual(span.attributes["db.type"], "testtype")
self.assertEqual(span.attributes["db.instance"], "testdatabase")
self.assertEqual(span.attributes["db.system"], "testcomponent")
self.assertEqual(span.attributes["db.name"], "testdatabase")
self.assertEqual(span.attributes["db.statement"], "Test query")
self.assertEqual(
span.attributes["db.statement.parameters"],
Expand All @@ -108,7 +108,7 @@ def test_span_succeeded_with_capture_of_statement_parameters(self):
self.assertEqual(span.attributes["net.peer.name"], "testhost")
self.assertEqual(span.attributes["net.peer.port"], 123)
self.assertIs(
span.status.status_code, trace_api.status.StatusCode.UNSET,
span.status.status_code, trace_api.status.StatusCode.UNSET
)

def test_span_not_recording(self):
Expand Down Expand Up @@ -159,7 +159,7 @@ def test_span_failed(self):
span = spans_list[0]
self.assertEqual(span.attributes["db.statement"], "Test query")
self.assertIs(
span.status.status_code, trace_api.status.StatusCode.ERROR,
span.status.status_code, trace_api.status.StatusCode.ERROR
)
self.assertEqual(span.status.description, "Test Exception")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class SQLite3Instrumentor(BaseInstrumentor):
# No useful attributes of sqlite3 connection object
_CONNECTION_ATTRIBUTES = {}

_DATABASE_COMPONENT = "sqlite3"
_DATABASE_COMPONENT = "sqlite"
_DATABASE_TYPE = "sql"

def _instrument(self, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def tearDownClass(cls):
if cls._connection:
cls._connection.close()

def validate_spans(self):
def validate_spans(self, span_name):
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 2)
for span in spans:
Expand All @@ -50,34 +50,30 @@ def validate_spans(self):
self.assertIsNotNone(root_span)
self.assertIsNotNone(child_span)
self.assertEqual(root_span.name, "rootSpan")
self.assertEqual(child_span.name, "sqlite3")
self.assertEqual(child_span.name, span_name)
self.assertIsNotNone(child_span.parent)
self.assertIs(child_span.parent, root_span.get_span_context())
self.assertIs(child_span.kind, trace_api.SpanKind.CLIENT)

def test_execute(self):
"""Should create a child span for execute method
"""
"""Should create a child span for execute method"""
stmt = "CREATE TABLE IF NOT EXISTS test (id integer)"
with self._tracer.start_as_current_span("rootSpan"):
self._cursor.execute(
"CREATE TABLE IF NOT EXISTS test (id integer)"
)
self.validate_spans()
self._cursor.execute(stmt)
self.validate_spans(stmt)

def test_executemany(self):
"""Should create a child span for executemany
"""
"""Should create a child span for executemany"""
stmt = "INSERT INTO test (id) VALUES (?)"
with self._tracer.start_as_current_span("rootSpan"):
data = [("1",), ("2",), ("3",)]
stmt = "INSERT INTO test (id) VALUES (?)"
self._cursor.executemany(stmt, data)
self.validate_spans()
self.validate_spans(stmt)

def test_callproc(self):
"""Should create a child span for callproc
"""
"""Should create a child span for callproc"""
with self._tracer.start_as_current_span("rootSpan"), self.assertRaises(
Exception
):
self._cursor.callproc("test", ())
self.validate_spans()
self.validate_spans("test")
14 changes: 7 additions & 7 deletions tests/opentelemetry-docker-tests/tests/check_availability.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@
MONGODB_DB_NAME = os.getenv("MONGODB_DB_NAME", "opentelemetry-tests")
MONGODB_HOST = os.getenv("MONGODB_HOST", "localhost")
MONGODB_PORT = int(os.getenv("MONGODB_PORT", "27017"))
MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME ", "opentelemetry-tests")
MYSQL_HOST = os.getenv("MYSQL_HOST ", "localhost")
MYSQL_PORT = int(os.getenv("MYSQL_PORT ", "3306"))
MYSQL_USER = os.getenv("MYSQL_USER ", "testuser")
MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD ", "testpassword")
MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME", "opentelemetry-tests")
MYSQL_HOST = os.getenv("MYSQL_HOST", "localhost")
MYSQL_PORT = int(os.getenv("MYSQL_PORT", "3306"))
MYSQL_USER = os.getenv("MYSQL_USER", "testuser")
MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "testpassword")
POSTGRES_DB_NAME = os.getenv("POSTGRESQL_DB_NAME", "opentelemetry-tests")
POSTGRES_HOST = os.getenv("POSTGRESQL_HOST", "localhost")
POSTGRES_PASSWORD = os.getenv("POSTGRESQL_HOST", "testpassword")
POSTGRES_PASSWORD = os.getenv("POSTGRESQL_PASSWORD", "testpassword")
POSTGRES_PORT = int(os.getenv("POSTGRESQL_PORT", "5432"))
POSTGRES_USER = os.getenv("POSTGRESQL_HOST", "testuser")
POSTGRES_USER = os.getenv("POSTGRESQL_USER", "testuser")
REDIS_HOST = os.getenv("REDIS_HOST", "localhost")
REDIS_PORT = int(os.getenv("REDIS_PORT ", "6379"))
RETRY_COUNT = 8
Expand Down
Loading