You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by to...@apache.org on 2021/06/06 17:05:35 UTC
[skywalking-python] branch master updated: psycopg plugin (#122)
This is an automated email from the ASF dual-hosted git repository.
tompytel pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-python.git
The following commit(s) were added to refs/heads/master by this push:
new 89b4c20 psycopg plugin (#122)
89b4c20 is described below
commit 89b4c2091f53704e654be124519545488d1834fe
Author: Tomasz Pytel <to...@gmail.com>
AuthorDate: Sun Jun 6 14:05:25 2021 -0300
psycopg plugin (#122)
* WIP initial psycopg plugin
* sql_parameters_length option
* converted to PostgreSQL component
---
Makefile | 2 +-
docs/EnvVars.md | 7 +-
docs/Plugins.md | 3 +-
requirements.txt | 1 +
skywalking/__init__.py | 1 +
skywalking/config.py | 4 +-
skywalking/plugins/sw_psycopg2.py | 122 +++++++++++++++++++++
skywalking/plugins/sw_pymysql.py | 4 +-
tests/plugin/sw_psycopg2/__init__.py | 16 +++
tests/plugin/sw_psycopg2/docker-compose.yml | 79 +++++++++++++
tests/plugin/sw_psycopg2/expected.data.yml | 114 +++++++++++++++++++
tests/plugin/sw_psycopg2/services/__init__.py | 16 +++
.../services/consumer.py} | 19 +---
.../services/provider.py | 6 +-
tests/plugin/sw_psycopg2/test_psycopg2.py | 36 ++++++
tests/plugin/sw_pymysql/services/provider.py | 2 +-
16 files changed, 403 insertions(+), 29 deletions(-)
diff --git a/Makefile b/Makefile
index 58590fa..e12c92e 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,7 @@ gen:
lint: clean
flake8 --version || python3 -m pip install flake8
flake8 . --count --select=E9,F63,F7,F82 --show-source
- flake8 . --count --max-complexity=13 --max-line-length=120
+ flake8 . --count --max-complexity=15 --max-line-length=120
license: clean
python3 tools/check-license-header.py skywalking tests tools
diff --git a/docs/EnvVars.md b/docs/EnvVars.md
index 6172dbf..cc23edd 100644
--- a/docs/EnvVars.md
+++ b/docs/EnvVars.md
@@ -9,9 +9,8 @@ Environment Variable | Description | Default
| `SW_AGENT_AUTHENTICATION` | The authentication token to verify that the agent is trusted by the backend OAP, as for how to configure the backend, refer to [the yaml](https://github.com/apache/skywalking/blob/4f0f39ffccdc9b41049903cc540b8904f7c9728e/oap-server/server-bootstrap/src/main/resources/application.yml#L155-L158). | unset |
| `SW_AGENT_LOGGING_LEVEL` | The logging level, could be one of `CRITICAL`, `FATAL`, `ERROR`, `WARN`(`WARNING`), `INFO`, `DEBUG` | `INFO` |
| `SW_AGENT_DISABLE_PLUGINS` | The name patterns in CSV pattern, plugins whose name matches one of the pattern won't be installed | `''` |
-| `SW_MYSQL_TRACE_SQL_PARAMETERS` | Indicates whether to collect the sql parameters or not | `False` |
-| `SW_MYSQL_SQL_PARAMETERS_MAX_LENGTH` | The maximum length of the collected parameter, parameters longer than the specified length will be truncated | `512` |
-| `SW_PYMONGO_TRACE_PARAMETERS` | Indicates whether to collect the filters of pymongo | `False` |
+| `SW_SQL_PARAMETERS_LENGTH` | The maximum length of the collected parameter, parameters longer than the specified length will be truncated, length 0 turns off parameter tracing | `0` |
+| `SW_PYMONGO_TRACE_PARAMETERS` | Indicates whether to collect the filters of pymongo | `False` |
| `SW_PYMONGO_PARAMETERS_MAX_LENGTH` | The maximum length of the collected filters, filters longer than the specified length will be truncated | `512` |
| `SW_IGNORE_SUFFIX` | If the operation name of the first span is included in this set, this segment should be ignored. | `.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg` |
| `SW_FLASK_COLLECT_HTTP_PARAMS`| This config item controls that whether the Flask plugin should collect the parameters of the request.| `false` |
@@ -23,6 +22,6 @@ Environment Variable | Description | Default
| `SW_TRACE_IGNORE_PATH`| You can setup multiple URL path patterns, The endpoints match these patterns wouldn't be traced. the current matching rules follow Ant Path match style , like /path/*, /path/**, /path/?.| `''` |
| `SW_ELASTICSEARCH_TRACE_DSL`| If true, trace all the DSL(Domain Specific Language) in ElasticSearch access, default is false | `false` |
| `SW_KAFKA_REPORTER_BOOTSTRAP_SERVERS` | A list of host/port pairs to use for establishing the initial connection to the Kafka cluster. It is in the form host1:port1,host2:port2,... | `localhost:9092` |
-| `SW_KAFKA_REPORTER_TOPIC_MANAGEMENT` | Specifying Kafka topic name for service instance reporting and registering. | `skywalking-managements` |
+| `SW_KAFKA_REPORTER_TOPIC_MANAGEMENT` | Specifying Kafka topic name for service instance reporting and registering. | `skywalking-managements` |
| `SW_KAFKA_REPORTER_TOPIC_SEGMENT` | Specifying Kafka topic name for Tracing data. | `skywalking-segments` |
| `SW_KAFKA_REPORTER_CONFIG_key` | The configs to init KafkaProducer. it support the basic arguments (whose type is either `str`, `bool`, or `int`) listed [here](https://kafka-python.readthedocs.io/en/master/apidoc/KafkaProducer.html#kafka.KafkaProducer) | unset |
diff --git a/docs/Plugins.md b/docs/Plugins.md
index fc7f1d6..28688e0 100644
--- a/docs/Plugins.md
+++ b/docs/Plugins.md
@@ -2,7 +2,7 @@
Library | Versions | Plugin Name
| :--- | :--- | :--- |
-| [http.server](https://docs.python.org/3/library/http.server.html) | Python 3.5 ~ 3.8 | `sw_http_server` |
+| [http.server](https://docs.python.org/3/library/http.server.html) | Python 3.5 ~ 3.9 | `sw_http_server` |
| [urllib.request](https://docs.python.org/3/library/urllib.request.html) | Python 3.5 ~ 3.8 | `sw_urllib_request` |
| [requests](https://requests.readthedocs.io/en/master/) | >= 2.9.0 < 2.15.0, >= 2.17.0 <= 2.24.0 | `sw_requests` |
| [Flask](https://flask.palletsprojects.com/en/1.1.x/) | >=1.0.4 <= 1.1.2 | `sw_flask` |
@@ -18,5 +18,6 @@ Library | Versions | Plugin Name
| [sanic](https://sanic.readthedocs.io/en/latest/) | >= 20.3.0 <= 20.9.1 | `sw_sanic` |
| [aiohttp](https://sanic.readthedocs.io/en/latest/) | >= 3.7.3 | `sw_aiohttp` |
| [pyramid](https://trypyramid.com) | >= 1.9 | `sw_pyramid` |
+| [psycopg2](https://www.psycopg.org/) | 2.8.6 | `sw_psycopg2` |
The column `Versions` only indicates that the versions are tested, if you found the newer versions are also supported, welcome to add the newer version into the table.
diff --git a/requirements.txt b/requirements.txt
index c0ccf07..91a06d2 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -34,6 +34,7 @@ parameterized==0.7.4
pika==1.1.0
pluggy==0.13.1
protobuf==3.12.4
+psycopg2-binary==2.8.6
py==1.9.0
pymongo==3.11.0
PyMySQL==0.10.0
diff --git a/skywalking/__init__.py b/skywalking/__init__.py
index eb180f1..482d39e 100644
--- a/skywalking/__init__.py
+++ b/skywalking/__init__.py
@@ -31,6 +31,7 @@ class Component(Enum):
Tornado = 7005
Redis = 7
MongoDB = 9
+ PostgreSQL = 22
KafkaProducer = 40
KafkaConsumer = 41
RabbitmqProducer = 52
diff --git a/skywalking/config.py b/skywalking/config.py
index d952381..60c2419 100644
--- a/skywalking/config.py
+++ b/skywalking/config.py
@@ -37,9 +37,7 @@ protocol = (os.getenv('SW_AGENT_PROTOCOL') or 'grpc').lower() # type: str
authentication = os.getenv('SW_AGENT_AUTHENTICATION') # type: str
logging_level = os.getenv('SW_AGENT_LOGGING_LEVEL') or 'INFO' # type: str
disable_plugins = (os.getenv('SW_AGENT_DISABLE_PLUGINS') or '').split(',') # type: List[str]
-mysql_trace_sql_parameters = True if os.getenv('SW_MYSQL_TRACE_SQL_PARAMETERS') and \
- os.getenv('SW_MYSQL_TRACE_SQL_PARAMETERS') == 'True' else False # type: bool
-mysql_sql_parameters_max_length = int(os.getenv('SW_MYSQL_SQL_PARAMETERS_MAX_LENGTH') or '512') # type: int
+sql_parameters_length = int(os.getenv('SW_SQL_PARAMETERS_LENGTH') or '0') # type: int
pymongo_trace_parameters = True if os.getenv('SW_PYMONGO_TRACE_PARAMETERS') and \
os.getenv('SW_PYMONGO_TRACE_PARAMETERS') == 'True' else False # type: bool
pymongo_parameters_max_length = int(os.getenv('SW_PYMONGO_PARAMETERS_MAX_LENGTH') or '512') # type: int
diff --git a/skywalking/plugins/sw_psycopg2.py b/skywalking/plugins/sw_psycopg2.py
new file mode 100644
index 0000000..1d5d137
--- /dev/null
+++ b/skywalking/plugins/sw_psycopg2.py
@@ -0,0 +1,122 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+from skywalking import Layer, Component, config
+from skywalking.trace import tags
+from skywalking.trace.context import get_context
+from skywalking.trace.tags import Tag
+
+
+def install():
+ import wrapt # psycopg2 is read-only C extension objects so they need to be proxied
+ import psycopg2
+
+ class ProxyCursor(wrapt.ObjectProxy):
+ def __init__(self, cur):
+ wrapt.ObjectProxy.__init__(self, cur)
+
+ self._self_cur = cur
+
+ def __enter__(self):
+ return ProxyCursor(wrapt.ObjectProxy.__enter__(self))
+
+ def execute(self, query, vars=None):
+ dsn = self.connection.get_dsn_parameters()
+ peer = dsn['host'] + ':' + dsn['port']
+
+ with get_context().new_exit_span(op="PostgreSLQ/Psycopg/execute", peer=peer) as span:
+ span.layer = Layer.Database
+ span.component = Component.PostgreSQL
+
+ span.tag(Tag(key=tags.DbType, val="PostgreSQL"))
+ span.tag(Tag(key=tags.DbInstance, val=dsn['dbname']))
+ span.tag(Tag(key=tags.DbStatement, val=query))
+
+ if config.sql_parameters_length and vars is not None:
+ text = ','.join(str(v) for v in vars)
+
+ if len(text) > config.sql_parameters_length:
+ text = text[:config.sql_parameters_length] + '...'
+
+ span.tag(Tag(key=tags.DbSqlParameters, val='[' + text + ']'))
+
+ return self._self_cur.execute(query, vars)
+
+ def executemany(self, query, vars_list):
+ dsn = self.connection.get_dsn_parameters()
+ peer = dsn['host'] + ':' + dsn['port']
+
+ with get_context().new_exit_span(op="PostgreSLQ/Psycopg/executemany", peer=peer) as span:
+ span.layer = Layer.Database
+ span.component = Component.PostgreSQL
+
+ span.tag(Tag(key=tags.DbType, val="PostgreSQL"))
+ span.tag(Tag(key=tags.DbInstance, val=dsn['dbname']))
+ span.tag(Tag(key=tags.DbStatement, val=query))
+
+ if config.sql_parameters_length:
+ max_len = config.sql_parameters_length
+ total_len = 0
+ text_list = []
+
+ for vars in vars_list:
+ text = '[' + ','.join(str(v) for v in vars) + ']'
+ total_len += len(text)
+
+ if total_len > max_len:
+ text_list.append(text[:max_len - total_len] + '...')
+
+ break
+
+ text_list.append(text)
+
+ span.tag(Tag(key=tags.DbSqlParameters, val='[' + ','.join(text_list) + ']'))
+
+ return self._self_cur.executemany(query, vars_list)
+
+ def callproc(self, procname, parameters=None):
+ dsn = self.connection.get_dsn_parameters()
+ peer = dsn['host'] + ':' + dsn['port']
+
+ with get_context().new_exit_span(op="PostgreSLQ/Psycopg/callproc", peer=peer) as span:
+ span.layer = Layer.Database
+ span.component = Component.PostgreSQL
+ args = '(' + ('' if not parameters else ','.join(parameters)) + ')'
+
+ span.tag(Tag(key=tags.DbType, val="PostgreSQL"))
+ span.tag(Tag(key=tags.DbInstance, val=dsn['dbname']))
+ span.tag(Tag(key=tags.DbStatement, val=procname + args))
+
+ return self._self_cur.callproc(procname, parameters)
+
+ class ProxyConnection(wrapt.ObjectProxy):
+ def __init__(self, conn):
+ wrapt.ObjectProxy.__init__(self, conn)
+
+ self._self_conn = conn
+
+ def __enter__(self):
+ return ProxyConnection(wrapt.ObjectProxy.__enter__(self))
+
+ def cursor(self, *args, **kwargs):
+ return ProxyCursor(self._self_conn.cursor(*args, **kwargs))
+
+ def connect(*args, **kwargs):
+ return ProxyConnection(_connect(*args, **kwargs))
+
+ _connect = psycopg2.connect
+ psycopg2.connect = connect
diff --git a/skywalking/plugins/sw_pymysql.py b/skywalking/plugins/sw_pymysql.py
index 15acdb5..715f918 100644
--- a/skywalking/plugins/sw_pymysql.py
+++ b/skywalking/plugins/sw_pymysql.py
@@ -39,9 +39,9 @@ def install():
span.tag(Tag(key=tags.DbInstance, val=(this.connection.db or b'').decode("utf-8")))
span.tag(Tag(key=tags.DbStatement, val=query))
- if config.mysql_trace_sql_parameters and args:
+ if config.sql_parameters_length and args:
parameter = ",".join([str(arg) for arg in args])
- max_len = config.mysql_sql_parameters_max_length
+ max_len = config.sql_parameters_length
parameter = parameter[0:max_len] + "..." if len(parameter) > max_len else parameter
span.tag(Tag(key=tags.DbSqlParameters, val='[' + parameter + ']'))
diff --git a/tests/plugin/sw_psycopg2/__init__.py b/tests/plugin/sw_psycopg2/__init__.py
new file mode 100644
index 0000000..b1312a0
--- /dev/null
+++ b/tests/plugin/sw_psycopg2/__init__.py
@@ -0,0 +1,16 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
diff --git a/tests/plugin/sw_psycopg2/docker-compose.yml b/tests/plugin/sw_psycopg2/docker-compose.yml
new file mode 100644
index 0000000..dfcf6c0
--- /dev/null
+++ b/tests/plugin/sw_psycopg2/docker-compose.yml
@@ -0,0 +1,79 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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: '2.1'
+
+services:
+ collector:
+ extends:
+ service: collector
+ file: ../docker/docker-compose.base.yml
+
+ postgres:
+ image: postgres:11
+ hostname: postgres
+ ports:
+ - 5432:5432
+ environment:
+ - POSTGRES_USER=root
+ - POSTGRES_PASSWORD=root
+ - POSTGRES_DB=admin
+ healthcheck:
+ test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/5432"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+ networks:
+ - beyond
+
+ provider:
+ extends:
+ service: agent
+ file: ../docker/docker-compose.base.yml
+ ports:
+ - 9091:9091
+ volumes:
+ - .:/app
+ command: ['bash', '-c', 'pip install flask && pip install -r /app/requirements.txt && python3 /app/services/provider.py']
+ depends_on:
+ collector:
+ condition: service_healthy
+ postgres:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9091"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+
+ consumer:
+ extends:
+ service: agent
+ file: ../docker/docker-compose.base.yml
+ ports:
+ - 9090:9090
+ volumes:
+ - .:/app
+ command: ['bash', '-c', 'pip install flask && python3 /app/services/consumer.py']
+ depends_on:
+ collector:
+ condition: service_healthy
+ provider:
+ condition: service_healthy
+
+networks:
+ beyond:
diff --git a/tests/plugin/sw_psycopg2/expected.data.yml b/tests/plugin/sw_psycopg2/expected.data.yml
new file mode 100644
index 0000000..6ff4ea5
--- /dev/null
+++ b/tests/plugin/sw_psycopg2/expected.data.yml
@@ -0,0 +1,114 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+segmentItems:
+ - serviceName: provider
+ segmentSize: 1
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: PostgreSLQ/Psycopg/execute
+ operationId: 0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Database
+ tags:
+ - key: db.type
+ value: PostgreSQL
+ - key: db.instance
+ value: admin
+ - key: db.statement
+ value: 'select * from user where user = %s'
+ - key: db.sql.parameters
+ value: '[root]'
+ startTime: gt 0
+ endTime: gt 0
+ isError: false
+ componentId: 22
+ spanType: Exit
+ peer: postgres:5432
+ skipAnalysis: false
+ - operationName: /users
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ tags:
+ - key: http.method
+ value: POST
+ - key: url
+ value: http://provider:9091/users
+ - key: status.code
+ value: '200'
+ refs:
+ - parentEndpoint: /users
+ networkAddress: provider:9091
+ refType: CrossProcess
+ parentSpanId: 1
+ parentTraceSegmentId: not null
+ parentServiceInstance: not null
+ parentService: consumer
+ traceId: not null
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 7001
+ spanType: Entry
+ peer: not null
+ skipAnalysis: false
+ - serviceName: consumer
+ segmentSize: 1
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /users
+ operationId: 0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Http
+ tags:
+ - key: http.method
+ value: POST
+ - key: url
+ value: http://provider:9091/users
+ - key: status.code
+ value: '200'
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 7002
+ isError: false
+ spanType: Exit
+ peer: provider:9091
+ skipAnalysis: false
+ - operationName: /users
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ tags:
+ - key: http.method
+ value: GET
+ - key: url
+ value: http://0.0.0.0:9090/users
+ - key: status.code
+ value: '200'
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 7001
+ isError: false
+ spanType: Entry
+ peer: not null
+ skipAnalysis: false
\ No newline at end of file
diff --git a/tests/plugin/sw_psycopg2/services/__init__.py b/tests/plugin/sw_psycopg2/services/__init__.py
new file mode 100644
index 0000000..b1312a0
--- /dev/null
+++ b/tests/plugin/sw_psycopg2/services/__init__.py
@@ -0,0 +1,16 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
diff --git a/tests/plugin/sw_pymysql/services/provider.py b/tests/plugin/sw_psycopg2/services/consumer.py
similarity index 68%
copy from tests/plugin/sw_pymysql/services/provider.py
copy to tests/plugin/sw_psycopg2/services/consumer.py
index 0e9f86f..c942f91 100644
--- a/tests/plugin/sw_pymysql/services/provider.py
+++ b/tests/plugin/sw_psycopg2/services/consumer.py
@@ -15,32 +15,23 @@
# limitations under the License.
#
-import time
+import requests
from skywalking import agent, config
if __name__ == '__main__':
- config.service_name = 'provider'
+ config.service_name = 'consumer'
config.logging_level = 'DEBUG'
- config.mysql_trace_sql_parameters = True
agent.start()
from flask import Flask, jsonify
- import pymysql.cursors
app = Flask(__name__)
@app.route("/users", methods=["POST", "GET"])
def application():
- time.sleep(0.5)
- connection = pymysql.connect(host='mysql', user='root', password='root', db='mysql', charset='utf8mb4')
- with connection.cursor() as cursor:
- sql = "select * from user where user = %s"
- cursor.execute(sql, ("root",))
+ res = requests.post("http://provider:9091/users")
+ return jsonify(res.json())
- connection.close()
-
- return jsonify({"song": "Despacito", "artist": "Luis Fonsi"})
-
- PORT = 9091
+ PORT = 9090
app.run(host='0.0.0.0', port=PORT, debug=True)
diff --git a/tests/plugin/sw_pymysql/services/provider.py b/tests/plugin/sw_psycopg2/services/provider.py
similarity index 88%
copy from tests/plugin/sw_pymysql/services/provider.py
copy to tests/plugin/sw_psycopg2/services/provider.py
index 0e9f86f..bf03a88 100644
--- a/tests/plugin/sw_pymysql/services/provider.py
+++ b/tests/plugin/sw_psycopg2/services/provider.py
@@ -22,18 +22,18 @@ from skywalking import agent, config
if __name__ == '__main__':
config.service_name = 'provider'
config.logging_level = 'DEBUG'
- config.mysql_trace_sql_parameters = True
+ config.sql_parameters_length = 512
agent.start()
from flask import Flask, jsonify
- import pymysql.cursors
+ import psycopg2
app = Flask(__name__)
@app.route("/users", methods=["POST", "GET"])
def application():
time.sleep(0.5)
- connection = pymysql.connect(host='mysql', user='root', password='root', db='mysql', charset='utf8mb4')
+ connection = psycopg2.connect(host='postgres', user='root', password='root', dbname='admin')
with connection.cursor() as cursor:
sql = "select * from user where user = %s"
cursor.execute(sql, ("root",))
diff --git a/tests/plugin/sw_psycopg2/test_psycopg2.py b/tests/plugin/sw_psycopg2/test_psycopg2.py
new file mode 100644
index 0000000..a21cb72
--- /dev/null
+++ b/tests/plugin/sw_psycopg2/test_psycopg2.py
@@ -0,0 +1,36 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+from typing import Callable
+
+import pytest
+import requests
+
+from tests.plugin.base import TestPluginBase
+
+
+@pytest.fixture
+def prepare():
+ # type: () -> Callable
+ return lambda *_: requests.get('http://0.0.0.0:9090/users')
+
+
+class TestPlugin(TestPluginBase):
+ @pytest.mark.parametrize('version', [
+ 'psycopg2-binary==2.8.6',
+ ])
+ def test_plugin(self, docker_compose, version):
+ self.validate()
diff --git a/tests/plugin/sw_pymysql/services/provider.py b/tests/plugin/sw_pymysql/services/provider.py
index 0e9f86f..8bb9cc5 100644
--- a/tests/plugin/sw_pymysql/services/provider.py
+++ b/tests/plugin/sw_pymysql/services/provider.py
@@ -22,7 +22,7 @@ from skywalking import agent, config
if __name__ == '__main__':
config.service_name = 'provider'
config.logging_level = 'DEBUG'
- config.mysql_trace_sql_parameters = True
+ config.sql_parameters_length = 512
agent.start()
from flask import Flask, jsonify