Skip to content

Commit e8a6897

Browse files
JaeHyuckSaxrmx
andauthored
Fix psycopg_pool instrumentation to restore Postgres spans (#2460)
* fix: instrument psycopg_pool connections to restore Postgres spans Signed-off-by: SaJH <wogur981208@gmail.com> * fix: add PostgreSQL dependencies for psycopg_pool tests Signed-off-by: JaeHyuck Sa <wogur981208@gmail.com> * Fix tests Assisted-by: Cursor * Fix test name --------- Signed-off-by: SaJH <wogur981208@gmail.com> Signed-off-by: JaeHyuck Sa <wogur981208@gmail.com> Co-authored-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
1 parent 6854f9b commit e8a6897

6 files changed

Lines changed: 109 additions & 1 deletion

File tree

.ci/.matrix_framework.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ FRAMEWORK:
2525
#- aioredis-2 # not supported yet
2626
- psycopg-newest
2727
- psycopg2-newest
28+
- psycopg_pool-newest
2829
- pymssql-newest
2930
- pyodbc-newest
3031
- memcached-newest

.ci/.matrix_framework_full.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ FRAMEWORK:
5252
- redis-newest
5353
- psycopg-newest
5454
- psycopg2-newest
55+
- psycopg_pool-newest
5556
- pymssql-newest
5657
- memcached-newest
5758
- pylibmc-1.4

elasticapm/instrumentation/packages/psycopg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def __enter__(self):
7979
class PsycopgInstrumentation(DbApi2Instrumentation):
8080
name = "psycopg"
8181

82-
instrument_list = [("psycopg", "connect")]
82+
instrument_list = [("psycopg", "connect"), ("psycopg", "Connection.connect")]
8383

8484
def call(self, module, method, wrapped, instance, args, kwargs):
8585
signature = "psycopg.connect"
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# BSD 3-Clause License
2+
#
3+
# Copyright (c) 2019, Elasticsearch BV
4+
# All rights reserved.
5+
#
6+
# Redistribution and use in source and binary forms, with or without
7+
# modification, are permitted provided that the following conditions are met:
8+
#
9+
# * Redistributions of source code must retain the above copyright notice, this
10+
# list of conditions and the following disclaimer.
11+
#
12+
# * Redistributions in binary form must reproduce the above copyright notice,
13+
# this list of conditions and the following disclaimer in the documentation
14+
# and/or other materials provided with the distribution.
15+
#
16+
# * Neither the name of the copyright holder nor the names of its
17+
# contributors may be used to endorse or promote products derived from
18+
# this software without specific prior written permission.
19+
#
20+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
31+
import os
32+
33+
import pytest
34+
35+
from elasticapm.conf.constants import SPAN
36+
37+
psycopg = pytest.importorskip("psycopg")
38+
pool_mod = pytest.importorskip("psycopg_pool")
39+
40+
pytestmark = [pytest.mark.psycopg_pool, pytest.mark.integrationtest]
41+
42+
has_postgres_configured = "POSTGRES_DB" in os.environ
43+
44+
45+
def connect_kwargs():
46+
return {
47+
"dbname": os.environ.get("POSTGRES_DB", "elasticapm_test"),
48+
"user": os.environ.get("POSTGRES_USER", "postgres"),
49+
"password": os.environ.get("POSTGRES_PASSWORD", "postgres"),
50+
"host": os.environ.get("POSTGRES_HOST", None),
51+
"port": os.environ.get("POSTGRES_PORT", None),
52+
}
53+
54+
55+
def make_conninfo():
56+
kw = connect_kwargs()
57+
host = kw["host"] or "localhost"
58+
port = kw["port"] or "5432"
59+
return f"postgresql://{kw['user']}:{kw['password']}@{host}:{port}/{kw['dbname']}"
60+
61+
62+
@pytest.mark.skipif(not has_postgres_configured, reason="PostgreSQL not configured")
63+
def test_connection_connect_generates_span(instrument, elasticapm_client):
64+
elasticapm_client.begin_transaction("request")
65+
try:
66+
connection = psycopg.Connection.connect(**connect_kwargs())
67+
connection.close()
68+
finally:
69+
elasticapm_client.end_transaction("200")
70+
71+
spans = elasticapm_client.events[SPAN]
72+
assert len(spans) == 1
73+
assert spans[0]["action"] == "connect"
74+
75+
76+
@pytest.mark.skipif(not has_postgres_configured, reason="PostgreSQL not configured")
77+
def test_pool_generates_query_span(instrument, elasticapm_client):
78+
with pool_mod.ConnectionPool(
79+
make_conninfo(),
80+
min_size=1,
81+
max_size=2,
82+
) as pool:
83+
pool.wait()
84+
85+
elasticapm_client.begin_transaction("request")
86+
try:
87+
with pool.connection() as connection:
88+
with connection.cursor() as cursor:
89+
cursor.execute("SELECT 1")
90+
cursor.fetchone()
91+
finally:
92+
elasticapm_client.end_transaction("200")
93+
94+
spans = elasticapm_client.events[SPAN]
95+
span = next(span for span in spans if span["action"] == "query")
96+
assert span["action"] == "query"
97+
assert span["context"]["db"]["type"] == "sql"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
psycopg[binary,pool]
2+
-r reqs-base.txt

tests/scripts/envs/psycopg_pool.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export PYTEST_MARKER="-m psycopg_pool"
2+
export DOCKER_DEPS="postgres"
3+
export POSTGRES_HOST="postgres"
4+
export POSTGRES_USER="postgres"
5+
export POSTGRES_PASSWORD="postgres"
6+
export POSTGRES_DB="elasticapm_test"
7+
export POSTGRES_PORT="5432"

0 commit comments

Comments
 (0)