diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/CHANGELOG.md b/instrumentation/opentelemetry-instrumentation-asyncpg/CHANGELOG.md
new file mode 100644
index 000000000..08464e8cd
--- /dev/null
+++ b/instrumentation/opentelemetry-instrumentation-asyncpg/CHANGELOG.md
@@ -0,0 +1,19 @@
+# Changelog
+
+## Unreleased
+
+- Change package name to opentelemetry-instrumentation-asyncpg
+ ([#999](https://github.com/open-telemetry/opentelemetry-python/pull/999))
+
+## Version 0.11b0
+
+Released 2020-07-28
+
+- Shouldn't capture query parameters by default
+ ([#854](https://github.com/open-telemetry/opentelemetry-python/pull/854))
+
+## Version 0.10b0
+
+Released 2020-06-23
+
+- Initial Release ([#814](https://github.com/open-telemetry/opentelemetry-python/pull/814))
diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/README.rst b/instrumentation/opentelemetry-instrumentation-asyncpg/README.rst
new file mode 100644
index 000000000..33c60852c
--- /dev/null
+++ b/instrumentation/opentelemetry-instrumentation-asyncpg/README.rst
@@ -0,0 +1,23 @@
+OpenTelemetry asyncpg Instrumentation
+=====================================
+
+|pypi|
+
+.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-asyncpg.svg
+ :target: https://pypi.org/project/opentelemetry-instrumentation-asyncpg/
+
+This library allows tracing PostgreSQL queries made by the
+`asyncpg `_ library.
+
+Installation
+------------
+
+::
+
+ pip install opentelemetry-instrumentation-asyncpg
+
+References
+----------
+
+* `OpenTelemetry asyncpg Instrumentation `_
+* `OpenTelemetry Project `_
diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg
new file mode 100644
index 000000000..1cc707df1
--- /dev/null
+++ b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg
@@ -0,0 +1,55 @@
+# Copyright The OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+[metadata]
+name = opentelemetry-instrumentation-asyncpg
+description = OpenTelemetry instrumentation for AsyncPG
+long_description = file: README.rst
+long_description_content_type = text/x-rst
+author = OpenTelemetry Authors
+author_email = cncf-opentelemetry-contributors@lists.cncf.io
+url = https://github.com/open-telemetry/opentelemetry-python/instrumentation/opentelemetry-instrumentation-asyncpg
+platforms = any
+license = Apache-2.0
+classifiers =
+ Development Status :: 4 - Beta
+ Intended Audience :: Developers
+ License :: OSI Approved :: Apache Software License
+ Programming Language :: Python
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.5
+ Programming Language :: Python :: 3.6
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+
+[options]
+python_requires = >=3.5
+package_dir=
+ =src
+packages=find_namespace:
+install_requires =
+ opentelemetry-api == 0.12.dev0
+ opentelemetry-instrumentation == 0.12.dev0
+ asyncpg >= 0.12.0
+
+[options.extras_require]
+test =
+ opentelemetry-test == 0.12.dev0
+
+[options.packages.find]
+where = src
+
+[options.entry_points]
+opentelemetry_instrumentor =
+ asyncpg = opentelemetry.instrumentation.asyncpg:AsyncPGInstrumentor
diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/setup.py b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.py
new file mode 100644
index 000000000..2ad47ac9d
--- /dev/null
+++ b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.py
@@ -0,0 +1,31 @@
+# Copyright The OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import os
+
+import setuptools
+
+BASE_DIR = os.path.dirname(__file__)
+VERSION_FILENAME = os.path.join(
+ BASE_DIR,
+ "src",
+ "opentelemetry",
+ "instrumentation",
+ "asyncpg",
+ "version.py",
+)
+PACKAGE_INFO = {}
+with open(VERSION_FILENAME) as f:
+ exec(f.read(), PACKAGE_INFO)
+
+setuptools.setup(version=PACKAGE_INFO["__version__"])
diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py
new file mode 100644
index 000000000..189809809
--- /dev/null
+++ b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/__init__.py
@@ -0,0 +1,142 @@
+# Copyright The OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+This library allows tracing PostgreSQL queries made by the
+`asyncpg `_ library.
+
+Usage
+-----
+
+.. code-block:: python
+
+ import asyncpg
+ from opentelemetry.instrumentation.asyncpg import AsyncPGInstrumentor
+
+ # You can optionally pass a custom TracerProvider to AsyncPGInstrumentor.instrument()
+ AsyncPGInstrumentor().instrument()
+ conn = await asyncpg.connect(user='user', password='password',
+ database='database', host='127.0.0.1')
+ values = await conn.fetch('''SELECT 42;''')
+
+API
+---
+"""
+
+import asyncpg
+import wrapt
+from asyncpg import exceptions
+
+from opentelemetry import trace
+from opentelemetry.instrumentation.asyncpg.version import __version__
+from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
+from opentelemetry.instrumentation.utils import unwrap
+from opentelemetry.trace import SpanKind
+from opentelemetry.trace.status import Status, StatusCanonicalCode
+
+_APPLIED = "_opentelemetry_tracer"
+
+
+def _exception_to_canonical_code(exc: Exception) -> StatusCanonicalCode:
+ if isinstance(
+ exc, (exceptions.InterfaceError, exceptions.SyntaxOrAccessError),
+ ):
+ return StatusCanonicalCode.INVALID_ARGUMENT
+ if isinstance(exc, exceptions.IdleInTransactionSessionTimeoutError):
+ return StatusCanonicalCode.DEADLINE_EXCEEDED
+ return StatusCanonicalCode.UNKNOWN
+
+
+def _hydrate_span_from_args(connection, query, parameters) -> dict:
+ span_attributes = {"db.type": "sql"}
+
+ params = getattr(connection, "_params", None)
+ span_attributes["db.instance"] = getattr(params, "database", None)
+ span_attributes["db.user"] = getattr(params, "user", None)
+
+ if query is not None:
+ span_attributes["db.statement"] = query
+
+ if parameters is not None and len(parameters) > 0:
+ span_attributes["db.statement.parameters"] = str(parameters)
+
+ return span_attributes
+
+
+class AsyncPGInstrumentor(BaseInstrumentor):
+ def __init__(self, capture_parameters=False):
+ super().__init__()
+ self.capture_parameters = capture_parameters
+
+ def _instrument(self, **kwargs):
+ tracer_provider = kwargs.get(
+ "tracer_provider", trace.get_tracer_provider()
+ )
+ setattr(
+ asyncpg,
+ _APPLIED,
+ tracer_provider.get_tracer("asyncpg", __version__),
+ )
+
+ for method in [
+ "Connection.execute",
+ "Connection.executemany",
+ "Connection.fetch",
+ "Connection.fetchval",
+ "Connection.fetchrow",
+ ]:
+ wrapt.wrap_function_wrapper(
+ "asyncpg.connection", method, self._do_execute
+ )
+
+ def _uninstrument(self, **__):
+ delattr(asyncpg, _APPLIED)
+ for method in [
+ "execute",
+ "executemany",
+ "fetch",
+ "fetchval",
+ "fetchrow",
+ ]:
+ unwrap(asyncpg.Connection, method)
+
+ async def _do_execute(self, func, instance, args, kwargs):
+ span_attributes = _hydrate_span_from_args(
+ instance, args[0], args[1:] if self.capture_parameters else None,
+ )
+ tracer = getattr(asyncpg, _APPLIED)
+
+ exception = None
+
+ with tracer.start_as_current_span(
+ "postgresql", kind=SpanKind.CLIENT
+ ) as span:
+
+ for attribute, value in span_attributes.items():
+ span.set_attribute(attribute, value)
+
+ try:
+ result = await func(*args, **kwargs)
+ except Exception as exc: # pylint: disable=W0703
+ exception = exc
+ raise
+ finally:
+ if exception is not None:
+ span.set_status(
+ Status(_exception_to_canonical_code(exception))
+ )
+ else:
+ span.set_status(Status(StatusCanonicalCode.OK))
+
+ return result
diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/version.py b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/version.py
new file mode 100644
index 000000000..780a92b6a
--- /dev/null
+++ b/instrumentation/opentelemetry-instrumentation-asyncpg/src/opentelemetry/instrumentation/asyncpg/version.py
@@ -0,0 +1,15 @@
+# Copyright The OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+__version__ = "0.12.dev0"
diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/tests/__init__.py b/instrumentation/opentelemetry-instrumentation-asyncpg/tests/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/tests/test_asyncpg_wrapper.py b/instrumentation/opentelemetry-instrumentation-asyncpg/tests/test_asyncpg_wrapper.py
new file mode 100644
index 000000000..33b121ce5
--- /dev/null
+++ b/instrumentation/opentelemetry-instrumentation-asyncpg/tests/test_asyncpg_wrapper.py
@@ -0,0 +1,35 @@
+import asyncpg
+from asyncpg import Connection
+
+from opentelemetry.instrumentation.asyncpg import AsyncPGInstrumentor
+from opentelemetry.test.test_base import TestBase
+
+
+class TestAsyncPGInstrumentation(TestBase):
+ def test_instrumentation_flags(self):
+ AsyncPGInstrumentor().instrument()
+ self.assertTrue(hasattr(asyncpg, "_opentelemetry_tracer"))
+ AsyncPGInstrumentor().uninstrument()
+ self.assertFalse(hasattr(asyncpg, "_opentelemetry_tracer"))
+
+ def test_duplicated_instrumentation(self):
+ AsyncPGInstrumentor().instrument()
+ AsyncPGInstrumentor().instrument()
+ AsyncPGInstrumentor().instrument()
+ AsyncPGInstrumentor().uninstrument()
+ for method_name in ["execute", "fetch"]:
+ method = getattr(Connection, method_name, None)
+ self.assertFalse(
+ hasattr(method, "_opentelemetry_ext_asyncpg_applied")
+ )
+
+ def test_duplicated_uninstrumentation(self):
+ AsyncPGInstrumentor().instrument()
+ AsyncPGInstrumentor().uninstrument()
+ AsyncPGInstrumentor().uninstrument()
+ AsyncPGInstrumentor().uninstrument()
+ for method_name in ["execute", "fetch"]:
+ method = getattr(Connection, method_name, None)
+ self.assertFalse(
+ hasattr(method, "_opentelemetry_ext_asyncpg_applied")
+ )