Skip to content

Commit a35c3f2

Browse files
authored
Merge pull request #2 from sourceplusplus/live-meter
Live meter
2 parents 78b98e9 + 61f3fbf commit a35c3f2

File tree

8 files changed

+100
-73
lines changed

8 files changed

+100
-73
lines changed

.github/workflows/e2e.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
PROBE_VERSION="$(python setup.py --version)"
2727
echo "SPP_PROBE_VERSION=$PROBE_VERSION" >> $GITHUB_ENV
2828
- run: python setup.py sdist
29-
- run: cp dist/sourceplusplus-${{ env.SPP_PROBE_VERSION }}.tar.gz e2e && ls && pwd
29+
- run: cp dist/sourceplusplus-${{ env.SPP_PROBE_VERSION }}.tar.gz e2e
3030
- run: cd e2e && docker-compose up -d
3131
- name: Docker IPs
3232
run: docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)
@@ -47,7 +47,7 @@ jobs:
4747
4848
- name: Download & install spp-cli
4949
run: |
50-
curl -O -J -L https://github.com/sourceplusplus/interface-cli/releases/latest/download/spp-cli && chmod +x spp-cli && mv spp-cli /usr/local/bin/spp-cli
50+
curl -O -J -L https://github.com/sourceplusplus/interface-cli/releases/latest/download/spp-cli-linux64.zip && unzip spp-cli-linux64.zip && chmod +x spp-cli && mv spp-cli /usr/local/bin/spp-cli
5151
5252
- name: Live breakpoint (false condition)
5353
run: |

e2e/docker-compose.yml

-19
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,10 @@ services:
4646
ports:
4747
- "11800:11800"
4848
depends_on:
49-
- es-server
5049
- spp-platform
5150
links:
52-
- es-server
5351
- spp-platform
54-
restart: on-failure
5552
environment:
56-
- SW_STORAGE=elasticsearch
57-
- SW_STORAGE_ES_CLUSTER_NODES=es-server:9200
5853
- SPP_PLATFORM_HOST=spp-platform
5954
- SPP_PLATFORM_PORT=5460
6055
- SPP_PLATFORM_CERTIFICATE_FILE=/skywalking/spp-platform.crt
@@ -65,17 +60,3 @@ services:
6560
- SW_RECEIVER_GRPC_SSL_ENABLED=true
6661
- SW_RECEIVER_GRPC_SSL_KEY_PATH=/skywalking/spp-platform.key
6762
- SW_RECEIVER_GRPC_SSL_CERT_CHAIN_PATH=/skywalking/spp-platform.crt
68-
es-server:
69-
image: blacktop/elasticsearch:7.0.0
70-
container_name: es-server
71-
hostname: es-server
72-
cap_add:
73-
- IPC_LOCK
74-
ulimits:
75-
memlock:
76-
soft: -1
77-
hard: -1
78-
nofile:
79-
soft: 65536
80-
hard: 65536
81-
command: -E cluster.name=es-skywalking -E path.data=data -E path.logs=logs -E network.host=0.0.0.0 -E node.name=node-1

e2e/spp-probe.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ skywalking:
1212
class_cache_mode: "FILE"
1313
service_name: "spp"
1414
collector:
15-
backend_service: "skywalking-oap:11800"
15+
backend_service: "skywalking-oap:11800"
16+
plugin:
17+
toolkit:
18+
log:
19+
transmit_formatted: false

sourceplusplus/SourcePlusPlus.py

+6
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,9 @@ def __register_remotes(self, eb, reply_address, status):
133133
LiveInstrumentCommand.from_json(json.dumps(msg["body"])), LiveInstrumentType.LOG
134134
)
135135
)
136+
eb.register_handler(
137+
address="spp.probe.command.live-meter-remote:" + self.probe_config["spp"]["probe_id"],
138+
handler=lambda msg: self.instrument_remote.handle_instrument_command(
139+
LiveInstrumentCommand.from_json(json.dumps(msg["body"])), LiveInstrumentType.METER
140+
)
141+
)

