Skip to content

Commit bbfa106

Browse files
authored
support python async api (#694)
* support python async api * add thread/process support * [enh] add asyncio plugins - standalone-py - py-photonix testapps - fastapi example - pinpointpy plugins and testcase * Update setup-php-sdk action * add more doc * fix unittest ci
1 parent 2352f99 commit bbfa106

37 files changed

+1366
-96
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,12 @@ jobs:
141141
steps:
142142
- uses: actions/checkout@v2
143143
- id: setup-php-sdk
144-
uses: php/setup-php-sdk@v0.8
144+
uses: php/setup-php-sdk@v0.10
145145
with:
146146
version: ${{ matrix.php-versions }}
147147
arch: ${{ matrix.arch }}
148148
ts: ${{ matrix.ts }}
149+
cache: true
149150
- uses: ilammy/msvc-dev-cmd@v1
150151
with:
151152
arch: ${{ matrix.arch }}
@@ -308,4 +309,4 @@ jobs:
308309
go install google.golang.org/protobuf/cmd/[email protected]
309310
go install google.golang.org/grpc/cmd/[email protected]
310311
# export PATH="$PATH:$(go env GOPATH)/bin"
311-
cd collector-agent && go mod tidy && go test ./... -v
312+
cd collector-agent && go mod tidy && go test ./... -v

DOC/PY/python..excalidraw.png

69.4 KB
Loading

common/include/common.h.in

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ int pinpoint_trace_is_root(NodeID);
154154
* @return int 0 : means oK
155155
* -1: exception found, check the log
156156
*/
157-
DEPRECATED(
158-
"use pinpoint_end_trace. if you need no span missing, set pinpoint_set_agent with `timeout_ms`")
157+
DEPRECATED("use pinpoint_end_trace. if you need all span, set pinpoint_set_agent with `timeout_ms`")
159158
int pinpoint_force_end_trace(NodeID, int32_t timeout);
160159

161160
/**

common/include/pinpoint/common.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ int pinpoint_trace_is_root(NodeID);
154154
* @return int 0 : means oK
155155
* -1: exception found, check the log
156156
*/
157-
DEPRECATED(
158-
"use pinpoint_end_trace. if you need no span missing, set pinpoint_set_agent with `timeout_ms`")
157+
DEPRECATED("use pinpoint_end_trace. if you need all span, set pinpoint_set_agent with `timeout_ms`")
159158
int pinpoint_force_end_trace(NodeID, int32_t timeout);
160159

161160
/**

plugins/PY/pinpointPy/Common.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@
2323
from pinpointPy.TraceContext import get_trace_context
2424
from functools import wraps
2525

26+
import warnings
27+
import functools
28+
29+
30+
def deprecated(reason: str):
31+
def decorator(func):
32+
@functools.wraps(func)
33+
def deprecated_func(*args, **kwargs):
34+
warnings.warn(f"{func.__name__} is deprecated. Reason: {reason}",
35+
category=DeprecationWarning, stacklevel=2)
36+
return func(*args, **kwargs)
37+
return deprecated_func
38+
return decorator
39+
2640

2741
class Trace:
2842
def __init__(self, name):
@@ -58,6 +72,9 @@ class PinTrace:
5872
def __init__(self, name):
5973
self.name = name
6074

75+
def setCurrentTraceNodeId(self, traceId):
76+
get_trace_context().set_parent_id(traceId)
77+
6178
def onBefore(self, parentId: int, *args, **kwargs):
6279
traceId = pinpoint.with_trace(parentId)
6380
get_trace_context().set_parent_id(traceId)
@@ -111,6 +128,32 @@ def getUniqueName(self):
111128
return self.name
112129

113130

131+
class AsyncPinTrace(PinTrace):
132+
133+
def __call__(self, func):
134+
self.func_name = func.__name__
135+
136+
@wraps(func)
137+
async def pinpointTrace(*args, **kwargs):
138+
ret = None
139+
# avoiding variable missing
140+
# use and return
141+
sampled, parentId, nArgs, nKwargs = self._isSample(*args, **kwargs)
142+
if not sampled:
143+
return await func(*nArgs, **nKwargs)
144+
traceId, nArgs, nKwargs = self.onBefore(
145+
parentId, *nArgs, **nKwargs)
146+
try:
147+
ret = await func(*nArgs, **nKwargs)
148+
return ret
149+
except Exception as e:
150+
self.onException(traceId, e)
151+
raise e
152+
finally:
153+
self.onEnd(traceId, ret)
154+
return pinpointTrace
155+
156+
114157
class TraceIdObject:
115158
def __init__(self, id: int) -> None:
116159
self.traceId = id
@@ -179,7 +222,7 @@ class PinTransaction(PinTrace):
179222
def __init__(self, name: str, userGenHeaderCb: GenPinHeader):
180223
"""pinpointPy user entry point
181224
182-
Example:
225+
Example:
183226
184227
```
185228
from pinpointPy.Common import GenPinHeader, PinHeader, PinTransaction
@@ -195,7 +238,7 @@ def run(msg):
195238
```
196239
Args:
197240
name (str): entry points name(showing pinpoint)
198-
userGenHeaderCb (GenPinHeader): This helps getting header from current function
241+
userGenHeaderCb (GenPinHeader): This helps getting header from current function
199242
"""
200243
super().__init__(name)
201244
self.name: str = name
@@ -215,12 +258,16 @@ def onBefore(self, parentId: int, *args, **kwargs):
215258

216259
pinpoint.add_trace_header(
217260
Defines.PP_INTERCEPTOR_NAME, self.name, traceId)
261+
218262
pinpoint.add_trace_header(
219263
Defines.PP_APP_NAME, pinpoint.app_name(), traceId)
220264
pinpoint.add_context(
221265
Defines.PP_APP_NAME, pinpoint.app_name(), traceId)
266+
222267
pinpoint.add_trace_header(
223268
Defines.PP_APP_ID, pinpoint.app_id(), traceId)
269+
pinpoint.add_context(
270+
Defines.PP_APP_ID, pinpoint.app_id(), traceId)
224271

225272
pinpoint.add_trace_header(Defines.PP_REQ_URI, header.Url, traceId)
226273
pinpoint.add_trace_header(Defines.PP_REQ_SERVER, header.Host, traceId)
@@ -264,3 +311,13 @@ def onEnd(self, traceId, ret):
264311
def onException(self, traceId, e):
265312
pinpoint.mark_as_error(str(e), "", 0, traceId)
266313
raise e
314+
315+
316+
def enable_experiment_plugins(async_plugins: bool = True):
317+
if async_plugins:
318+
from pinpointPy.libs._threading import monkey_patch as thread_patch
319+
thread_patch()
320+
from pinpointPy.libs._process import monkey_patch as process_patch
321+
process_patch()
322+
from pinpointPy.libs._asyncio import monkey_patch as asyncio_patch
323+
asyncio_patch()

plugins/PY/pinpointPy/CommonPlugin.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717

1818
from pinpointPy import Common, Defines, pinpoint
19+
import random
1920

2021

2122
class PinpointCommonPlugin(Common.PinTrace):
@@ -36,3 +37,92 @@ def onEnd(self, traceId, ret):
3637
def onException(self, traceId, e):
3738
pinpoint.add_exception(str(e), traceId)
3839
raise e
40+
41+
42+
class AsyncCommonPlugin(Common.AsyncPinTrace):
43+
44+
# -> tuple[int, Any, dict[str, Any]]:
45+
def onBefore(self, parentId, *args, **kwargs):
46+
traceId, args, kwargs = super().onBefore(parentId, *args, **kwargs)
47+
pinpoint.add_trace_header(
48+
Defines.PP_INTERCEPTOR_NAME, self.getUniqueName(), traceId)
49+
pinpoint.add_trace_header(
50+
Defines.PP_SERVER_TYPE, Defines.PP_METHOD_CALL, traceId)
51+
return traceId, args, kwargs
52+
53+
def onEnd(self, traceId, ret):
54+
super().onEnd(traceId, ret)
55+
56+
def onException(self, traceId, e):
57+
pinpoint.add_exception(str(e), traceId)
58+
59+
60+
class HookTargetPlugins(Common.PinTrace):
61+
def onBefore(self, parentId: int, *args, **kwargs):
62+
63+
traceId, args, kwargs = super().onBefore(parentId, *args, **kwargs)
64+
pinpoint.add_trace_header(
65+
Defines.PP_INTERCEPTOR_NAME, self.getUniqueName(), traceId)
66+
pinpoint.add_trace_header(
67+
Defines.PP_SERVER_TYPE, Defines.P_INVOCATION_CALL_TYPE, traceId)
68+
69+
async_id = random.randint(0, 9999)
70+
pinpoint.add_trace_header(
71+
Defines.PP_ASYNC_CALL_ID, f'{async_id}', traceId)
72+
73+
sequence_id = pinpoint.get_sequence_id(traceId)
74+
75+
tid = pinpoint.get_context(Defines.PP_TRANSCATION_ID, traceId)
76+
seq_id = pinpoint.get_context(Defines.PP_SPAN_ID, traceId)
77+
app_name = pinpoint.get_context(Defines.PP_APP_NAME, traceId)
78+
app_id = pinpoint.get_context(Defines.PP_APP_ID, traceId)
79+
80+
if 'target' in kwargs:
81+
origin_target = kwargs['target']
82+
83+
def pp_new_entry_func(*args, **kwargs):
84+
# start trace
85+
thread_trace_id = pinpoint.with_trace(0)
86+
self.setCurrentTraceNodeId(thread_trace_id)
87+
pinpoint.add_trace_header(
88+
Defines.PP_APP_NAME, app_name, thread_trace_id)
89+
pinpoint.add_context(
90+
Defines.PP_APP_NAME, app_name, thread_trace_id)
91+
92+
pinpoint.add_trace_header(
93+
Defines.PP_APP_ID, app_id, thread_trace_id)
94+
pinpoint.add_context(
95+
Defines.PP_APP_ID, app_id, thread_trace_id)
96+
97+
pinpoint.add_trace_header(
98+
Defines.PP_SPAN_ID, seq_id, thread_trace_id)
99+
pinpoint.add_context(
100+
Defines.PP_SPAN_ID, seq_id, thread_trace_id)
101+
102+
pinpoint.add_trace_header(
103+
Defines.PP_TRANSCATION_ID, tid, thread_trace_id)
104+
pinpoint.add_context(
105+
Defines.PP_TRANSCATION_ID, tid, thread_trace_id)
106+
107+
pinpoint.add_trace_header(
108+
Defines.PP_SERVER_TYPE, Defines.PYTHON, thread_trace_id)
109+
pinpoint.set_async_context(
110+
thread_trace_id, async_id, sequence_id)
111+
112+
if callable(origin_target):
113+
# todo add
114+
@PinpointCommonPlugin(origin_target.__name__)
115+
def call_origin_target(*args, **kwargs):
116+
origin_target(*args, **kwargs)
117+
118+
call_origin_target(*args, **kwargs)
119+
120+
pinpoint.end_trace(thread_trace_id)
121+
122+
kwargs['target'] = pp_new_entry_func
123+
124+
return traceId, args, kwargs
125+
126+
def onEnd(self, traceId, ret):
127+
super().onEnd(traceId, ret)
128+
return ret

plugins/PY/pinpointPy/Defines.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@
7676
PP_CELERY = '1702'
7777

7878
PP_REMOTE_METHOD = '9900'
79+
P_INVOCATION_CALL_TYPE = '100'
80+
81+
PP_ASYNC_CALL_ID = 'asyId'
7982

8083
PP_HTTP_URL = '40'
8184
PP_HTTP_PARAM = '41'

plugins/PY/pinpointPy/Fastapi/AsyCommon.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,24 @@
2020
from pinpointPy.TraceContext import TraceContext
2121
from pinpointPy.Common import PinTrace
2222

23+
2324
class AsyncTraceContext (TraceContext):
2425
def get_parent_id(self):
25-
id = context.get('_pinpoint_id_', 0)
26-
if id == 0:
26+
try:
27+
id = context.get('_pinpoint_id_', 0)
28+
if id == 0:
29+
return False, -1
30+
else:
31+
return True, id
32+
except Exception:
2733
return False, -1
28-
else:
29-
return True, id
3034

3135
def set_parent_id(self, id: int):
3236
context['_pinpoint_id_'] = id
3337

3438

3539
class AsyncPinTrace(PinTrace):
36-
40+
3741
def __call__(self, func):
3842
self.func_name = func.__name__
3943

plugins/PY/pinpointPy/Fastapi/AsyCommonPlugin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
from pinpointPy.Fastapi.AsyCommon import AsyncPinTrace
1919
from pinpointPy import Defines, pinpoint
20+
from pinpointPy.Common import deprecated
2021

2122

23+
@deprecated("please use AsyncCommonPlugin in pinpointPy.CommonPlugin eg: `from pinpointPy.CommonPlugin import AsyncCommonPlugin`")
2224
class CommonPlugin(AsyncPinTrace):
2325

2426
# -> tuple[int, Any, dict[str, Any]]:

plugins/PY/pinpointPy/Fastapi/AsyRequestPlugin.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def onBefore(self, parentId, *args, **kwargs):
3434
pinpoint.add_trace_header(
3535
Defines.PP_APP_ID, pinpoint.app_id(), traceId)
3636
pinpoint.add_context(Defines.PP_APP_NAME, pinpoint.app_name(), traceId)
37+
pinpoint.add_context(Defines.PP_APP_ID, pinpoint.app_id(), traceId)
3738
###############################################################
3839
request = args[0]
3940

0 commit comments

Comments
 (0)