Skip to content

Commit 6c29a96

Browse files
Jedorewu-sheng
andauthored
Add Neo4j plugin. (#312)
* Add Neo4j plugin. --------- Co-authored-by: 吴晟 Wu Sheng <wu.sheng@foxmail.com>
1 parent 788182f commit 6c29a96

13 files changed

Lines changed: 527 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
## Change Logs
22

33
### 1.1.0
4+
- Plugins:
5+
- Add neo4j plugin.(#312)
46

57
- Fixes:
68
- Fix unexpected 'No active span' IllegalStateError (#311)

docs/en/setup/Plugins.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ or a limitation of SkyWalking auto-instrumentation (welcome to contribute!)
3333
| [kafka-python](https://kafka-python.readthedocs.io) | Python >=3.7 - ['2.0']; | `sw_kafka` |
3434
| [loguru](https://pypi.org/project/loguru/) | Python >=3.7 - ['0.6.0', '0.7.0']; | `sw_loguru` |
3535
| [mysqlclient](https://mysqlclient.readthedocs.io/) | Python >=3.7 - ['2.1.*']; | `sw_mysqlclient` |
36+
| [neo4j](https://neo4j.com/docs/python-manual/5/) | Python >=3.7 - ['5.*']; | `sw_neo4j` |
3637
| [psycopg[binary]](https://www.psycopg.org/) | Python >=3.11 - ['3.1.*']; Python >=3.7 - ['3.0.18', '3.1.*']; | `sw_psycopg` |
3738
| [psycopg2-binary](https://www.psycopg.org/) | Python >=3.10 - NOT SUPPORTED YET; Python >=3.7 - ['2.9']; | `sw_psycopg2` |
3839
| [pymongo](https://pymongo.readthedocs.io) | Python >=3.7 - ['3.11.*']; | `sw_pymongo` |
@@ -53,6 +54,8 @@ in SkyWalking currently. Celery clients can use whatever protocol they want.
5354
- While Falcon is instrumented, only Hug is tested.
5455
Hug is believed to be abandoned project, use this plugin with a bit more caution.
5556
Instead of Hug, plugin test should move to test actual Falcon.
57+
- The Neo4j plugin integrates neo4j python driver 5.x.x versions which
58+
support both Neo4j 5 and 4.4 DBMS.
5659
- The websocket instrumentation only traces client side connection handshake,
5760
the actual message exchange (send/recv) is not traced since injecting headers to socket message
5861
body is the only way to propagate the trace context, which requires customization of message structure

poetry.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ websockets = "^10.4"
132132
loguru = "^0.6.0"
133133
httpx = "^0.23.3"
134134
confluent-kafka = "^2.0.2"
135+
neo4j = "^5.9.0"
135136

136137
[tool.poetry.group.lint.dependencies]
137138
pylint = '2.13.9'

skywalking/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class Component(Enum):
3838
RabbitmqConsumer = 53
3939
Elasticsearch = 47
4040
HBase = 94
41+
Neo4j = 112
4142
Urllib3 = 7006
4243
Sanic = 7007
4344
AioHttp = 7008

skywalking/plugins/sw_neo4j.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
import json
19+
20+
from skywalking import Layer, Component, config
21+
from skywalking.trace.context import get_context
22+
from skywalking.trace.tags import TagDbType, TagDbInstance, TagDbStatement, TagDbSqlParameters
23+
24+
link_vector = ['https://neo4j.com/docs/python-manual/5/']
25+
support_matrix = {
26+
'neo4j': {
27+
'>=3.7': ['5.*'],
28+
}
29+
}
30+
note = """The Neo4j plugin integrates neo4j python driver 5.x.x versions which
31+
support both Neo4j 5 and 4.4 DBMS."""
32+
33+
34+
def install():
35+
from neo4j import AsyncSession, Session
36+
from neo4j._sync.work.transaction import TransactionBase
37+
from neo4j._async.work.transaction import AsyncTransactionBase
38+
39+
_session_run = Session.run
40+
_async_session_run = AsyncSession.run
41+
_transaction_run = TransactionBase.run
42+
_async_transaction_run = AsyncTransactionBase.run
43+
44+
def _archive_span(span, database, query, parameters, **kwargs):
45+
span.layer = Layer.Database
46+
span.tag(TagDbType('Neo4j'))
47+
span.tag(TagDbInstance(database or ''))
48+
span.tag(TagDbStatement(query))
49+
50+
parameters = dict(parameters or {}, **kwargs)
51+
if config.plugin_sql_parameters_max_length and parameters:
52+
parameter = json.dumps(parameters, ensure_ascii=False)
53+
max_len = config.plugin_sql_parameters_max_length
54+
parameter = f'{parameter[0:max_len]}...' if len(
55+
parameter) > max_len else parameter
56+
span.tag(TagDbSqlParameters(f'[{parameter}]'))
57+
58+
def get_peer(address):
59+
return f'{address.host}:{address.port}'
60+
61+
def _sw_session_run(self, query, parameters, **kwargs):
62+
with get_context().new_exit_span(
63+
op='Neo4j/Session/run',
64+
peer=get_peer(self._pool.address),
65+
component=Component.Neo4j) as span:
66+
_archive_span(span, self._config.database, query, parameters, **kwargs)
67+
return _session_run(self, query, parameters, **kwargs)
68+
69+
def _sw_transaction_run(self, query, parameters=None, **kwargs):
70+
with get_context().new_exit_span(
71+
op='Neo4j/Transaction/run',
72+
peer=get_peer(self._connection.unresolved_address),
73+
component=Component.Neo4j) as span:
74+
_archive_span(span, self._database, query, parameters, **kwargs)
75+
return _transaction_run(self, query, parameters, **kwargs)
76+
77+
async def _sw_async_session_run(self, query, parameters, **kwargs):
78+
with get_context().new_exit_span(
79+
op='Neo4j/AsyncSession/run',
80+
peer=get_peer(self._pool.address),
81+
component=Component.Neo4j) as span:
82+
_archive_span(span, self._config.database, query, parameters, **kwargs)
83+
return await _async_session_run(self, query, parameters, **kwargs)
84+
85+
async def _sw_async_transaction_run(self, query, parameters, **kwargs):
86+
with get_context().new_exit_span(
87+
op='Neo4j/AsyncTransaction/run',
88+
peer=get_peer(self._connection.unresolved_address),
89+
component=Component.Neo4j) as span:
90+
_archive_span(span, self._database, query, parameters, **kwargs)
91+
return await _async_transaction_run(self, query, parameters, **kwargs)
92+
93+
Session.run = _sw_session_run
94+
AsyncSession.run = _sw_async_session_run
95+
TransactionBase.run = _sw_transaction_run
96+
AsyncTransactionBase.run = _sw_async_transaction_run
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
version: '2.1'
19+
20+
services:
21+
collector:
22+
extends:
23+
service: collector
24+
file: ../../docker-compose.base.yml
25+
26+
neo4j:
27+
image: neo4j:4.4-community
28+
hostname: neo4j
29+
ports:
30+
- 7687:7687
31+
environment:
32+
- NEO4J_dbms_security_auth__enabled=false
33+
healthcheck:
34+
test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/7687"]
35+
interval: 5s
36+
timeout: 60s
37+
retries: 120
38+
networks:
39+
- beyond
40+
41+
provider:
42+
extends:
43+
service: agent
44+
file: ../../docker-compose.base.yml
45+
ports:
46+
- 9091:9091
47+
volumes:
48+
- .:/app
49+
command: ['bash', '-c', 'pip3 install uvicorn && pip3 install fastapi && pip3 install -r /app/requirements.txt && sw-python run python3 /app/services/provider.py']
50+
depends_on:
51+
collector:
52+
condition: service_healthy
53+
neo4j:
54+
condition: service_healthy
55+
healthcheck:
56+
test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9091"]
57+
interval: 5s
58+
timeout: 60s
59+
retries: 120
60+
environment:
61+
SW_AGENT_NAME: provider
62+
SW_AGENT_LOGGING_LEVEL: DEBUG
63+
SW_PLUGIN_SQL_PARAMETERS_MAX_LENGTH: 512
64+
65+
consumer:
66+
extends:
67+
service: agent
68+
file: ../../docker-compose.base.yml
69+
ports:
70+
- 9090:9090
71+
volumes:
72+
- .:/app
73+
command: ['bash', '-c', 'pip3 install uvicorn && pip3 install fastapi && pip3 install -r /app/requirements.txt && sw-python run python3 /app/services/consumer.py']
74+
depends_on:
75+
collector:
76+
condition: service_healthy
77+
provider:
78+
condition: service_healthy
79+
environment:
80+
SW_AGENT_NAME: consumer
81+
SW_AGENT_LOGGING_LEVEL: DEBUG
82+
83+
networks:
84+
beyond:

0 commit comments

Comments
 (0)