sourceplusplus/control/ContextReceiver.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import threading
33
import time
44
import traceback
5-
65
from skywalking import config, agent
76
from skywalking.protocol.common.Common_pb2 import KeyStringValuePair
87
from skywalking.protocol.logging.Logging_pb2 import LogData, LogDataBody, TextLog, TraceContext, LogTags
@@ -12,6 +11,7 @@
1211
from sourceplusplus.control.LiveInstrumentRemote import LiveInstrumentRemote
1312
from sourceplusplus.models.instrument.LiveBreakpoint import LiveBreakpoint
1413
from sourceplusplus.models.instrument.LiveLog import LiveLog
14+
from sourceplusplus.models.instrument.LiveMeter import LiveMeter
1515

1616

1717
def try_find(var, globals, locals):
@@ -21,7 +21,16 @@ def try_find(var, globals, locals):
2121
return globals[var]
2222

2323

24-
def do_log(live_log_id, globals, locals):
24+
def apply_meter(live_meter_id, globals, locals):
25+
live_meter: LiveMeter = LiveInstrumentRemote.instruments[live_meter_id][1]
26+
if live_meter.throttle.is_rate_limited():
27+
return
28+
if live_meter.condition is not None and not eval(live_meter.condition, globals, locals):
29+
return
30+
pass
31+
32+
33+
def apply_log(live_log_id, globals, locals):
2534
live_log: LiveLog = LiveInstrumentRemote.instruments[live_log_id][1]
2635
if live_log.throttle.is_rate_limited():
2736
return
@@ -80,7 +89,7 @@ def do_log(live_log_id, globals, locals):
8089
})
8190

8291

83-
def do_breakpoint(live_breakpoint_id, globals, locals):
92+
def apply_breakpoint(live_breakpoint_id, globals, locals):
8493
live_breakpoint: LiveBreakpoint = LiveInstrumentRemote.instruments[live_breakpoint_id][1]
8594
if live_breakpoint.throttle.is_rate_limited():
8695
return
@@ -94,7 +103,7 @@ def do_breakpoint(live_breakpoint_id, globals, locals):
94103
for key in locals:
95104
var = try_find(key, globals, locals)
96105
tag = StringTag(json.dumps({
97-
key: str(var), # don't str everything
106+
key: str(var), # todo: don't str everything
98107
"@class": str(type(var)),
99108
"@identity": id(var)
100109
}))
+41-47
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import json
22
import sys
33
import threading
4-
4+
from nopdb import nopdb
55
from vertx import EventBus
66

7-
from nopdb import nopdb
87
from sourceplusplus.models.command.CommandType import CommandType
98
from sourceplusplus.models.command.LiveInstrumentCommand import LiveInstrumentCommand
109
from sourceplusplus.models.command.LiveInstrumentContext import LiveInstrumentContext
1110
from sourceplusplus.models.instrument.LiveBreakpoint import LiveBreakpoint
1211
from sourceplusplus.models.instrument.LiveLog import LiveLog
12+
from sourceplusplus.models.instrument.LiveMeter import LiveMeter
1313
from sourceplusplus.models.instrument.common.LiveInstrumentType import LiveInstrumentType
1414
from sourceplusplus.models.instrument.common.LiveSourceLocation import LiveSourceLocation
1515

@@ -25,55 +25,50 @@ def __init__(self, eb: EventBus):
2525
LiveInstrumentRemote.dbg.start()
2626
threading.settrace(sys.gettrace())
2727

