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,239 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Dict, Optional, Union
|
|
3
|
+
|
|
4
|
+
import grpc
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class KurrentDBClientException(Exception):
|
|
8
|
+
"""
|
|
9
|
+
Base class for exceptions raised by the client.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ProgrammingError(Exception):
|
|
14
|
+
"""
|
|
15
|
+
Raised when programming errors are encountered.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class GrpcError(KurrentDBClientException):
|
|
20
|
+
"""
|
|
21
|
+
Base class for exceptions raised by gRPC.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ExceptionThrownByHandler(GrpcError):
|
|
26
|
+
"""
|
|
27
|
+
Raised when gRPC service returns RpcError with status
|
|
28
|
+
code "UNKNOWN" and details "Exception was thrown by handler.".
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ServiceUnavailable(GrpcError):
|
|
33
|
+
"""
|
|
34
|
+
Raised when gRPC service is unavailable.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class SSLError(ServiceUnavailable):
|
|
39
|
+
"""
|
|
40
|
+
Raised when gRPC service is unavailable due to SSL error.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class DeadlineExceeded(KurrentDBClientException):
|
|
45
|
+
"""
|
|
46
|
+
Base class for exceptions involving deadlines being exceeded.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class GrpcDeadlineExceeded(GrpcError, DeadlineExceeded):
|
|
51
|
+
"""
|
|
52
|
+
Raised when gRPC operation times out.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class CancelledByClient(KurrentDBClientException):
|
|
57
|
+
"""
|
|
58
|
+
Raised when gRPC operation is cancelled.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class AbortedByServer(GrpcError):
|
|
63
|
+
"""
|
|
64
|
+
Raised when gRPC operation is aborted.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ConsumerTooSlow(AbortedByServer):
|
|
69
|
+
"""
|
|
70
|
+
Raised when buffer is overloaded.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class NodeIsNotLeader(KurrentDBClientException):
|
|
75
|
+
"""
|
|
76
|
+
Raised when client attempts to write to a node that is not a leader.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def leader_grpc_target(self) -> Optional[str]:
|
|
81
|
+
if (
|
|
82
|
+
self.args
|
|
83
|
+
and isinstance(self.args[0], (grpc.Call, grpc.aio.AioRpcError))
|
|
84
|
+
and self.args[0].code() == grpc.StatusCode.NOT_FOUND
|
|
85
|
+
and self.args[0].details() == "Leader info available"
|
|
86
|
+
):
|
|
87
|
+
# The typing of trailing_metadata is a mess.
|
|
88
|
+
rpc_error = self.args[0]
|
|
89
|
+
trailing_metadata: Dict[str, Union[str, bytes]]
|
|
90
|
+
if isinstance(rpc_error, grpc.Call):
|
|
91
|
+
trailing_metadata = {
|
|
92
|
+
m.key: m.value for m in rpc_error.trailing_metadata() # type: ignore[attr-defined]
|
|
93
|
+
}
|
|
94
|
+
else:
|
|
95
|
+
assert isinstance(rpc_error, grpc.aio.AioRpcError)
|
|
96
|
+
trailing_metadata = rpc_error.trailing_metadata() # type: ignore[assignment]
|
|
97
|
+
|
|
98
|
+
host = trailing_metadata["leader-endpoint-host"]
|
|
99
|
+
port = trailing_metadata["leader-endpoint-port"]
|
|
100
|
+
if isinstance(host, bytes):
|
|
101
|
+
host = host.decode("utf-8") # pragma: no cover
|
|
102
|
+
if isinstance(port, bytes):
|
|
103
|
+
port = port.decode("utf-8") # pragma: no cover
|
|
104
|
+
return f"{host}:{port}"
|
|
105
|
+
else:
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class NotFound(KurrentDBClientException):
|
|
110
|
+
"""
|
|
111
|
+
Raised when stream or subscription or projection is not found.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class AlreadyExists(KurrentDBClientException):
|
|
116
|
+
"""
|
|
117
|
+
Raised when creating something, e.g. a persistent subscription, that already exists.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class SubscriptionConfirmationError(KurrentDBClientException):
|
|
122
|
+
"""
|
|
123
|
+
Raised when subscription confirmation fails.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class WrongCurrentVersion(KurrentDBClientException):
|
|
128
|
+
"""
|
|
129
|
+
Raised when expected position does not match the
|
|
130
|
+
stream position of the last event in a stream.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
WrongExpectedVersion = WrongCurrentVersion
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class AccessDeniedError(KurrentDBClientException):
|
|
138
|
+
"""
|
|
139
|
+
Raised when access is denied by the server.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class StreamIsDeleted(KurrentDBClientException):
|
|
144
|
+
"""
|
|
145
|
+
Raised when reading from or appending to a stream that has been
|
|
146
|
+
tombstoned, and when deleting a stream that has been deleted
|
|
147
|
+
whilst expecting the stream exists, and when getting or setting
|
|
148
|
+
metadata for a stream that has been tombstoned, and when deleting
|
|
149
|
+
a stream that has been tombstoned, and when tombstoning a stream
|
|
150
|
+
that has been tombstoned.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class AppendDeadlineExceeded(DeadlineExceeded):
|
|
155
|
+
"""
|
|
156
|
+
Raised when append operation is timed out by the server.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class UnknownError(KurrentDBClientException):
|
|
161
|
+
"""
|
|
162
|
+
Raised when append operation fails with an "unknown" error.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class InvalidTransactionError(KurrentDBClientException):
|
|
167
|
+
"""
|
|
168
|
+
Raised when append operation fails with an "invalid transaction" error.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class OperationFailed(GrpcError):
|
|
173
|
+
"""
|
|
174
|
+
Raised when an operation fails (e.g. deleting a projection that isn't disabled).
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class MaximumAppendSizeExceededError(KurrentDBClientException):
|
|
179
|
+
"""
|
|
180
|
+
Raised when append operation fails with a "maximum append size exceeded" error.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class BadRequestError(KurrentDBClientException):
|
|
185
|
+
"""
|
|
186
|
+
Raised when append operation fails with a "bad request" error.
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class DiscoveryFailed(KurrentDBClientException):
|
|
191
|
+
"""
|
|
192
|
+
Raised when client fails to satisfy node preference using gossip cluster info.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class LeaderNotFound(DiscoveryFailed):
|
|
197
|
+
"""
|
|
198
|
+
Raised when NodePreference is 'follower' but the cluster has no such nodes.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class FollowerNotFound(DiscoveryFailed):
|
|
203
|
+
"""
|
|
204
|
+
Raised when NodePreference is 'follower' but the cluster has no such nodes.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class ReadOnlyReplicaNotFound(DiscoveryFailed):
|
|
209
|
+
"""
|
|
210
|
+
Raised when NodePreference is 'readonlyreplica' but the cluster has no such nodes.
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class ExceptionIteratingRequests(KurrentDBClientException):
|
|
215
|
+
"""
|
|
216
|
+
Raised when a persistent subscription errors whilst iterating requests.
|
|
217
|
+
|
|
218
|
+
This helps debugging because otherwise we just get a gRPC error
|
|
219
|
+
that says "Exception iterating requests!"
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class FailedPrecondition(KurrentDBClientException):
|
|
224
|
+
"""
|
|
225
|
+
Raised when a "failed precondition" status error is encountered.
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class MaximumSubscriptionsReached(FailedPrecondition):
|
|
230
|
+
"""
|
|
231
|
+
Raised when trying to read from a persistent subscription that
|
|
232
|
+
is already being read by the maximum number of subscribers.
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class InternalError(GrpcError):
|
|
237
|
+
"""
|
|
238
|
+
Raised when a grpc INTERNAL error is encountered.
|
|
239
|
+
"""
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Optional, Sequence, Union
|
|
4
|
+
|
|
5
|
+
import grpc
|
|
6
|
+
import grpc.aio
|
|
7
|
+
|
|
8
|
+
from kurrentdbclient.common import (
|
|
9
|
+
AsyncGrpcStreamers,
|
|
10
|
+
GrpcStreamers,
|
|
11
|
+
KurrentDBService,
|
|
12
|
+
Metadata,
|
|
13
|
+
TGrpcStreamers,
|
|
14
|
+
handle_rpc_error,
|
|
15
|
+
)
|
|
16
|
+
from kurrentdbclient.connection_spec import ConnectionSpec
|
|
17
|
+
from kurrentdbclient.protos.Grpc import gossip_pb2, gossip_pb2_grpc, shared_pb2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ClusterMember:
|
|
22
|
+
state: str
|
|
23
|
+
address: str
|
|
24
|
+
port: int
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
NODE_STATE_LEADER = "NODE_STATE_LEADER"
|
|
28
|
+
NODE_STATE_FOLLOWER = "NODE_STATE_FOLLOWER"
|
|
29
|
+
NODE_STATE_REPLICA = "NODE_STATE_REPLICA"
|
|
30
|
+
NODE_STATE_OTHER = "NODE_STATE_OTHER"
|
|
31
|
+
GOSSIP_API_NODE_STATES_MAPPING = {
|
|
32
|
+
gossip_pb2.MemberInfo.VNodeState.Follower: NODE_STATE_FOLLOWER,
|
|
33
|
+
gossip_pb2.MemberInfo.VNodeState.Leader: NODE_STATE_LEADER,
|
|
34
|
+
gossip_pb2.MemberInfo.VNodeState.ReadOnlyReplica: NODE_STATE_REPLICA,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BaseGossipService(KurrentDBService[TGrpcStreamers]):
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
channel: Union[grpc.Channel, grpc.aio.Channel],
|
|
42
|
+
connection_spec: ConnectionSpec,
|
|
43
|
+
grpc_streamers: TGrpcStreamers,
|
|
44
|
+
):
|
|
45
|
+
super().__init__(connection_spec=connection_spec, grpc_streamers=grpc_streamers)
|
|
46
|
+
self._stub = gossip_pb2_grpc.GossipStub(channel) # type: ignore[no-untyped-call]
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _construct_cluster_members(
|
|
50
|
+
cluster_info: gossip_pb2.ClusterInfo,
|
|
51
|
+
) -> Sequence[ClusterMember]:
|
|
52
|
+
members = []
|
|
53
|
+
for member_info in cluster_info.members:
|
|
54
|
+
member = ClusterMember(
|
|
55
|
+
GOSSIP_API_NODE_STATES_MAPPING.get(member_info.state, NODE_STATE_OTHER),
|
|
56
|
+
member_info.http_end_point.address,
|
|
57
|
+
member_info.http_end_point.port,
|
|
58
|
+
)
|
|
59
|
+
members.append(member)
|
|
60
|
+
return tuple(members)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class AsyncGossipService(BaseGossipService[AsyncGrpcStreamers]):
|
|
64
|
+
async def read(
|
|
65
|
+
self,
|
|
66
|
+
timeout: Optional[float] = None,
|
|
67
|
+
metadata: Optional[Metadata] = None,
|
|
68
|
+
credentials: Optional[grpc.CallCredentials] = None,
|
|
69
|
+
) -> Sequence[ClusterMember]:
|
|
70
|
+
try:
|
|
71
|
+
read_resp = await self._stub.Read(
|
|
72
|
+
shared_pb2.Empty(),
|
|
73
|
+
timeout=timeout,
|
|
74
|
+
metadata=self._metadata(metadata),
|
|
75
|
+
credentials=credentials,
|
|
76
|
+
)
|
|
77
|
+
except grpc.RpcError as e:
|
|
78
|
+
raise handle_rpc_error(e) from None
|
|
79
|
+
|
|
80
|
+
return self._construct_cluster_members(read_resp)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class GossipService(BaseGossipService[GrpcStreamers]):
|
|
84
|
+
"""
|
|
85
|
+
Encapsulates the 'gossip.Gossip' gRPC service.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def read(
|
|
89
|
+
self,
|
|
90
|
+
timeout: Optional[float] = None,
|
|
91
|
+
metadata: Optional[Metadata] = None,
|
|
92
|
+
credentials: Optional[grpc.CallCredentials] = None,
|
|
93
|
+
) -> Sequence[ClusterMember]:
|
|
94
|
+
try:
|
|
95
|
+
read_resp = self._stub.Read(
|
|
96
|
+
shared_pb2.Empty(),
|
|
97
|
+
timeout=timeout,
|
|
98
|
+
metadata=self._metadata(metadata),
|
|
99
|
+
credentials=credentials,
|
|
100
|
+
)
|
|
101
|
+
except grpc.RpcError as e:
|
|
102
|
+
raise handle_rpc_error(e) from None
|
|
103
|
+
|
|
104
|
+
return self._construct_cluster_members(read_resp)
|
|
File without changes
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any, Collection
|
|
5
|
+
|
|
6
|
+
# Note: namespace pacakge issue? don't understand why this and not e.g. utils.unwrap
|
|
7
|
+
from opentelemetry.instrumentation.instrumentor import ( # type: ignore[attr-defined]
|
|
8
|
+
BaseInstrumentor,
|
|
9
|
+
)
|
|
10
|
+
from opentelemetry.instrumentation.utils import unwrap
|
|
11
|
+
from opentelemetry.semconv.schemas import Schemas
|
|
12
|
+
from opentelemetry.trace import Tracer, get_tracer
|
|
13
|
+
|
|
14
|
+
from kurrentdbclient import AsyncKurrentDBClient, KurrentDBClient
|
|
15
|
+
from kurrentdbclient.instrumentation.opentelemetry.grpc import (
|
|
16
|
+
try_unwrap_opentelemetry_intercept_grpc_server_stream,
|
|
17
|
+
try_wrap_opentelemetry_intercept_grpc_server_stream,
|
|
18
|
+
)
|
|
19
|
+
from kurrentdbclient.instrumentation.opentelemetry.package import _instruments
|
|
20
|
+
from kurrentdbclient.instrumentation.opentelemetry.spanners import (
|
|
21
|
+
span_append_to_stream,
|
|
22
|
+
span_catchup_subscription,
|
|
23
|
+
span_get_stream,
|
|
24
|
+
span_persistent_subscription,
|
|
25
|
+
span_read_stream,
|
|
26
|
+
)
|
|
27
|
+
from kurrentdbclient.instrumentation.opentelemetry.utils import apply_spanner
|
|
28
|
+
from kurrentdbclient.instrumentation.opentelemetry.version import __version__
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class _RedefinedBaseInstrumentor(BaseInstrumentor): # type: ignore[misc]
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _BaseInstrumentor(_RedefinedBaseInstrumentor):
|
|
36
|
+
instrument_get_and_read_stream = False
|
|
37
|
+
|
|
38
|
+
def instrumentation_dependencies(self) -> Collection[str]:
|
|
39
|
+
return _instruments
|
|
40
|
+
|
|
41
|
+
def _instrument(self, **kwargs: Any) -> None:
|
|
42
|
+
instrument_get_and_read_stream = bool(
|
|
43
|
+
kwargs.get("instrument_get_and_read_stream")
|
|
44
|
+
)
|
|
45
|
+
self.instrument_get_and_read_stream = instrument_get_and_read_stream
|
|
46
|
+
|
|
47
|
+
def _get_tracer(self, **kwargs: Any) -> Tracer:
|
|
48
|
+
tracer_provider = kwargs.get("tracer_provider")
|
|
49
|
+
tracer = get_tracer(
|
|
50
|
+
__name__,
|
|
51
|
+
__version__,
|
|
52
|
+
tracer_provider=tracer_provider,
|
|
53
|
+
schema_url=Schemas.V1_25_0.value,
|
|
54
|
+
)
|
|
55
|
+
return tracer
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class KurrentDBClientInstrumentor(_BaseInstrumentor):
|
|
59
|
+
def _instrument(self, **kwargs: Any) -> None:
|
|
60
|
+
super()._instrument(**kwargs)
|
|
61
|
+
|
|
62
|
+
tracer = self._get_tracer(**kwargs)
|
|
63
|
+
|
|
64
|
+
apply_spanner(
|
|
65
|
+
patched_class=KurrentDBClient,
|
|
66
|
+
spanned_func=KurrentDBClient.append_to_stream,
|
|
67
|
+
spanner_func=span_append_to_stream,
|
|
68
|
+
tracer=tracer,
|
|
69
|
+
)
|
|
70
|
+
apply_spanner(
|
|
71
|
+
patched_class=KurrentDBClient,
|
|
72
|
+
spanned_func=KurrentDBClient.subscribe_to_stream,
|
|
73
|
+
spanner_func=span_catchup_subscription,
|
|
74
|
+
tracer=tracer,
|
|
75
|
+
)
|
|
76
|
+
apply_spanner(
|
|
77
|
+
patched_class=KurrentDBClient,
|
|
78
|
+
spanned_func=KurrentDBClient.subscribe_to_all,
|
|
79
|
+
spanner_func=span_catchup_subscription,
|
|
80
|
+
tracer=tracer,
|
|
81
|
+
)
|
|
82
|
+
apply_spanner(
|
|
83
|
+
patched_class=KurrentDBClient,
|
|
84
|
+
spanned_func=KurrentDBClient.read_subscription_to_stream,
|
|
85
|
+
spanner_func=span_persistent_subscription,
|
|
86
|
+
tracer=tracer,
|
|
87
|
+
)
|
|
88
|
+
apply_spanner(
|
|
89
|
+
patched_class=KurrentDBClient,
|
|
90
|
+
spanned_func=KurrentDBClient.read_subscription_to_all,
|
|
91
|
+
spanner_func=span_persistent_subscription,
|
|
92
|
+
tracer=tracer,
|
|
93
|
+
)
|
|
94
|
+
if self.instrument_get_and_read_stream:
|
|
95
|
+
apply_spanner(
|
|
96
|
+
patched_class=KurrentDBClient,
|
|
97
|
+
spanned_func=KurrentDBClient.read_stream,
|
|
98
|
+
spanner_func=span_read_stream,
|
|
99
|
+
tracer=tracer,
|
|
100
|
+
)
|
|
101
|
+
apply_spanner(
|
|
102
|
+
patched_class=KurrentDBClient,
|
|
103
|
+
spanned_func=KurrentDBClient.get_stream,
|
|
104
|
+
spanner_func=span_get_stream,
|
|
105
|
+
tracer=tracer,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Because its server streaming wrapper doesn't return an
|
|
109
|
+
# object with a cancel() method, so we can't stop them.
|
|
110
|
+
try_wrap_opentelemetry_intercept_grpc_server_stream()
|
|
111
|
+
|
|
112
|
+
def _uninstrument(self, **kwargs: Any) -> None:
|
|
113
|
+
unwrap(KurrentDBClient, "append_to_stream")
|
|
114
|
+
unwrap(KurrentDBClient, "subscribe_to_stream")
|
|
115
|
+
unwrap(KurrentDBClient, "subscribe_to_all")
|
|
116
|
+
unwrap(KurrentDBClient, "read_subscription_to_stream")
|
|
117
|
+
unwrap(KurrentDBClient, "read_subscription_to_all")
|
|
118
|
+
|
|
119
|
+
if self.instrument_get_and_read_stream:
|
|
120
|
+
unwrap(KurrentDBClient, "get_stream")
|
|
121
|
+
unwrap(KurrentDBClient, "read_stream")
|
|
122
|
+
|
|
123
|
+
try_unwrap_opentelemetry_intercept_grpc_server_stream()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class AsyncKurrentDBClientInstrumentor(_BaseInstrumentor):
|
|
127
|
+
def _instrument(self, **kwargs: Any) -> None:
|
|
128
|
+
super()._instrument(**kwargs)
|
|
129
|
+
|
|
130
|
+
tracer = self._get_tracer(**kwargs)
|
|
131
|
+
|
|
132
|
+
apply_spanner(
|
|
133
|
+
patched_class=AsyncKurrentDBClient,
|
|
134
|
+
spanned_func=AsyncKurrentDBClient.append_to_stream,
|
|
135
|
+
spanner_func=span_append_to_stream,
|
|
136
|
+
tracer=tracer,
|
|
137
|
+
)
|
|
138
|
+
apply_spanner(
|
|
139
|
+
patched_class=AsyncKurrentDBClient,
|
|
140
|
+
spanned_func=AsyncKurrentDBClient.subscribe_to_stream,
|
|
141
|
+
spanner_func=span_catchup_subscription,
|
|
142
|
+
tracer=tracer,
|
|
143
|
+
)
|
|
144
|
+
apply_spanner(
|
|
145
|
+
patched_class=AsyncKurrentDBClient,
|
|
146
|
+
spanned_func=AsyncKurrentDBClient.subscribe_to_all,
|
|
147
|
+
spanner_func=span_catchup_subscription,
|
|
148
|
+
tracer=tracer,
|
|
149
|
+
)
|
|
150
|
+
apply_spanner(
|
|
151
|
+
patched_class=AsyncKurrentDBClient,
|
|
152
|
+
spanned_func=AsyncKurrentDBClient.read_subscription_to_stream,
|
|
153
|
+
spanner_func=span_persistent_subscription,
|
|
154
|
+
tracer=tracer,
|
|
155
|
+
)
|
|
156
|
+
apply_spanner(
|
|
157
|
+
patched_class=AsyncKurrentDBClient,
|
|
158
|
+
spanned_func=AsyncKurrentDBClient.read_subscription_to_all,
|
|
159
|
+
spanner_func=span_persistent_subscription,
|
|
160
|
+
tracer=tracer,
|
|
161
|
+
)
|
|
162
|
+
if self.instrument_get_and_read_stream:
|
|
163
|
+
apply_spanner(
|
|
164
|
+
patched_class=AsyncKurrentDBClient,
|
|
165
|
+
spanned_func=AsyncKurrentDBClient.read_stream,
|
|
166
|
+
spanner_func=span_read_stream,
|
|
167
|
+
tracer=tracer,
|
|
168
|
+
)
|
|
169
|
+
apply_spanner(
|
|
170
|
+
patched_class=AsyncKurrentDBClient,
|
|
171
|
+
spanned_func=AsyncKurrentDBClient.get_stream,
|
|
172
|
+
spanner_func=span_get_stream,
|
|
173
|
+
tracer=tracer,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def _uninstrument(self, **kwargs: Any) -> None:
|
|
177
|
+
unwrap(AsyncKurrentDBClient, "append_to_stream")
|
|
178
|
+
unwrap(AsyncKurrentDBClient, "subscribe_to_stream")
|
|
179
|
+
unwrap(AsyncKurrentDBClient, "subscribe_to_all")
|
|
180
|
+
unwrap(AsyncKurrentDBClient, "read_subscription_to_stream")
|
|
181
|
+
unwrap(AsyncKurrentDBClient, "read_subscription_to_all")
|
|
182
|
+
|
|
183
|
+
if self.instrument_get_and_read_stream:
|
|
184
|
+
unwrap(AsyncKurrentDBClient, "get_stream")
|
|
185
|
+
unwrap(AsyncKurrentDBClient, "read_stream")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from opentelemetry.semconv._incubating.attributes import db_attributes
|
|
4
|
+
from opentelemetry.semconv.attributes import exception_attributes, server_attributes
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Attributes:
|
|
8
|
+
DB_OPERATION = db_attributes.DB_OPERATION
|
|
9
|
+
DB_SYSTEM = db_attributes.DB_SYSTEM
|
|
10
|
+
DB_USER = db_attributes.DB_USER
|
|
11
|
+
EVENTSTOREDB_STREAM = "db.kurrentdb.stream"
|
|
12
|
+
EVENTSTOREDB_SUBSCRIPTION_ID = "db.kurrentdb.subscription.id"
|
|
13
|
+
EVENTSTOREDB_EVENT_ID = "db.kurrentdb.event.id"
|
|
14
|
+
EVENTSTOREDB_EVENT_TYPE = "db.kurrentdb.event.type"
|
|
15
|
+
EXCEPTION_ESCAPED = exception_attributes.EXCEPTION_ESCAPED
|
|
16
|
+
EXCEPTION_MESSAGE = exception_attributes.EXCEPTION_MESSAGE
|
|
17
|
+
EXCEPTION_STACKTRACE = exception_attributes.EXCEPTION_STACKTRACE
|
|
18
|
+
EXCEPTION_TYPE = exception_attributes.EXCEPTION_TYPE
|
|
19
|
+
SERVER_ADDRESS = server_attributes.SERVER_ADDRESS
|
|
20
|
+
SERVER_PORT = server_attributes.SERVER_PORT
|