Skip to content

Commit

Permalink
Add Redis Plugin (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
alonelaval authored and kezhenxu94 committed Aug 3, 2020
1 parent 52ba611 commit 37e817b
Show file tree
Hide file tree
Showing 11 changed files with 414 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Library | Plugin Name
| [Flask](https://flask.palletsprojects.com/en/1.1.x/) | `sw_flask` |
| [PyMySQL](https://pymysql.readthedocs.io/en/latest/) | `sw_pymysql` |
| [Django](https://www.djangoproject.com/) | `sw_django` |
| [redis-py](https://github.com/andymccurdy/redis-py/) | `sw_redis` |

## API

Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"testcontainers",
"Werkzeug",
"pymysql",
"redis",
],
},
classifiers=[
Expand Down
1 change: 1 addition & 0 deletions skywalking/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Component(Enum):
Requests = 7002
PyMysql = 7003
Django = 7004
Redis = 7005


class Layer(Enum):
Expand Down
54 changes: 54 additions & 0 deletions skywalking/plugins/sw_redis/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# 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.
#
import logging

from skywalking import Layer, Component
from skywalking.trace import tags
from skywalking.trace.context import get_context
from skywalking.trace.tags import Tag

logger = logging.getLogger(__name__)


def install():
# noinspection PyBroadException
try:
from redis.connection import Connection

_send_command = Connection.send_command

def _sw_send_command(this: Connection, *args, **kwargs):
peer = "%s:%s" % (this.host, this.port)
op = args[0]
context = get_context()
with context.new_exit_span(op="Redis/"+op or "/", peer=peer) as span:
span.layer = Layer.Cache
span.component = Component.Redis

try:
res = _send_command(this, *args, **kwargs)
span.tag(Tag(key=tags.DbType, val="Redis"))
span.tag(Tag(key=tags.DbInstance, val=this.db))
span.tag(Tag(key=tags.DbStatement, val=op))
except BaseException as e:
span.raised()
raise e
return res

Connection.send_command = _sw_send_command
except Exception:
logger.warning('failed to install plugin %s', __name__)
16 changes: 16 additions & 0 deletions tests/plugin/sw_redis/__init__.py
Original file line number Diff line number Diff line change
@@ -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.
#
74 changes: 74 additions & 0 deletions tests/plugin/sw_redis/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#
# 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

redis:
image: redis:3.2.9-alpine
hostname: redis
ports:
- 6379:6379
healthcheck:
test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/6379"]
interval: 5s
timeout: 60s
retries: 120
networks:
- beyond

provider:
extends:
service: agent
file: ../docker/docker-compose.base.yml
ports:
- 9091:9091
volumes:
- ./services/provider.py:/app/provider.py
command: ['bash', '-c', 'pip install flask && pip install redis && python3 /app/provider.py']
depends_on:
collector:
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:
- ./services/consumer.py:/app/consumer.py
command: ['bash', '-c', 'pip install flask && python3 /app/consumer.py']
depends_on:
collector:
condition: service_healthy
provider:
condition: service_healthy

networks:
beyond:
127 changes: 127 additions & 0 deletions tests/plugin/sw_redis/expected.data.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#
# 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: Redis/SET
operationId: 0
parentSpanId: 0
spanId: 1
spanLayer: Cache
tags:
- key: db.type
value: Redis
- key: db.instance
value: '0'
- key: db.statement
value: 'SET'
startTime: gt 0
endTime: gt 0
componentId: 7005
spanType: Exit
peer: redis:6379
skipAnalysis: false
- operationName: Redis/GET
operationId: 0
parentSpanId: 0
spanId: 2
spanLayer: Cache
tags:
- key: db.type
value: Redis
- key: db.instance
value: '0'
- key: db.statement
value: 'GET'
startTime: gt 0
endTime: gt 0
componentId: 7005
spanType: Exit
peer: redis:6379
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
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
spanType: Entry
peer: not null
skipAnalysis: false
16 changes: 16 additions & 0 deletions tests/plugin/sw_redis/services/__init__.py
Original file line number Diff line number Diff line change
@@ -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.
#
37 changes: 37 additions & 0 deletions tests/plugin/sw_redis/services/consumer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# 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.
#

import requests

from skywalking import agent, config

if __name__ == '__main__':
config.service_name = 'consumer'
config.logging_level = 'DEBUG'
agent.start()

from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/users", methods=["POST", "GET"])
def application():
res = requests.post("http://provider:9091/users")
return jsonify(res.json())

PORT = 9090
app.run(host='0.0.0.0', port=PORT, debug=True)
44 changes: 44 additions & 0 deletions tests/plugin/sw_redis/services/provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#
# 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.
#

import time

from skywalking import agent, config

if __name__ == '__main__':
config.service_name = 'provider'
config.logging_level = 'DEBUG'
agent.start()

from flask import Flask, jsonify
import redis

app = Flask(__name__)

@app.route("/users", methods=["POST", "GET"])
def application():
time.sleep(0.5)

r = redis.StrictRedis(host='redis', port=6379, db=0)

r.set('foo', 'bar')
r.get('foo')

return jsonify({"song": "Despacito", "artist": "Luis Fonsi"})

PORT = 9091
app.run(host='0.0.0.0', port=PORT, debug=True)

0 comments on commit 37e817b

Please sign in to comment.