28-
def add_live_log(self, context: LiveInstrumentContext):
29-
for i in context.instruments:
30-
live_log = LiveLog.from_json(i)
31-
bp = LiveInstrumentRemote.dbg.breakpoint(file=live_log.location.source, line=live_log.location.line)
32-
LiveInstrumentRemote.instruments[live_log.id] = [bp, live_log]
33-
bp.exec("import sourceplusplus.control.ContextReceiver as ContextReceiver\n"
34-
"ContextReceiver.do_log('" + live_log.id + "',globals(),locals())")
35-
self.eb.publish(address="spp.platform.status.live-log-applied", body=json.loads(i))
36-
37-
def remove_live_log(self, context: LiveInstrumentContext):
38-
print("Removing live log(s)")
39-
for i in context.instruments:
40-
live_log = LiveLog.from_json(i)
41-
try:
42-
LiveInstrumentRemote.dbg.remove_callback(LiveInstrumentRemote.instruments.pop(live_log.id)[0]._handle)
43-
except KeyError:
44-
pass
45-
for i in context.locations:
46-
loc = LiveSourceLocation.from_json(i)
47-
delete = []
48-
for key, val in LiveInstrumentRemote.instruments.items():
49-
if isinstance(val[1], LiveLog) and val[1].location == loc:
50-
delete.append(key)
51-
for i in delete:
52-
del LiveInstrumentRemote.instruments[i]
53-
54-
def add_live_breakpoint(self, context: LiveInstrumentContext):
55-
print("Adding live breakpoint(s)")
28+
def add_live_instrument(self, context: LiveInstrumentContext, instrument_type: LiveInstrumentType):
5629
for i in context.instruments:
57-
live_bp = LiveBreakpoint.from_json(i)
58-
bp = LiveInstrumentRemote.dbg.breakpoint(file=live_bp.location.source, line=live_bp.location.line)
59-
LiveInstrumentRemote.instruments[live_bp.id] = [bp, live_bp]
60-
bp.exec("import sourceplusplus.control.ContextReceiver as ContextReceiver\n"
61-
"ContextReceiver.do_breakpoint('" + live_bp.id + "',globals(),locals())")
62-
self.eb.publish(address="spp.platform.status.live-breakpoint-applied", body=json.loads(i))
30+
if instrument_type == LiveInstrumentType.BREAKPOINT:
31+
live_instrument = LiveBreakpoint.from_json(i)
32+
elif instrument_type == LiveInstrumentType.LOG:
33+
live_instrument = LiveLog.from_json(i)
34+
else:
35+
live_instrument = LiveMeter.from_json(i)
36+
bp = LiveInstrumentRemote.dbg.breakpoint(
37+
file=live_instrument.location.source,
38+
line=live_instrument.location.line
39+
)
40+
LiveInstrumentRemote.instruments[live_instrument.id] = [bp, live_instrument]
41+
if instrument_type == LiveInstrumentType.BREAKPOINT:
42+
bp.exec("import sourceplusplus.control.ContextReceiver as ContextReceiver\n"
43+
"ContextReceiver.apply_breakpoint('" + live_instrument.id + "',globals(),locals())")
44+
self.eb.publish(address="spp.platform.status.live-breakpoint-applied", body=json.loads(i))
45+
elif instrument_type == LiveInstrumentType.LOG:
46+
bp.exec("import sourceplusplus.control.ContextReceiver as ContextReceiver\n"
47+
"ContextReceiver.apply_log('" + live_instrument.id + "',globals(),locals())")
48+
self.eb.publish(address="spp.platform.status.live-log-applied", body=json.loads(i))
49+
else:
50+
bp.exec("import sourceplusplus.control.ContextReceiver as ContextReceiver\n"
51+
"ContextReceiver.apply_meter('" + live_instrument.id + "',globals(),locals())")
52+
self.eb.publish(address="spp.platform.status.live-meter-applied", body=json.loads(i))
6353

