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.
Files changed (49) hide show
  1. kurrentdbclient/__init__.py +49 -0
  2. kurrentdbclient/asyncio_client.py +1662 -0
  3. kurrentdbclient/client.py +1914 -0
  4. kurrentdbclient/common.py +535 -0
  5. kurrentdbclient/connection.py +107 -0
  6. kurrentdbclient/connection_spec.py +371 -0
  7. kurrentdbclient/events.py +141 -0
  8. kurrentdbclient/exceptions.py +239 -0
  9. kurrentdbclient/gossip.py +104 -0
  10. kurrentdbclient/instrumentation/__init__.py +0 -0
  11. kurrentdbclient/instrumentation/opentelemetry/__init__.py +185 -0
  12. kurrentdbclient/instrumentation/opentelemetry/attributes.py +20 -0
  13. kurrentdbclient/instrumentation/opentelemetry/grpc.py +165 -0
  14. kurrentdbclient/instrumentation/opentelemetry/package.py +2 -0
  15. kurrentdbclient/instrumentation/opentelemetry/spanners.py +1097 -0
  16. kurrentdbclient/instrumentation/opentelemetry/utils.py +199 -0
  17. kurrentdbclient/instrumentation/opentelemetry/version.py +2 -0
  18. kurrentdbclient/persistent.py +1982 -0
  19. kurrentdbclient/projections.py +735 -0
  20. kurrentdbclient/protos/Grpc/cluster_pb2.py +92 -0
  21. kurrentdbclient/protos/Grpc/cluster_pb2.pyi +765 -0
  22. kurrentdbclient/protos/Grpc/cluster_pb2_grpc.py +514 -0
  23. kurrentdbclient/protos/Grpc/code_pb2.py +37 -0
  24. kurrentdbclient/protos/Grpc/code_pb2.pyi +357 -0
  25. kurrentdbclient/protos/Grpc/code_pb2_grpc.py +24 -0
  26. kurrentdbclient/protos/Grpc/gossip_pb2.py +46 -0
  27. kurrentdbclient/protos/Grpc/gossip_pb2.pyi +126 -0
  28. kurrentdbclient/protos/Grpc/gossip_pb2_grpc.py +98 -0
  29. kurrentdbclient/protos/Grpc/persistent_pb2.py +140 -0
  30. kurrentdbclient/protos/Grpc/persistent_pb2.pyi +1135 -0
  31. kurrentdbclient/protos/Grpc/persistent_pb2_grpc.py +399 -0
  32. kurrentdbclient/protos/Grpc/projections_pb2.py +99 -0
  33. kurrentdbclient/protos/Grpc/projections_pb2.pyi +558 -0
  34. kurrentdbclient/protos/Grpc/projections_pb2_grpc.py +485 -0
  35. kurrentdbclient/protos/Grpc/shared_pb2.py +62 -0
  36. kurrentdbclient/protos/Grpc/shared_pb2.pyi +218 -0
  37. kurrentdbclient/protos/Grpc/shared_pb2_grpc.py +24 -0
  38. kurrentdbclient/protos/Grpc/status_pb2.py +39 -0
  39. kurrentdbclient/protos/Grpc/status_pb2.pyi +67 -0
  40. kurrentdbclient/protos/Grpc/status_pb2_grpc.py +24 -0
  41. kurrentdbclient/protos/Grpc/streams_pb2.py +132 -0
  42. kurrentdbclient/protos/Grpc/streams_pb2.pyi +1038 -0
  43. kurrentdbclient/protos/Grpc/streams_pb2_grpc.py +269 -0
  44. kurrentdbclient/py.typed +0 -0
  45. kurrentdbclient/streams.py +1400 -0
  46. kurrentdbclient-0.3.dist-info/LICENSE +29 -0
  47. kurrentdbclient-0.3.dist-info/METADATA +3769 -0
  48. kurrentdbclient-0.3.dist-info/RECORD +49 -0
  49. 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