kurrentdbclient 0.3__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.
- kurrentdbclient/__init__.py +49 -0
- kurrentdbclient/asyncio_client.py +1662 -0
- kurrentdbclient/client.py +1914 -0
- kurrentdbclient/common.py +535 -0
- kurrentdbclient/connection.py +107 -0
- kurrentdbclient/connection_spec.py +371 -0
- kurrentdbclient/events.py +141 -0
- kurrentdbclient/exceptions.py +239 -0
- kurrentdbclient/gossip.py +104 -0
- kurrentdbclient/instrumentation/__init__.py +0 -0
- kurrentdbclient/instrumentation/opentelemetry/__init__.py +185 -0
- kurrentdbclient/instrumentation/opentelemetry/attributes.py +20 -0
- kurrentdbclient/instrumentation/opentelemetry/grpc.py +165 -0
- kurrentdbclient/instrumentation/opentelemetry/package.py +2 -0
- kurrentdbclient/instrumentation/opentelemetry/spanners.py +1097 -0
- kurrentdbclient/instrumentation/opentelemetry/utils.py +199 -0
- kurrentdbclient/instrumentation/opentelemetry/version.py +2 -0
- kurrentdbclient/persistent.py +1982 -0
- kurrentdbclient/projections.py +735 -0
- kurrentdbclient/protos/Grpc/cluster_pb2.py +92 -0
- kurrentdbclient/protos/Grpc/cluster_pb2.pyi +765 -0
- kurrentdbclient/protos/Grpc/cluster_pb2_grpc.py +514 -0
- kurrentdbclient/protos/Grpc/code_pb2.py +37 -0
- kurrentdbclient/protos/Grpc/code_pb2.pyi +357 -0
- kurrentdbclient/protos/Grpc/code_pb2_grpc.py +24 -0
- kurrentdbclient/protos/Grpc/gossip_pb2.py +46 -0
- kurrentdbclient/protos/Grpc/gossip_pb2.pyi +126 -0
- kurrentdbclient/protos/Grpc/gossip_pb2_grpc.py +98 -0
- kurrentdbclient/protos/Grpc/persistent_pb2.py +140 -0
- kurrentdbclient/protos/Grpc/persistent_pb2.pyi +1135 -0
- kurrentdbclient/protos/Grpc/persistent_pb2_grpc.py +399 -0
- kurrentdbclient/protos/Grpc/projections_pb2.py +99 -0
- kurrentdbclient/protos/Grpc/projections_pb2.pyi +558 -0
- kurrentdbclient/protos/Grpc/projections_pb2_grpc.py +485 -0
- kurrentdbclient/protos/Grpc/shared_pb2.py +62 -0
- kurrentdbclient/protos/Grpc/shared_pb2.pyi +218 -0
- kurrentdbclient/protos/Grpc/shared_pb2_grpc.py +24 -0
- kurrentdbclient/protos/Grpc/status_pb2.py +39 -0
- kurrentdbclient/protos/Grpc/status_pb2.pyi +67 -0
- kurrentdbclient/protos/Grpc/status_pb2_grpc.py +24 -0
- kurrentdbclient/protos/Grpc/streams_pb2.py +132 -0
- kurrentdbclient/protos/Grpc/streams_pb2.pyi +1038 -0
- kurrentdbclient/protos/Grpc/streams_pb2_grpc.py +269 -0
- kurrentdbclient/py.typed +0 -0
- kurrentdbclient/streams.py +1400 -0
- kurrentdbclient-0.3.dist-info/LICENSE +29 -0
- kurrentdbclient-0.3.dist-info/METADATA +3769 -0
- kurrentdbclient-0.3.dist-info/RECORD +49 -0
- kurrentdbclient-0.3.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import inspect
|
|
5
|
+
import re
|
|
6
|
+
import traceback
|
|
7
|
+
from contextlib import contextmanager
|
|
8
|
+
from typing import (
|
|
9
|
+
Any,
|
|
10
|
+
Callable,
|
|
11
|
+
Coroutine,
|
|
12
|
+
Iterator,
|
|
13
|
+
MutableMapping,
|
|
14
|
+
Optional,
|
|
15
|
+
Protocol,
|
|
16
|
+
Type,
|
|
17
|
+
TypeVar,
|
|
18
|
+
Union,
|
|
19
|
+
cast,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
import wrapt
|
|
23
|
+
from opentelemetry.context import Context
|
|
24
|
+
from opentelemetry.trace import Span, SpanKind, Status, StatusCode, Tracer
|
|
25
|
+
from opentelemetry.util.types import AttributeValue
|
|
26
|
+
from typing_extensions import Concatenate, ParamSpec
|
|
27
|
+
|
|
28
|
+
from kurrentdbclient.instrumentation.opentelemetry.attributes import Attributes
|
|
29
|
+
|
|
30
|
+
# Define type variables and type aliases for spanner functions.
|
|
31
|
+
T = TypeVar("T")
|
|
32
|
+
P = ParamSpec("P")
|
|
33
|
+
R = TypeVar("R")
|
|
34
|
+
BoundFunc = Callable[P, R]
|
|
35
|
+
SpannerResponse = Iterator[R]
|
|
36
|
+
SpannerFunc = Callable[Concatenate[Tracer, T, BoundFunc[P, R], P], SpannerResponse[R]]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Define function type for wrapt-style wrapper functions.
|
|
40
|
+
T_contra = TypeVar("T_contra", contravariant=True)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class WraptWrapperFunc(Protocol[T_contra, P, R]):
|
|
44
|
+
def __call__(
|
|
45
|
+
self,
|
|
46
|
+
original: BoundFunc[P, R],
|
|
47
|
+
instance: T_contra,
|
|
48
|
+
args: P.args,
|
|
49
|
+
kwargs: P.kwargs,
|
|
50
|
+
) -> R:
|
|
51
|
+
pass # pragma: no cover
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Define type alias for unbound object class methods.
|
|
55
|
+
UnboundFunc = Callable[Concatenate[T, P], R]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Define type-safe function to apply an instrumenting
|
|
59
|
+
# spanner function to the method of an object class.
|
|
60
|
+
def apply_spanner(
|
|
61
|
+
patched_class: Type[T],
|
|
62
|
+
spanned_func: UnboundFunc[T, P, R],
|
|
63
|
+
spanner_func: SpannerFunc[T, P, R],
|
|
64
|
+
tracer: Tracer,
|
|
65
|
+
) -> UnboundFunc[T, P, R]:
|
|
66
|
+
|
|
67
|
+
if inspect.iscoroutinefunction(spanned_func):
|
|
68
|
+
|
|
69
|
+
# Make a context manager for the spanner function.
|
|
70
|
+
async_spanner_func = cast(
|
|
71
|
+
SpannerFunc[T, P, Coroutine[Any, Any, R]], spanner_func
|
|
72
|
+
)
|
|
73
|
+
async_spanner = contextmanager(async_spanner_func)
|
|
74
|
+
|
|
75
|
+
# Define wrapt-style instrumentation wrapper.
|
|
76
|
+
async def async_instrumentation_wrapper(
|
|
77
|
+
original: BoundFunc[P, Coroutine[Any, Any, R]],
|
|
78
|
+
instance: T,
|
|
79
|
+
args: P.kwargs,
|
|
80
|
+
kwargs: P.args,
|
|
81
|
+
) -> R:
|
|
82
|
+
# Use the spanner function to execute the spanned function.
|
|
83
|
+
with async_spanner(tracer, instance, original, *args, **kwargs) as result:
|
|
84
|
+
return await result
|
|
85
|
+
|
|
86
|
+
# Replace spanned function with instrumentation wrapper.
|
|
87
|
+
async_spanned_func = cast(
|
|
88
|
+
UnboundFunc[T, P, Coroutine[Any, Any, R]], spanned_func
|
|
89
|
+
)
|
|
90
|
+
_patch_class(patched_class, async_spanned_func, async_instrumentation_wrapper)
|
|
91
|
+
|
|
92
|
+
else:
|
|
93
|
+
|
|
94
|
+
# Make a context manager for the spanner function.
|
|
95
|
+
spanner = contextmanager(spanner_func)
|
|
96
|
+
|
|
97
|
+
# Define wrapt-style instrumentation wrapper.
|
|
98
|
+
def instrumentation_wrapper(
|
|
99
|
+
original: BoundFunc[P, R],
|
|
100
|
+
instance: T,
|
|
101
|
+
args: P.args,
|
|
102
|
+
kwargs: P.kwargs,
|
|
103
|
+
) -> R:
|
|
104
|
+
# Use the spanner function to execute the spanned function.
|
|
105
|
+
with spanner(tracer, instance, original, *args, **kwargs) as result:
|
|
106
|
+
return result
|
|
107
|
+
|
|
108
|
+
# Replace spanned function with instrumentation wrapper.
|
|
109
|
+
_patch_class(patched_class, spanned_func, instrumentation_wrapper)
|
|
110
|
+
|
|
111
|
+
# Satisfy the return type (which brings together the typing for mypy).
|
|
112
|
+
return spanned_func
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _patch_class(
|
|
116
|
+
patched_class: Type[T],
|
|
117
|
+
spanned_func: UnboundFunc[T, P, R],
|
|
118
|
+
instrumentation_wrapper_func: WraptWrapperFunc[T, P, R],
|
|
119
|
+
) -> UnboundFunc[T, P, R]:
|
|
120
|
+
|
|
121
|
+
# Wrap spanned function with instrumentation wrapper function.
|
|
122
|
+
wrapt.wrap_function_wrapper(
|
|
123
|
+
patched_class,
|
|
124
|
+
spanned_func.__name__,
|
|
125
|
+
instrumentation_wrapper_func,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Satisfy the return type (which brings together the typing for mypy).
|
|
129
|
+
return spanned_func
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# Define type variables for overloaded spanner functions.
|
|
133
|
+
AsyncSpannerResponse = SpannerResponse[Coroutine[Any, Any, R]]
|
|
134
|
+
S = TypeVar("S")
|
|
135
|
+
OverloadedSpannerResponse = Union[SpannerResponse[R], AsyncSpannerResponse[S]]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@contextmanager
|
|
139
|
+
def _start_span(
|
|
140
|
+
tracer: Tracer,
|
|
141
|
+
span_name: str,
|
|
142
|
+
span_kind: SpanKind = SpanKind.CLIENT,
|
|
143
|
+
context: Optional[Context] = None,
|
|
144
|
+
end_on_exit: bool = True,
|
|
145
|
+
) -> Iterator[Span]:
|
|
146
|
+
with tracer.start_as_current_span(
|
|
147
|
+
name=span_name,
|
|
148
|
+
kind=span_kind,
|
|
149
|
+
record_exception=False,
|
|
150
|
+
set_status_on_exception=False,
|
|
151
|
+
context=context,
|
|
152
|
+
end_on_exit=end_on_exit,
|
|
153
|
+
) as span:
|
|
154
|
+
yield span
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _set_span_ok(span: Span) -> None:
|
|
158
|
+
span.set_status(StatusCode.OK)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _set_span_error(span: Span, error: Exception) -> None:
|
|
162
|
+
# Set span status.
|
|
163
|
+
exc_type = type(error)
|
|
164
|
+
span.set_status(
|
|
165
|
+
Status(
|
|
166
|
+
status_code=StatusCode.ERROR,
|
|
167
|
+
description=f"{exc_type.__name__}: {error}",
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
# Log an event for the error.
|
|
171
|
+
exception_type = (
|
|
172
|
+
f"{exc_type.__module__}.{exc_type.__qualname__}"
|
|
173
|
+
if exc_type.__module__ and exc_type.__module__ != "builtins"
|
|
174
|
+
else exc_type.__qualname__
|
|
175
|
+
)
|
|
176
|
+
exception_message = str(error)
|
|
177
|
+
stack = ["Traceback (most recent call last):\n"]
|
|
178
|
+
# stack += traceback.format_stack()
|
|
179
|
+
stack += traceback.format_exception(exc_type, error, error.__traceback__)[1:]
|
|
180
|
+
exception_stacktrace = "".join([line for line in stack if _stack_include(line)])
|
|
181
|
+
exception_escaped = str(True)
|
|
182
|
+
# Gather attributes.
|
|
183
|
+
attributes: MutableMapping[str, AttributeValue] = {
|
|
184
|
+
Attributes.EXCEPTION_TYPE: exception_type,
|
|
185
|
+
Attributes.EXCEPTION_MESSAGE: exception_message,
|
|
186
|
+
Attributes.EXCEPTION_STACKTRACE: exception_stacktrace,
|
|
187
|
+
Attributes.EXCEPTION_ESCAPED: exception_escaped,
|
|
188
|
+
}
|
|
189
|
+
span.add_event(name="exception", attributes=attributes, timestamp=None)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
_stack_exclude_patterns = [
|
|
193
|
+
"opentelemetry",
|
|
194
|
+
]
|
|
195
|
+
_stack_exclude_regex = re.compile(".*(" + "|".join(_stack_exclude_patterns) + ").*")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _stack_include(line: str) -> bool:
|
|
199
|
+
return _stack_exclude_regex.match(line) is None
|