64-
def remove_live_breakpoint(self, context: LiveInstrumentContext):
65-
print("Removing live breakpoint(s)")
54+
def remove_live_instrument(self, context: LiveInstrumentContext, type: LiveInstrumentType):
55+
print("Removing live instrument(s)")
6656
for i in context.instruments:
67-
live_bp = LiveBreakpoint.from_json(i)
57+
if type == LiveInstrumentType.BREAKPOINT:
58+
instrument = LiveBreakpoint.from_json(i)
59+
elif type == LiveInstrumentType.LOG:
60+
instrument = LiveLog.from_json(i)
61+
else:
62+
instrument = LiveMeter.from_json(i)
6863
try:
69-
LiveInstrumentRemote.dbg.remove_callback(LiveInstrumentRemote.instruments.pop(live_bp.id)[0]._handle)
64+
LiveInstrumentRemote.dbg.remove_callback(LiveInstrumentRemote.instruments.pop(instrument.id)[0]._handle)
7065
except KeyError:
7166
pass
7267
for i in context.locations:
7368
loc = LiveSourceLocation.from_json(i)
7469
delete = []
7570
for key, val in LiveInstrumentRemote.instruments.items():
76-
if isinstance(val[1], LiveBreakpoint) and val[1].location == loc:
71+
if val[1].type == type and val[1].location == loc:
7772
delete.append(key)
7873
for i in delete:
7974
del LiveInstrumentRemote.instruments[i]
@@ -82,11 +77,10 @@ def handle_instrument_command(self, command: LiveInstrumentCommand, instrument_t
8277
print("Received command: " + command.command_type)
8378
if command.command_type == CommandType.ADD_LIVE_INSTRUMENT:
8479
if instrument_type == LiveInstrumentType.BREAKPOINT:
85-
self.add_live_breakpoint(command.context)
80+
self.add_live_instrument(command.context, LiveInstrumentType.BREAKPOINT)
81+
elif instrument_type == LiveInstrumentType.LOG:
82+
self.add_live_instrument(command.context, LiveInstrumentType.LOG)
8683
else:
87-
self.add_live_log(command.context)
84+
self.add_live_instrument(command.context, LiveInstrumentType.METER)
8885
elif command.command_type == CommandType.REMOVE_LIVE_INSTRUMENT:
89-
if instrument_type == LiveInstrumentType.BREAKPOINT:
90-
self.remove_live_breakpoint(command.context)
91-
else:
92-
self.remove_live_log(command.context)
86+
self.remove_live_instrument(command.context, instrument_type)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import json
2+
3+
import humps
4+
5+
from .common.LiveInstrument import LiveInstrument
6+
from .common.LiveInstrumentType import LiveInstrumentType
7+
from .common.LiveSourceLocation import LiveSourceLocation
8+
from .common.throttle.HitThrottle import HitThrottle
9+
from .common.throttle.ThrottleStep import ThrottleStep
10+
11+
12+
class LiveMeter(LiveInstrument):
13+
def __init__(self, location: LiveSourceLocation):
14+
super().__init__(location)
15+
self.hit_limit = -1
16+
self.type = LiveInstrumentType.METER
17+
18+
@classmethod
19+
def from_json(cls, json_str):
20+
json_dict = humps.decamelize(json.loads(json_str))
21+
# todo: easier way to convert
22+
location = LiveSourceLocation(json_dict["location"]["source"], json_dict["location"]["line"])
23+
meter = LiveMeter(location)
24+
for key in json_dict:
25+
setattr(meter, key, json_dict[key])
26+
meter.location = LiveSourceLocation(json_dict["location"]["source"], json_dict["location"]["line"])
27+
28+
if "throttle" in json_dict:
29+
meter.throttle = HitThrottle(json_dict["throttle"]["limit"], ThrottleStep(json_dict["throttle"]["step"]))
30+
31+
meter.type = LiveInstrumentType.METER
32+
return meter

sourceplusplus/models/instrument/common/LiveInstrumentType.py

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
class LiveInstrumentType(str, Enum):
55
BREAKPOINT = "BREAKPOINT"
66
LOG = "LOG"
7+
METER = "METER"

0 commit comments

Comments
 (0)