scale-gp-beta 0.1.0a23__py3-none-any.whl → 0.1.0a24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scale_gp_beta/_version.py +1 -1
- scale_gp_beta/lib/tracing/span.py +84 -53
- scale_gp_beta/lib/tracing/trace_queue_manager.py +7 -3
- scale_gp_beta/lib/tracing/tracing.py +9 -3
- {scale_gp_beta-0.1.0a23.dist-info → scale_gp_beta-0.1.0a24.dist-info}/METADATA +1 -1
- {scale_gp_beta-0.1.0a23.dist-info → scale_gp_beta-0.1.0a24.dist-info}/RECORD +8 -8
- {scale_gp_beta-0.1.0a23.dist-info → scale_gp_beta-0.1.0a24.dist-info}/WHEEL +0 -0
- {scale_gp_beta-0.1.0a23.dist-info → scale_gp_beta-0.1.0a24.dist-info}/licenses/LICENSE +0 -0
scale_gp_beta/_version.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
from copy import deepcopy
|
|
4
5
|
from typing import TYPE_CHECKING, Type, Optional
|
|
6
|
+
from threading import RLock
|
|
5
7
|
from typing_extensions import override
|
|
6
8
|
|
|
7
9
|
from scale_gp_beta.types.span_upsert_batch_params import Item as SpanCreateRequest
|
|
@@ -64,8 +66,8 @@ class BaseSpan:
|
|
|
64
66
|
self._group_id = group_id
|
|
65
67
|
self._span_id: str = span_id or generate_span_id()
|
|
66
68
|
self._parent_span_id = parent_span_id
|
|
67
|
-
self.
|
|
68
|
-
self.
|
|
69
|
+
self._start_time: Optional[str] = None
|
|
70
|
+
self._end_time: Optional[str] = None
|
|
69
71
|
self._input: SpanInputParam = input or {}
|
|
70
72
|
self._output: SpanOutputParam = output or {}
|
|
71
73
|
self._metadata: SpanMetadataParam = metadata or {}
|
|
@@ -74,6 +76,7 @@ class BaseSpan:
|
|
|
74
76
|
self._queue_manager = queue_manager
|
|
75
77
|
|
|
76
78
|
self._contextvar_token: Optional[contextvars.Token[Optional[BaseSpan]]] = None
|
|
79
|
+
self._lock = RLock()
|
|
77
80
|
|
|
78
81
|
def start(self) -> None:
|
|
79
82
|
pass
|
|
@@ -113,13 +116,33 @@ class BaseSpan:
|
|
|
113
116
|
return self._span_type
|
|
114
117
|
|
|
115
118
|
# with setters
|
|
119
|
+
@property
|
|
120
|
+
def start_time(self) -> Optional[str]:
|
|
121
|
+
return self._start_time
|
|
122
|
+
|
|
123
|
+
@start_time.setter
|
|
124
|
+
def start_time(self, value: Optional[str]) -> None:
|
|
125
|
+
with self._lock:
|
|
126
|
+
self._start_time = value
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def end_time(self) -> Optional[str]:
|
|
130
|
+
return self._end_time
|
|
131
|
+
|
|
132
|
+
@end_time.setter
|
|
133
|
+
def end_time(self, value: Optional[str]) -> None:
|
|
134
|
+
with self._lock:
|
|
135
|
+
self._end_time = value
|
|
136
|
+
|
|
116
137
|
@property
|
|
117
138
|
def metadata(self) -> SpanMetadataParam:
|
|
118
139
|
return self._metadata
|
|
119
140
|
|
|
120
141
|
@metadata.setter
|
|
121
142
|
def metadata(self, value: SpanMetadataParam) -> None:
|
|
122
|
-
|
|
143
|
+
# this does not protect against span.metadata["foo"] = "bar" which uses the getter, ditto input and output
|
|
144
|
+
with self._lock:
|
|
145
|
+
self._metadata = value
|
|
123
146
|
|
|
124
147
|
@property
|
|
125
148
|
def input(self) -> SpanInputParam:
|
|
@@ -127,7 +150,8 @@ class BaseSpan:
|
|
|
127
150
|
|
|
128
151
|
@input.setter
|
|
129
152
|
def input(self, value: SpanInputParam) -> None:
|
|
130
|
-
self.
|
|
153
|
+
with self._lock:
|
|
154
|
+
self._input = value
|
|
131
155
|
|
|
132
156
|
@property
|
|
133
157
|
def output(self) -> SpanOutputParam:
|
|
@@ -135,7 +159,8 @@ class BaseSpan:
|
|
|
135
159
|
|
|
136
160
|
@output.setter
|
|
137
161
|
def output(self, value: SpanOutputParam) -> None:
|
|
138
|
-
self.
|
|
162
|
+
with self._lock:
|
|
163
|
+
self._output = value
|
|
139
164
|
|
|
140
165
|
def set_error(
|
|
141
166
|
self,
|
|
@@ -144,12 +169,13 @@ class BaseSpan:
|
|
|
144
169
|
exception: Optional[BaseException] = None,
|
|
145
170
|
) -> None:
|
|
146
171
|
# Naively record details in metadata for now, note that error capture only supported in context manager
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
172
|
+
with self._lock:
|
|
173
|
+
exception_type = type(exception).__name__ if exception else None
|
|
174
|
+
exception_message = str(exception) if exception else None
|
|
175
|
+
self._status = "ERROR"
|
|
176
|
+
self.metadata["error"] = True
|
|
177
|
+
self.metadata["error_type"] = error_type or exception_type
|
|
178
|
+
self.metadata["error_message"] = error_message or exception_message
|
|
153
179
|
|
|
154
180
|
def __enter__(self) -> BaseSpan:
|
|
155
181
|
self.start()
|
|
@@ -167,32 +193,35 @@ class BaseSpan:
|
|
|
167
193
|
self.end()
|
|
168
194
|
|
|
169
195
|
def to_request_params(self) -> SpanCreateRequest:
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
196
|
+
with self._lock:
|
|
197
|
+
if self.start_time is None:
|
|
198
|
+
raise ParamsCreationError("No start time specified")
|
|
199
|
+
|
|
200
|
+
request_data = SpanCreateRequest(
|
|
201
|
+
name=self.name,
|
|
202
|
+
id=self.span_id,
|
|
203
|
+
trace_id=self.trace_id,
|
|
204
|
+
start_timestamp=self.start_time,
|
|
205
|
+
input=self.input,
|
|
206
|
+
output=self.output,
|
|
207
|
+
metadata=self.metadata,
|
|
208
|
+
status=self.status,
|
|
209
|
+
type=self.span_type
|
|
210
|
+
)
|
|
184
211
|
|
|
185
|
-
|
|
186
|
-
|
|
212
|
+
if self.end_time is not None:
|
|
213
|
+
request_data["end_timestamp"] = self.end_time
|
|
187
214
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
215
|
+
# parent_span_id is optional (root spans)
|
|
216
|
+
if self.parent_span_id is not None:
|
|
217
|
+
request_data["parent_id"] = self.parent_span_id
|
|
191
218
|
|
|
192
|
-
|
|
193
|
-
|
|
219
|
+
if self.group_id is not None:
|
|
220
|
+
request_data["group_id"] = self.group_id
|
|
194
221
|
|
|
195
|
-
|
|
222
|
+
# ensure no future changes to metadata, input or output changes request_data, full isolation
|
|
223
|
+
request_data = deepcopy(request_data)
|
|
224
|
+
return request_data
|
|
196
225
|
|
|
197
226
|
@override
|
|
198
227
|
def __repr__(self) -> str:
|
|
@@ -288,13 +317,14 @@ class Span(BaseSpan):
|
|
|
288
317
|
Sets the `start_time`, reports the span start to the `TraceQueueManager`
|
|
289
318
|
, and registers this span as the current span.
|
|
290
319
|
"""
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
320
|
+
with self._lock:
|
|
321
|
+
if self.start_time is not None:
|
|
322
|
+
log.warning(f"Span {self.name}: {self.span_id} has already started at {self.start_time}")
|
|
323
|
+
return
|
|
294
324
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
325
|
+
self.start_time = iso_timestamp()
|
|
326
|
+
self._queue_manager.report_span_start(self)
|
|
327
|
+
self._contextvar_token = Scope.set_current_span(self)
|
|
298
328
|
|
|
299
329
|
@override
|
|
300
330
|
def end(self) -> None:
|
|
@@ -304,19 +334,20 @@ class Span(BaseSpan):
|
|
|
304
334
|
`TraceQueueManager` for queuing and export, and resets this span from the
|
|
305
335
|
`Scope`.
|
|
306
336
|
"""
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
(
|
|
313
|
-
|
|
314
|
-
|
|
337
|
+
with self._lock:
|
|
338
|
+
if self.end_time is not None:
|
|
339
|
+
log.warning(f"Span {self.name}: {self.span_id} has already ended at {self.end_time}")
|
|
340
|
+
return
|
|
341
|
+
if self._contextvar_token is None:
|
|
342
|
+
log.warning(
|
|
343
|
+
(
|
|
344
|
+
f"Span {self.name}: {self.span_id} attempting to end without a valid context token. "
|
|
345
|
+
"Was start() called and completed successfully?"
|
|
346
|
+
)
|
|
315
347
|
)
|
|
316
|
-
|
|
317
|
-
return
|
|
348
|
+
return
|
|
318
349
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
350
|
+
self.end_time = iso_timestamp()
|
|
351
|
+
self._queue_manager.report_span_end(self)
|
|
352
|
+
Scope.reset_current_span(self._contextvar_token)
|
|
353
|
+
self._contextvar_token = None
|
|
@@ -30,7 +30,7 @@ class TraceQueueManager:
|
|
|
30
30
|
"""Manage trace and spans queue
|
|
31
31
|
Store spans in-memory until the threshold has been reached then flush to server.
|
|
32
32
|
|
|
33
|
-
Optionally provide a client, if unprovided we will attempt to create a default client.
|
|
33
|
+
Optionally provide a client, if unprovided, we will attempt to create a default client.
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
36
|
def __init__(
|
|
@@ -41,6 +41,7 @@ class TraceQueueManager:
|
|
|
41
41
|
trigger_queue_size: int = DEFAULT_TRIGGER_QUEUE_SIZE,
|
|
42
42
|
trigger_cadence: float = DEFAULT_TRIGGER_CADENCE,
|
|
43
43
|
retries: int = DEFAULT_RETRIES,
|
|
44
|
+
worker_enabled: Optional[bool] = None,
|
|
44
45
|
):
|
|
45
46
|
self._client = client
|
|
46
47
|
self._attempted_local_client_creation = False
|
|
@@ -54,7 +55,9 @@ class TraceQueueManager:
|
|
|
54
55
|
self._shutdown_event = threading.Event()
|
|
55
56
|
self._queue: queue.Queue[Span] = queue.Queue(maxsize=max_queue_size)
|
|
56
57
|
|
|
57
|
-
if not is_disabled()
|
|
58
|
+
self._worker_enabled = worker_enabled if worker_enabled is not None else not is_disabled()
|
|
59
|
+
|
|
60
|
+
if self._worker_enabled:
|
|
58
61
|
self._worker = threading.Thread(daemon=True, target=self._run)
|
|
59
62
|
self._worker.start()
|
|
60
63
|
|
|
@@ -66,7 +69,7 @@ class TraceQueueManager:
|
|
|
66
69
|
self._client = client
|
|
67
70
|
|
|
68
71
|
def shutdown(self, timeout: Optional[float] = None) -> None:
|
|
69
|
-
if
|
|
72
|
+
if not self._worker_enabled:
|
|
70
73
|
log.debug("No worker to shutdown")
|
|
71
74
|
return
|
|
72
75
|
log.info(f"Shutting down trace queue manager, joining worker thread with timeout {timeout}")
|
|
@@ -92,6 +95,7 @@ class TraceQueueManager:
|
|
|
92
95
|
|
|
93
96
|
def enqueue(self, span: "Span") -> None:
|
|
94
97
|
try:
|
|
98
|
+
# Should this be a deep copy of span instead? Currently is a reference
|
|
95
99
|
self._queue.put_nowait(span)
|
|
96
100
|
except queue.Full:
|
|
97
101
|
log.warning(f"Queue full, ignoring span {span.span_id}")
|
|
@@ -6,7 +6,7 @@ from .util import is_disabled
|
|
|
6
6
|
from .scope import Scope
|
|
7
7
|
from .trace import Trace, BaseTrace, NoOpTrace
|
|
8
8
|
from .types import SpanInputParam, SpanOutputParam, SpanTypeLiterals, SpanMetadataParam
|
|
9
|
-
from .trace_queue_manager import tracing_queue_manager
|
|
9
|
+
from .trace_queue_manager import TraceQueueManager, tracing_queue_manager
|
|
10
10
|
|
|
11
11
|
log: logging.Logger = logging.getLogger(__name__)
|
|
12
12
|
|
|
@@ -58,6 +58,7 @@ def create_trace(
|
|
|
58
58
|
span_id: Optional[str] = None,
|
|
59
59
|
trace_id: Optional[str] = None,
|
|
60
60
|
group_id: Optional[str] = None,
|
|
61
|
+
queue_manager: Optional[TraceQueueManager] = None,
|
|
61
62
|
) -> BaseTrace:
|
|
62
63
|
"""Creates a new trace and root span instance.
|
|
63
64
|
|
|
@@ -83,6 +84,8 @@ def create_trace(
|
|
|
83
84
|
If None, a unique trace ID will be generated.
|
|
84
85
|
Max length is 38 characters.
|
|
85
86
|
group_id (Optional[str]): An optional, id to group traces.
|
|
87
|
+
queue_manager (Optional[TraceQueueManager], optional): An optional `TraceQueueManager`.
|
|
88
|
+
Useful for when you need explicit control of flushing and client behavior.
|
|
86
89
|
|
|
87
90
|
Returns:
|
|
88
91
|
BaseTrace: A `Trace` instance if tracing is enabled, or a `NoOpTrace`
|
|
@@ -109,7 +112,7 @@ def create_trace(
|
|
|
109
112
|
if active_trace is not None:
|
|
110
113
|
log.warning(f"Trace with id {active_trace.trace_id} is already active. Creating a new trace anyways.")
|
|
111
114
|
|
|
112
|
-
queue_manager = tracing_queue_manager()
|
|
115
|
+
queue_manager = queue_manager or tracing_queue_manager()
|
|
113
116
|
trace = Trace(
|
|
114
117
|
name=name,
|
|
115
118
|
trace_id=trace_id,
|
|
@@ -136,6 +139,7 @@ def create_span(
|
|
|
136
139
|
parent_id: Optional[str] = None,
|
|
137
140
|
trace_id: Optional[str] = None,
|
|
138
141
|
group_id: Optional[str] = None,
|
|
142
|
+
queue_manager: Optional[TraceQueueManager] = None,
|
|
139
143
|
) -> BaseSpan:
|
|
140
144
|
"""Creates a new span instance.
|
|
141
145
|
|
|
@@ -171,6 +175,8 @@ def create_span(
|
|
|
171
175
|
trace_id (Optional[str], optional): A `Trace` id. Used for explicit control.
|
|
172
176
|
Default to trace id fetched from the active scope.
|
|
173
177
|
group_id (Optional[str]): An optional, id to group traces.
|
|
178
|
+
queue_manager (Optional[TraceQueueManager], optional): An optional `TraceQueueManager`.
|
|
179
|
+
Useful for when you need explicit control of flushing and client behavior.
|
|
174
180
|
|
|
175
181
|
Returns:
|
|
176
182
|
BaseSpan: A `Span` instance if tracing is enabled and a valid trace context
|
|
@@ -213,7 +219,7 @@ def create_span(
|
|
|
213
219
|
log.debug(f"Attempting to create a span with no trace")
|
|
214
220
|
return noop_span
|
|
215
221
|
|
|
216
|
-
queue_manager = tracing_queue_manager()
|
|
222
|
+
queue_manager = queue_manager or tracing_queue_manager()
|
|
217
223
|
span = Span(
|
|
218
224
|
name=name,
|
|
219
225
|
span_id=span_id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: scale-gp-beta
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0a24
|
|
4
4
|
Summary: The official Python library for the Scale GP API
|
|
5
5
|
Project-URL: Homepage, https://github.com/scaleapi/sgp-python-beta
|
|
6
6
|
Project-URL: Repository, https://github.com/scaleapi/sgp-python-beta
|
|
@@ -11,7 +11,7 @@ scale_gp_beta/_resource.py,sha256=siZly_U6D0AOVLAzaOsqUdEFFzVMbWRj-ml30nvRp7E,11
|
|
|
11
11
|
scale_gp_beta/_response.py,sha256=GemuybPk0uemovTlGHyHkj-ScYTTDJA0jqH5FQqIPwQ,28852
|
|
12
12
|
scale_gp_beta/_streaming.py,sha256=fcCSGXslmi2SmmkM05g2SACXHk2Mj7k1X5uMBu6U5s8,10112
|
|
13
13
|
scale_gp_beta/_types.py,sha256=0wSs40TefKMPBj2wQKenEeZ0lzedoHClNJeqrpAgkII,6204
|
|
14
|
-
scale_gp_beta/_version.py,sha256=
|
|
14
|
+
scale_gp_beta/_version.py,sha256=7E-g0q6eQvQbS2pu4ASnulYRwTSdV6WaybxYdb6Zhpg,174
|
|
15
15
|
scale_gp_beta/pagination.py,sha256=t-U86PYxl20VRsz8VXOMJJDe7HxkX7ISFMvRNbBNy9s,4054
|
|
16
16
|
scale_gp_beta/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
scale_gp_beta/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
|
|
@@ -28,11 +28,11 @@ scale_gp_beta/lib/.keep,sha256=wuNrz-5SXo3jJaJOJgz4vFHM41YH_g20F5cRQo0vLes,224
|
|
|
28
28
|
scale_gp_beta/lib/tracing/__init__.py,sha256=UgyExbqAA2ljDEF4X4YFhtbBZuoQJ2IF4hkGs_xQEc0,226
|
|
29
29
|
scale_gp_beta/lib/tracing/exceptions.py,sha256=vL2_GAfWEy8EfLhrBkDClLYTasOLnL-5zUpdCQnSzcs,107
|
|
30
30
|
scale_gp_beta/lib/tracing/scope.py,sha256=kHrd0his8L2K_KXn2E6J9d565PliEdFoKRQ1d5ALTyk,3901
|
|
31
|
-
scale_gp_beta/lib/tracing/span.py,sha256=
|
|
31
|
+
scale_gp_beta/lib/tracing/span.py,sha256=jmi1IYkPSAw_26bid7fCpiAWmyjW8XjaoonX70ydXPc,12448
|
|
32
32
|
scale_gp_beta/lib/tracing/trace.py,sha256=sdLUnvByLaMbV2TgI-MdKKs7If1-6GKz5j9A6scnDoI,6205
|
|
33
33
|
scale_gp_beta/lib/tracing/trace_exporter.py,sha256=bE6hS-Qu9KknEUTdsfIQMQwauah125mEavTDqEenBRA,3779
|
|
34
|
-
scale_gp_beta/lib/tracing/trace_queue_manager.py,sha256=
|
|
35
|
-
scale_gp_beta/lib/tracing/tracing.py,sha256=
|
|
34
|
+
scale_gp_beta/lib/tracing/trace_queue_manager.py,sha256=RnEDOKi7c1xlKXUsofShzZ8WrHldbhc0wyveMNgX8E4,6206
|
|
35
|
+
scale_gp_beta/lib/tracing/tracing.py,sha256=_j30MMy-w5Y33t2lAYSFVpMY_Ia2PFcEFaUEG5UN2OI,9368
|
|
36
36
|
scale_gp_beta/lib/tracing/types.py,sha256=fnU7XGiyfF3UEIx-iqyHRjNHlOV7s75tP0b5efvt2sk,1156
|
|
37
37
|
scale_gp_beta/lib/tracing/util.py,sha256=8Oq4wLXRNOzh3CC1zRaBEr0h_WdXLrk536BUNKRddVE,1527
|
|
38
38
|
scale_gp_beta/resources/__init__.py,sha256=Fyo05_2_pc5orfyTSIpxa3btmBTd45VasgibwSqbbKo,4942
|
|
@@ -117,7 +117,7 @@ scale_gp_beta/types/chat/completion_models_params.py,sha256=ETxafJIUx4tTvkiR-ZCr
|
|
|
117
117
|
scale_gp_beta/types/chat/completion_models_response.py,sha256=Ctgj6o-QWPSdjBKzG9J4Id0-DjXu4UGGw1NR6-840Ec,403
|
|
118
118
|
scale_gp_beta/types/chat/model_definition.py,sha256=NNgopTm900GD0Zs2YHkcvoW67uKaWUKVyPbhKBHvKdQ,817
|
|
119
119
|
scale_gp_beta/types/files/__init__.py,sha256=OKfJYcKb4NObdiRObqJV_dOyDQ8feXekDUge2o_4pXQ,122
|
|
120
|
-
scale_gp_beta-0.1.
|
|
121
|
-
scale_gp_beta-0.1.
|
|
122
|
-
scale_gp_beta-0.1.
|
|
123
|
-
scale_gp_beta-0.1.
|
|
120
|
+
scale_gp_beta-0.1.0a24.dist-info/METADATA,sha256=orXAxIkeUTgNuTWIfGt97BdKdhLi4NBJmg55IZ4cwEA,27611
|
|
121
|
+
scale_gp_beta-0.1.0a24.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
122
|
+
scale_gp_beta-0.1.0a24.dist-info/licenses/LICENSE,sha256=x49Bj8r_ZpqfzThbmfHyZ_bE88XvHdIMI_ANyLHFFRE,11338
|
|
123
|
+
scale_gp_beta-0.1.0a24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|