python-etcd3-async 0.1.0__py3-none-any.whl → 0.1.2__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.
- etcd3/async_client_extensions.py +52 -31
- etcd3/exceptions.py +2 -0
- etcd3/locks.py +33 -25
- etcd3/trace_attributes.py +91 -103
- etcd3/utils.py +4 -3
- etcdrpc/__init__.py +2 -1
- {python_etcd3_async-0.1.0.dist-info → python_etcd3_async-0.1.2.dist-info}/METADATA +46 -7
- {python_etcd3_async-0.1.0.dist-info → python_etcd3_async-0.1.2.dist-info}/RECORD +9 -9
- {python_etcd3_async-0.1.0.dist-info → python_etcd3_async-0.1.2.dist-info}/WHEEL +1 -1
etcd3/async_client_extensions.py
CHANGED
|
@@ -67,32 +67,32 @@ def _manage_client_errors(self, exc):
|
|
|
67
67
|
|
|
68
68
|
def _set_span_attributes_from_response(response, endpoint: str = None):
|
|
69
69
|
"""Set span attributes from etcd response.
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
:param response: etcd response object
|
|
72
72
|
:param endpoint: Optional endpoint string
|
|
73
73
|
"""
|
|
74
74
|
if not is_tracing_available():
|
|
75
75
|
return
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
span = get_current_span()
|
|
78
78
|
if span is None:
|
|
79
79
|
return
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
# Build attributes from response
|
|
82
|
-
attrs = build_response_attributes(header=getattr(response,
|
|
83
|
-
|
|
82
|
+
attrs = build_response_attributes(header=getattr(response, "header", None))
|
|
83
|
+
|
|
84
84
|
# Add count if available
|
|
85
|
-
if hasattr(response,
|
|
85
|
+
if hasattr(response, "count"):
|
|
86
86
|
attrs[TraceAttributes.ETCD_COUNT] = response.count
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
# Add deleted if available
|
|
89
|
-
if hasattr(response,
|
|
89
|
+
if hasattr(response, "deleted"):
|
|
90
90
|
attrs[TraceAttributes.ETCD_DELETED] = response.deleted
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
# Add endpoint if provided
|
|
93
93
|
if endpoint:
|
|
94
94
|
attrs[TraceAttributes.ETCD_ENDPOINT] = endpoint
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
# Set attributes on span
|
|
97
97
|
for key, value in attrs.items():
|
|
98
98
|
if value is not None:
|
|
@@ -147,11 +147,13 @@ class AsyncKVOperations:
|
|
|
147
147
|
credentials=self.client.call_credentials,
|
|
148
148
|
metadata=self.client.metadata,
|
|
149
149
|
)
|
|
150
|
-
|
|
150
|
+
|
|
151
151
|
# Set trace attributes from response
|
|
152
|
-
endpoint =
|
|
152
|
+
endpoint = (
|
|
153
|
+
str(self.client.endpoint_in_use) if self.client.endpoint_in_use else None
|
|
154
|
+
)
|
|
153
155
|
_set_span_attributes_from_response(response, endpoint)
|
|
154
|
-
|
|
156
|
+
|
|
155
157
|
return response
|
|
156
158
|
|
|
157
159
|
async def get(self, key, **kwargs):
|
|
@@ -259,9 +261,11 @@ class AsyncKVOperations:
|
|
|
259
261
|
credentials=self.client.call_credentials,
|
|
260
262
|
metadata=self.client.metadata,
|
|
261
263
|
)
|
|
262
|
-
|
|
264
|
+
|
|
263
265
|
# Set trace attributes from response
|
|
264
|
-
endpoint =
|
|
266
|
+
endpoint = (
|
|
267
|
+
str(self.client.endpoint_in_use) if self.client.endpoint_in_use else None
|
|
268
|
+
)
|
|
265
269
|
_set_span_attributes_from_response(put_response, endpoint)
|
|
266
270
|
|
|
267
271
|
if prev_kv:
|
|
@@ -317,9 +321,11 @@ class AsyncKVOperations:
|
|
|
317
321
|
credentials=self.client.call_credentials,
|
|
318
322
|
metadata=self.client.metadata,
|
|
319
323
|
)
|
|
320
|
-
|
|
324
|
+
|
|
321
325
|
# Set trace attributes from response
|
|
322
|
-
endpoint =
|
|
326
|
+
endpoint = (
|
|
327
|
+
str(self.client.endpoint_in_use) if self.client.endpoint_in_use else None
|
|
328
|
+
)
|
|
323
329
|
_set_span_attributes_from_response(delete_response, endpoint)
|
|
324
330
|
|
|
325
331
|
if return_response:
|
|
@@ -391,7 +397,9 @@ class AsyncKVOperations:
|
|
|
391
397
|
except Exception as exc:
|
|
392
398
|
if isinstance(exc, exceptions.BatchOperationError):
|
|
393
399
|
raise
|
|
394
|
-
raise exceptions.BatchOperationError(
|
|
400
|
+
raise exceptions.BatchOperationError(
|
|
401
|
+
f"Batch put failed: {exc}"
|
|
402
|
+
) from exc
|
|
395
403
|
else:
|
|
396
404
|
# Non-atomic: parallel execution with concurrency control
|
|
397
405
|
semaphore = asyncio.Semaphore(concurrency)
|
|
@@ -456,7 +464,9 @@ class AsyncKVOperations:
|
|
|
456
464
|
except Exception as exc:
|
|
457
465
|
if isinstance(exc, exceptions.BatchOperationError):
|
|
458
466
|
raise
|
|
459
|
-
raise exceptions.BatchOperationError(
|
|
467
|
+
raise exceptions.BatchOperationError(
|
|
468
|
+
f"Batch delete failed: {exc}"
|
|
469
|
+
) from exc
|
|
460
470
|
else:
|
|
461
471
|
# Non-atomic: parallel execution with concurrency control
|
|
462
472
|
semaphore = asyncio.Semaphore(concurrency)
|
|
@@ -537,21 +547,24 @@ class AsyncLeaseOperations:
|
|
|
537
547
|
credentials=self.client.call_credentials,
|
|
538
548
|
metadata=self.client.metadata,
|
|
539
549
|
)
|
|
540
|
-
|
|
550
|
+
|
|
541
551
|
# Set trace attributes for lease
|
|
542
552
|
if is_tracing_available():
|
|
543
553
|
span = get_current_span()
|
|
544
554
|
if span:
|
|
545
555
|
attrs = build_lease_attributes(
|
|
546
|
-
lease_id=lease_grant_response.ID,
|
|
547
|
-
|
|
556
|
+
lease_id=lease_grant_response.ID, ttl=lease_grant_response.TTL
|
|
557
|
+
)
|
|
558
|
+
endpoint = (
|
|
559
|
+
str(self.client.endpoint_in_use)
|
|
560
|
+
if self.client.endpoint_in_use
|
|
561
|
+
else None
|
|
548
562
|
)
|
|
549
|
-
endpoint = str(self.client.endpoint_in_use) if self.client.endpoint_in_use else None
|
|
550
563
|
if endpoint:
|
|
551
564
|
attrs[TraceAttributes.ETCD_ENDPOINT] = endpoint
|
|
552
565
|
for key, value in attrs.items():
|
|
553
566
|
span.set_attribute(key, value)
|
|
554
|
-
|
|
567
|
+
|
|
555
568
|
return AsyncLease(
|
|
556
569
|
lease_id=lease_grant_response.ID,
|
|
557
570
|
ttl=lease_grant_response.TTL,
|
|
@@ -569,13 +582,17 @@ class AsyncLeaseOperations:
|
|
|
569
582
|
credentials=self.client.call_credentials,
|
|
570
583
|
metadata=self.client.metadata,
|
|
571
584
|
)
|
|
572
|
-
|
|
585
|
+
|
|
573
586
|
# Set trace attributes for lease revocation
|
|
574
587
|
if is_tracing_available():
|
|
575
588
|
span = get_current_span()
|
|
576
589
|
if span:
|
|
577
590
|
attrs = build_lease_attributes(lease_id=lease_id)
|
|
578
|
-
endpoint =
|
|
591
|
+
endpoint = (
|
|
592
|
+
str(self.client.endpoint_in_use)
|
|
593
|
+
if self.client.endpoint_in_use
|
|
594
|
+
else None
|
|
595
|
+
)
|
|
579
596
|
if endpoint:
|
|
580
597
|
attrs[TraceAttributes.ETCD_ENDPOINT] = endpoint
|
|
581
598
|
for key, value in attrs.items():
|
|
@@ -646,7 +663,7 @@ class AsyncLeaseOperations:
|
|
|
646
663
|
# Exponential backoff with jitter
|
|
647
664
|
retry_delay = min(
|
|
648
665
|
base_retry_delay * (2 ** (consecutive_errors - 1)),
|
|
649
|
-
max_retry_delay
|
|
666
|
+
max_retry_delay,
|
|
650
667
|
)
|
|
651
668
|
jitter = random.uniform(0, retry_delay * 0.1)
|
|
652
669
|
actual_delay = retry_delay + jitter
|
|
@@ -677,7 +694,7 @@ class AsyncLeaseOperations:
|
|
|
677
694
|
credentials=self.client.call_credentials,
|
|
678
695
|
metadata=self.client.metadata,
|
|
679
696
|
)
|
|
680
|
-
|
|
697
|
+
|
|
681
698
|
# Set trace attributes for lease info
|
|
682
699
|
if is_tracing_available():
|
|
683
700
|
span = get_current_span()
|
|
@@ -685,15 +702,19 @@ class AsyncLeaseOperations:
|
|
|
685
702
|
attrs = build_lease_attributes(
|
|
686
703
|
lease_id=lease_id,
|
|
687
704
|
ttl=lease_timing_response.TTL,
|
|
688
|
-
remaining_ttl=getattr(lease_timing_response,
|
|
705
|
+
remaining_ttl=getattr(lease_timing_response, "TTL", None),
|
|
706
|
+
)
|
|
707
|
+
endpoint = (
|
|
708
|
+
str(self.client.endpoint_in_use)
|
|
709
|
+
if self.client.endpoint_in_use
|
|
710
|
+
else None
|
|
689
711
|
)
|
|
690
|
-
endpoint = str(self.client.endpoint_in_use) if self.client.endpoint_in_use else None
|
|
691
712
|
if endpoint:
|
|
692
713
|
attrs[TraceAttributes.ETCD_ENDPOINT] = endpoint
|
|
693
714
|
for key, value in attrs.items():
|
|
694
715
|
if value is not None:
|
|
695
716
|
span.set_attribute(key, value)
|
|
696
|
-
|
|
717
|
+
|
|
697
718
|
return lease_timing_response
|
|
698
719
|
|
|
699
720
|
|
etcd3/exceptions.py
CHANGED
|
@@ -39,9 +39,11 @@ class NoServerAvailableError(Etcd3Exception):
|
|
|
39
39
|
|
|
40
40
|
class LockReleaseError(Etcd3Exception):
|
|
41
41
|
"""Raised when a lock release operation fails."""
|
|
42
|
+
|
|
42
43
|
pass
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
class BatchOperationError(Etcd3Exception):
|
|
46
47
|
"""Raised when a batch operation fails."""
|
|
48
|
+
|
|
47
49
|
pass
|
etcd3/locks.py
CHANGED
|
@@ -88,7 +88,9 @@ class Lock(object):
|
|
|
88
88
|
success, metadata = self.etcd_client.transaction(
|
|
89
89
|
compare=[self.etcd_client.transactions.create(self.key) == 0],
|
|
90
90
|
success=[
|
|
91
|
-
self.etcd_client.transactions.put(
|
|
91
|
+
self.etcd_client.transactions.put(
|
|
92
|
+
self.key, self.uuid, lease=self.lease
|
|
93
|
+
)
|
|
92
94
|
],
|
|
93
95
|
failure=[self.etcd_client.transactions.get(self.key)],
|
|
94
96
|
)
|
|
@@ -189,7 +191,7 @@ class Lock(object):
|
|
|
189
191
|
)
|
|
190
192
|
|
|
191
193
|
if success:
|
|
192
|
-
return
|
|
194
|
+
return "released"
|
|
193
195
|
|
|
194
196
|
# Transaction succeeded but comparison failed
|
|
195
197
|
# Check if key exists and who owns it
|
|
@@ -200,26 +202,28 @@ class Lock(object):
|
|
|
200
202
|
raise exceptions.LockReleaseError(
|
|
201
203
|
"Lock key does not exist - may have expired or been released"
|
|
202
204
|
)
|
|
203
|
-
return
|
|
205
|
+
return "not_found"
|
|
204
206
|
if current_value != self.uuid:
|
|
205
207
|
if raise_error:
|
|
206
208
|
raise exceptions.LockReleaseError(
|
|
207
209
|
"Lock is held by another owner - cannot release"
|
|
208
210
|
)
|
|
209
|
-
return
|
|
211
|
+
return "not_owner"
|
|
210
212
|
|
|
211
213
|
if raise_error:
|
|
212
214
|
raise exceptions.LockReleaseError("Unknown lock release failure")
|
|
213
|
-
return
|
|
215
|
+
return "error"
|
|
214
216
|
|
|
215
217
|
except exceptions.Etcd3Exception:
|
|
216
218
|
if raise_error:
|
|
217
219
|
raise
|
|
218
|
-
return
|
|
220
|
+
return "error"
|
|
219
221
|
except Exception as exc:
|
|
220
222
|
if raise_error:
|
|
221
|
-
raise exceptions.LockReleaseError(
|
|
222
|
-
|
|
223
|
+
raise exceptions.LockReleaseError(
|
|
224
|
+
f"Lock release failed: {exc}"
|
|
225
|
+
) from exc
|
|
226
|
+
return "error"
|
|
223
227
|
|
|
224
228
|
def refresh(self):
|
|
225
229
|
"""Refresh the time to live on this lock."""
|
|
@@ -315,22 +319,24 @@ class AsyncLock(object):
|
|
|
315
319
|
|
|
316
320
|
def _set_lock_span_attributes(self, acquired: bool = None):
|
|
317
321
|
"""Set lock-related attributes on current span.
|
|
318
|
-
|
|
322
|
+
|
|
319
323
|
:param acquired: Whether the lock was acquired (optional)
|
|
320
324
|
"""
|
|
321
325
|
if not is_tracing_available():
|
|
322
326
|
return
|
|
323
|
-
|
|
327
|
+
|
|
324
328
|
span = get_current_span()
|
|
325
329
|
if span is None:
|
|
326
330
|
return
|
|
327
|
-
|
|
331
|
+
|
|
328
332
|
attrs = build_lock_attributes(
|
|
329
|
-
name=self.key
|
|
333
|
+
name=self.key
|
|
334
|
+
if isinstance(self.key, str)
|
|
335
|
+
else self.key.decode("utf-8", errors="replace"),
|
|
330
336
|
uuid=self.uuid,
|
|
331
|
-
acquired=acquired
|
|
337
|
+
acquired=acquired,
|
|
332
338
|
)
|
|
333
|
-
|
|
339
|
+
|
|
334
340
|
for key, value in attrs.items():
|
|
335
341
|
if value is not None:
|
|
336
342
|
span.set_attribute(key, value)
|
|
@@ -345,7 +351,9 @@ class AsyncLock(object):
|
|
|
345
351
|
success, metadata = await self.etcd_client.transaction(
|
|
346
352
|
compare=[self.etcd_client.transactions.create(self.key) == 0],
|
|
347
353
|
success=[
|
|
348
|
-
self.etcd_client.transactions.put(
|
|
354
|
+
self.etcd_client.transactions.put(
|
|
355
|
+
self.key, self.uuid, lease=self.lease
|
|
356
|
+
)
|
|
349
357
|
],
|
|
350
358
|
failure=[self.etcd_client.transactions.get(self.key)],
|
|
351
359
|
)
|
|
@@ -450,7 +458,7 @@ class AsyncLock(object):
|
|
|
450
458
|
|
|
451
459
|
if success:
|
|
452
460
|
self._set_lock_span_attributes(acquired=False)
|
|
453
|
-
return
|
|
461
|
+
return "released"
|
|
454
462
|
|
|
455
463
|
# Transaction succeeded but comparison failed
|
|
456
464
|
# Check if key exists and who owns it
|
|
@@ -462,29 +470,31 @@ class AsyncLock(object):
|
|
|
462
470
|
raise exceptions.LockReleaseError(
|
|
463
471
|
"Lock key does not exist - may have expired or been released"
|
|
464
472
|
)
|
|
465
|
-
return
|
|
473
|
+
return "not_found"
|
|
466
474
|
if current_value != self.uuid:
|
|
467
475
|
self._set_lock_span_attributes(acquired=None) # Owned by another
|
|
468
476
|
if raise_error:
|
|
469
477
|
raise exceptions.LockReleaseError(
|
|
470
478
|
"Lock is held by another owner - cannot release"
|
|
471
479
|
)
|
|
472
|
-
return
|
|
480
|
+
return "not_owner"
|
|
473
481
|
|
|
474
482
|
self._set_lock_span_attributes(acquired=None)
|
|
475
483
|
if raise_error:
|
|
476
484
|
raise exceptions.LockReleaseError("Unknown lock release failure")
|
|
477
|
-
return
|
|
485
|
+
return "error"
|
|
478
486
|
|
|
479
487
|
except exceptions.Etcd3Exception:
|
|
480
488
|
self._set_lock_span_attributes(acquired=None)
|
|
481
489
|
if raise_error:
|
|
482
490
|
raise
|
|
483
|
-
return
|
|
491
|
+
return "error"
|
|
484
492
|
except Exception as exc:
|
|
485
493
|
if raise_error:
|
|
486
|
-
raise exceptions.LockReleaseError(
|
|
487
|
-
|
|
494
|
+
raise exceptions.LockReleaseError(
|
|
495
|
+
f"Lock release failed: {exc}"
|
|
496
|
+
) from exc
|
|
497
|
+
return "error"
|
|
488
498
|
|
|
489
499
|
def refresh(self):
|
|
490
500
|
"""Refresh the time to lease on this lock.
|
|
@@ -540,9 +550,7 @@ class AsyncLock(object):
|
|
|
540
550
|
refresh_gen = self.refresh()
|
|
541
551
|
# Get one response from the generator to trigger keepalive
|
|
542
552
|
try:
|
|
543
|
-
await asyncio.wait_for(
|
|
544
|
-
refresh_gen.__anext__(), timeout=5.0
|
|
545
|
-
)
|
|
553
|
+
await asyncio.wait_for(refresh_gen.__anext__(), timeout=5.0)
|
|
546
554
|
# Successfully refreshed
|
|
547
555
|
except StopAsyncIteration:
|
|
548
556
|
# Generator ended unexpectedly
|
etcd3/trace_attributes.py
CHANGED
|
@@ -12,35 +12,35 @@ from typing import Any, Dict, Optional
|
|
|
12
12
|
|
|
13
13
|
class EtcdOperationType(Enum):
|
|
14
14
|
"""etcd operation types for tracing."""
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
# KV operations
|
|
17
17
|
KV_GET = "kv.get"
|
|
18
18
|
KV_PUT = "kv.put"
|
|
19
19
|
KV_DELETE = "kv.delete"
|
|
20
20
|
KV_RANGE = "kv.range"
|
|
21
21
|
KV_TXN = "kv.transaction"
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
# Lease operations
|
|
24
24
|
LEASE_GRANT = "lease.grant"
|
|
25
25
|
LEASE_REVOKE = "lease.revoke"
|
|
26
26
|
LEASE_KEEPALIVE = "lease.keepalive"
|
|
27
27
|
LEASE_TTL = "lease.ttl"
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
# Lock operations
|
|
30
30
|
LOCK_ACQUIRE = "lock.acquire"
|
|
31
31
|
LOCK_RELEASE = "lock.release"
|
|
32
32
|
LOCK_REFRESH = "lock.refresh"
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
# Watch operations
|
|
35
35
|
WATCH_CREATE = "watch.create"
|
|
36
36
|
WATCH_CANCEL = "watch.cancel"
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
# Cluster operations
|
|
39
39
|
CLUSTER_MEMBER_ADD = "cluster.member.add"
|
|
40
40
|
CLUSTER_MEMBER_REMOVE = "cluster.member.remove"
|
|
41
41
|
CLUSTER_MEMBER_UPDATE = "cluster.member.update"
|
|
42
42
|
CLUSTER_MEMBER_LIST = "cluster.member.list"
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
# Maintenance operations
|
|
45
45
|
MAINTENANCE_STATUS = "maintenance.status"
|
|
46
46
|
MAINTENANCE_COMPACT = "maintenance.compact"
|
|
@@ -50,126 +50,126 @@ class EtcdOperationType(Enum):
|
|
|
50
50
|
@dataclass(frozen=True)
|
|
51
51
|
class TraceAttributes:
|
|
52
52
|
"""Standard attribute names for etcd OpenTelemetry traces.
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
These attributes follow OpenTelemetry semantic conventions where applicable
|
|
55
55
|
and define etcd-specific attributes for comprehensive observability.
|
|
56
56
|
"""
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
# === OpenTelemetry Standard Database Attributes ===
|
|
59
59
|
DB_SYSTEM = "db.system"
|
|
60
60
|
"""Database system: always 'etcd' for this client."""
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
DB_OPERATION = "db.operation"
|
|
63
63
|
"""Database operation name (e.g., 'kv.get', 'lease.grant')."""
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
DB_STATEMENT = "db.statement"
|
|
66
66
|
"""Database statement (for complex queries, optional)."""
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
# === etcd Key-Value Attributes ===
|
|
69
69
|
ETCD_KEY = "etcd.key"
|
|
70
70
|
"""The key being operated on."""
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
ETCD_RANGE_END = "etcd.range_end"
|
|
73
73
|
"""End of the key range for range operations."""
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
ETCD_LIMIT = "etcd.limit"
|
|
76
76
|
"""Maximum number of keys to return."""
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
ETCD_REVISION = "etcd.revision"
|
|
79
79
|
"""Current revision of the operation result."""
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
ETCD_PREV_REVISION = "etcd.prev_revision"
|
|
82
82
|
"""Previous revision (for compare operations)."""
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
ETCD_COUNT = "etcd.count"
|
|
85
85
|
"""Number of keys returned or affected."""
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
ETCD_DELETED = "etcd.deleted"
|
|
88
88
|
"""Number of keys deleted."""
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
# === etcd Cluster Attributes ===
|
|
91
91
|
ETCD_ENDPOINT = "etcd.endpoint"
|
|
92
92
|
"""The etcd endpoint being accessed."""
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
ETCD_CLUSTER_ID = "etcd.cluster_id"
|
|
95
95
|
"""Cluster ID from response header."""
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
ETCD_MEMBER_ID = "etcd.member_id"
|
|
98
98
|
"""Member ID from response header."""
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
ETCD_RAFT_TERM = "etcd.raft_term"
|
|
101
101
|
"""Raft term from response header."""
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
# === etcd Lease Attributes ===
|
|
104
104
|
ETCD_LEASE_ID = "etcd.lease.id"
|
|
105
105
|
"""Lease ID."""
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
ETCD_LEASE_TTL = "etcd.lease.ttl"
|
|
108
108
|
"""Lease TTL in seconds."""
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
ETCD_LEASE_REMAINING_TTL = "etcd.lease.remaining_ttl"
|
|
111
111
|
"""Remaining TTL for the lease."""
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
# === etcd Lock Attributes ===
|
|
114
114
|
ETCD_LOCK_NAME = "etcd.lock.name"
|
|
115
115
|
"""Lock name (key path)."""
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
ETCD_LOCK_UUID = "etcd.lock.uuid"
|
|
118
118
|
"""Lock UUID (first 8 bytes)."""
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
ETCD_LOCK_ACQUIRED = "etcd.lock.acquired"
|
|
121
121
|
"""Whether the lock was successfully acquired."""
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
# === etcd Transaction Attributes ===
|
|
124
124
|
ETCD_TXN_COMPARE_COUNT = "etcd.txn.compare_count"
|
|
125
125
|
"""Number of compare conditions."""
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
ETCD_TXN_SUCCESS_COUNT = "etcd.txn.success_count"
|
|
128
128
|
"""Number of success operations."""
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
ETCD_TXN_FAILURE_COUNT = "etcd.txn.failure_count"
|
|
131
131
|
"""Number of failure operations."""
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
ETCD_TXN_SUCCEEDED = "etcd.txn.succeeded"
|
|
134
134
|
"""Whether the transaction succeeded."""
|
|
135
|
-
|
|
135
|
+
|
|
136
136
|
# === etcd Batch Attributes ===
|
|
137
137
|
ETCD_BATCH_SIZE = "etcd.batch.size"
|
|
138
138
|
"""Number of operations in the batch."""
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
ETCD_BATCH_ATOMIC = "etcd.batch.atomic"
|
|
141
141
|
"""Whether the batch is atomic."""
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
# === etcd Error Attributes ===
|
|
144
144
|
ETCD_ERROR_CODE = "etcd.error_code"
|
|
145
145
|
"""Error code if operation failed."""
|
|
146
|
-
|
|
146
|
+
|
|
147
147
|
ETCD_ERROR_MESSAGE = "etcd.error_message"
|
|
148
148
|
"""Error message if operation failed."""
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
# === Retry Attributes ===
|
|
151
151
|
ETCD_RETRY_COUNT = "etcd.retry.count"
|
|
152
152
|
"""Number of retries for this operation."""
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
ETCD_RETRY_ENDPOINT = "etcd.retry.endpoint"
|
|
155
155
|
"""Endpoint used after retry."""
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
def _safe_decode(value: Optional[bytes], max_length: int = 256) -> Optional[str]:
|
|
159
159
|
"""Safely decode bytes to string for attribute values.
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
Args:
|
|
162
162
|
value: Bytes value to decode
|
|
163
163
|
max_length: Maximum length for the decoded string
|
|
164
|
-
|
|
164
|
+
|
|
165
165
|
Returns:
|
|
166
166
|
Decoded string or None if input is None
|
|
167
167
|
"""
|
|
168
168
|
if value is None:
|
|
169
169
|
return None
|
|
170
|
-
|
|
170
|
+
|
|
171
171
|
try:
|
|
172
|
-
decoded = value.decode(
|
|
172
|
+
decoded = value.decode("utf-8", errors="replace")
|
|
173
173
|
if len(decoded) > max_length:
|
|
174
174
|
decoded = decoded[:max_length] + "..."
|
|
175
175
|
return decoded
|
|
@@ -182,17 +182,17 @@ def build_kv_attributes(
|
|
|
182
182
|
key: Optional[bytes] = None,
|
|
183
183
|
range_end: Optional[bytes] = None,
|
|
184
184
|
limit: Optional[int] = None,
|
|
185
|
-
**kwargs
|
|
185
|
+
**kwargs,
|
|
186
186
|
) -> Dict[str, Any]:
|
|
187
187
|
"""Build trace attributes for KV operations.
|
|
188
|
-
|
|
188
|
+
|
|
189
189
|
Args:
|
|
190
190
|
operation: Operation type (e.g., 'kv.get', 'kv.put')
|
|
191
191
|
key: The key being operated on
|
|
192
192
|
range_end: End of key range for range operations
|
|
193
193
|
limit: Maximum number of keys to return
|
|
194
194
|
**kwargs: Additional attributes
|
|
195
|
-
|
|
195
|
+
|
|
196
196
|
Returns:
|
|
197
197
|
Dictionary of trace attributes
|
|
198
198
|
"""
|
|
@@ -200,51 +200,48 @@ def build_kv_attributes(
|
|
|
200
200
|
TraceAttributes.DB_SYSTEM: "etcd",
|
|
201
201
|
TraceAttributes.DB_OPERATION: operation,
|
|
202
202
|
}
|
|
203
|
-
|
|
203
|
+
|
|
204
204
|
if key is not None:
|
|
205
205
|
attrs[TraceAttributes.ETCD_KEY] = _safe_decode(key)
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
if range_end is not None:
|
|
208
208
|
attrs[TraceAttributes.ETCD_RANGE_END] = _safe_decode(range_end)
|
|
209
|
-
|
|
209
|
+
|
|
210
210
|
if limit is not None:
|
|
211
211
|
attrs[TraceAttributes.ETCD_LIMIT] = limit
|
|
212
|
-
|
|
212
|
+
|
|
213
213
|
attrs.update(kwargs)
|
|
214
214
|
return attrs
|
|
215
215
|
|
|
216
216
|
|
|
217
217
|
def build_response_attributes(
|
|
218
|
-
header=None,
|
|
219
|
-
count: Optional[int] = None,
|
|
220
|
-
deleted: Optional[int] = None,
|
|
221
|
-
**kwargs
|
|
218
|
+
header=None, count: Optional[int] = None, deleted: Optional[int] = None, **kwargs
|
|
222
219
|
) -> Dict[str, Any]:
|
|
223
220
|
"""Build trace attributes from etcd response.
|
|
224
|
-
|
|
221
|
+
|
|
225
222
|
Args:
|
|
226
223
|
header: Response header from etcd
|
|
227
224
|
count: Number of keys returned/affected
|
|
228
225
|
deleted: Number of keys deleted
|
|
229
226
|
**kwargs: Additional attributes
|
|
230
|
-
|
|
227
|
+
|
|
231
228
|
Returns:
|
|
232
229
|
Dictionary of trace attributes
|
|
233
230
|
"""
|
|
234
231
|
attrs = {}
|
|
235
|
-
|
|
232
|
+
|
|
236
233
|
if header:
|
|
237
234
|
attrs[TraceAttributes.ETCD_REVISION] = header.revision
|
|
238
235
|
attrs[TraceAttributes.ETCD_CLUSTER_ID] = header.cluster_id
|
|
239
236
|
attrs[TraceAttributes.ETCD_MEMBER_ID] = header.member_id
|
|
240
237
|
attrs[TraceAttributes.ETCD_RAFT_TERM] = header.raft_term
|
|
241
|
-
|
|
238
|
+
|
|
242
239
|
if count is not None:
|
|
243
240
|
attrs[TraceAttributes.ETCD_COUNT] = count
|
|
244
|
-
|
|
241
|
+
|
|
245
242
|
if deleted is not None:
|
|
246
243
|
attrs[TraceAttributes.ETCD_DELETED] = deleted
|
|
247
|
-
|
|
244
|
+
|
|
248
245
|
attrs.update(kwargs)
|
|
249
246
|
return attrs
|
|
250
247
|
|
|
@@ -253,32 +250,32 @@ def build_lease_attributes(
|
|
|
253
250
|
lease_id: Optional[int] = None,
|
|
254
251
|
ttl: Optional[int] = None,
|
|
255
252
|
remaining_ttl: Optional[int] = None,
|
|
256
|
-
**kwargs
|
|
253
|
+
**kwargs,
|
|
257
254
|
) -> Dict[str, Any]:
|
|
258
255
|
"""Build trace attributes for lease operations.
|
|
259
|
-
|
|
256
|
+
|
|
260
257
|
Args:
|
|
261
258
|
lease_id: Lease ID
|
|
262
259
|
ttl: Lease TTL in seconds
|
|
263
260
|
remaining_ttl: Remaining TTL
|
|
264
261
|
**kwargs: Additional attributes
|
|
265
|
-
|
|
262
|
+
|
|
266
263
|
Returns:
|
|
267
264
|
Dictionary of trace attributes
|
|
268
265
|
"""
|
|
269
266
|
attrs = {
|
|
270
267
|
TraceAttributes.DB_SYSTEM: "etcd",
|
|
271
268
|
}
|
|
272
|
-
|
|
269
|
+
|
|
273
270
|
if lease_id is not None:
|
|
274
271
|
attrs[TraceAttributes.ETCD_LEASE_ID] = lease_id
|
|
275
|
-
|
|
272
|
+
|
|
276
273
|
if ttl is not None:
|
|
277
274
|
attrs[TraceAttributes.ETCD_LEASE_TTL] = ttl
|
|
278
|
-
|
|
275
|
+
|
|
279
276
|
if remaining_ttl is not None:
|
|
280
277
|
attrs[TraceAttributes.ETCD_LEASE_REMAINING_TTL] = remaining_ttl
|
|
281
|
-
|
|
278
|
+
|
|
282
279
|
attrs.update(kwargs)
|
|
283
280
|
return attrs
|
|
284
281
|
|
|
@@ -287,34 +284,34 @@ def build_lock_attributes(
|
|
|
287
284
|
name: Optional[str] = None,
|
|
288
285
|
uuid: Optional[bytes] = None,
|
|
289
286
|
acquired: Optional[bool] = None,
|
|
290
|
-
**kwargs
|
|
287
|
+
**kwargs,
|
|
291
288
|
) -> Dict[str, Any]:
|
|
292
289
|
"""Build trace attributes for lock operations.
|
|
293
|
-
|
|
290
|
+
|
|
294
291
|
Args:
|
|
295
292
|
name: Lock name (key path)
|
|
296
293
|
uuid: Lock UUID (will use first 8 bytes)
|
|
297
294
|
acquired: Whether the lock was acquired
|
|
298
295
|
**kwargs: Additional attributes
|
|
299
|
-
|
|
296
|
+
|
|
300
297
|
Returns:
|
|
301
298
|
Dictionary of trace attributes
|
|
302
299
|
"""
|
|
303
300
|
attrs = {
|
|
304
301
|
TraceAttributes.DB_SYSTEM: "etcd",
|
|
305
302
|
}
|
|
306
|
-
|
|
303
|
+
|
|
307
304
|
if name is not None:
|
|
308
305
|
attrs[TraceAttributes.ETCD_LOCK_NAME] = name
|
|
309
|
-
|
|
306
|
+
|
|
310
307
|
if uuid is not None:
|
|
311
308
|
# Use first 8 bytes of UUID for readability
|
|
312
309
|
uuid_str = uuid[:8].hex() if isinstance(uuid, bytes) else str(uuid)[:16]
|
|
313
310
|
attrs[TraceAttributes.ETCD_LOCK_UUID] = uuid_str
|
|
314
|
-
|
|
311
|
+
|
|
315
312
|
if acquired is not None:
|
|
316
313
|
attrs[TraceAttributes.ETCD_LOCK_ACQUIRED] = acquired
|
|
317
|
-
|
|
314
|
+
|
|
318
315
|
attrs.update(kwargs)
|
|
319
316
|
return attrs
|
|
320
317
|
|
|
@@ -324,52 +321,48 @@ def build_txn_attributes(
|
|
|
324
321
|
success_count: Optional[int] = None,
|
|
325
322
|
failure_count: Optional[int] = None,
|
|
326
323
|
succeeded: Optional[bool] = None,
|
|
327
|
-
**kwargs
|
|
324
|
+
**kwargs,
|
|
328
325
|
) -> Dict[str, Any]:
|
|
329
326
|
"""Build trace attributes for transaction operations.
|
|
330
|
-
|
|
327
|
+
|
|
331
328
|
Args:
|
|
332
329
|
compare_count: Number of compare conditions
|
|
333
330
|
success_count: Number of success operations
|
|
334
331
|
failure_count: Number of failure operations
|
|
335
332
|
succeeded: Whether the transaction succeeded
|
|
336
333
|
**kwargs: Additional attributes
|
|
337
|
-
|
|
334
|
+
|
|
338
335
|
Returns:
|
|
339
336
|
Dictionary of trace attributes
|
|
340
337
|
"""
|
|
341
338
|
attrs = {
|
|
342
339
|
TraceAttributes.DB_SYSTEM: "etcd",
|
|
343
340
|
}
|
|
344
|
-
|
|
341
|
+
|
|
345
342
|
if compare_count is not None:
|
|
346
343
|
attrs[TraceAttributes.ETCD_TXN_COMPARE_COUNT] = compare_count
|
|
347
|
-
|
|
344
|
+
|
|
348
345
|
if success_count is not None:
|
|
349
346
|
attrs[TraceAttributes.ETCD_TXN_SUCCESS_COUNT] = success_count
|
|
350
|
-
|
|
347
|
+
|
|
351
348
|
if failure_count is not None:
|
|
352
349
|
attrs[TraceAttributes.ETCD_TXN_FAILURE_COUNT] = failure_count
|
|
353
|
-
|
|
350
|
+
|
|
354
351
|
if succeeded is not None:
|
|
355
352
|
attrs[TraceAttributes.ETCD_TXN_SUCCEEDED] = succeeded
|
|
356
|
-
|
|
353
|
+
|
|
357
354
|
attrs.update(kwargs)
|
|
358
355
|
return attrs
|
|
359
356
|
|
|
360
357
|
|
|
361
|
-
def build_batch_attributes(
|
|
362
|
-
size: int,
|
|
363
|
-
atomic: bool = False,
|
|
364
|
-
**kwargs
|
|
365
|
-
) -> Dict[str, Any]:
|
|
358
|
+
def build_batch_attributes(size: int, atomic: bool = False, **kwargs) -> Dict[str, Any]:
|
|
366
359
|
"""Build trace attributes for batch operations.
|
|
367
|
-
|
|
360
|
+
|
|
368
361
|
Args:
|
|
369
362
|
size: Number of operations in the batch
|
|
370
363
|
atomic: Whether the batch is atomic
|
|
371
364
|
**kwargs: Additional attributes
|
|
372
|
-
|
|
365
|
+
|
|
373
366
|
Returns:
|
|
374
367
|
Dictionary of trace attributes
|
|
375
368
|
"""
|
|
@@ -378,57 +371,52 @@ def build_batch_attributes(
|
|
|
378
371
|
TraceAttributes.ETCD_BATCH_SIZE: size,
|
|
379
372
|
TraceAttributes.ETCD_BATCH_ATOMIC: atomic,
|
|
380
373
|
}
|
|
381
|
-
|
|
374
|
+
|
|
382
375
|
attrs.update(kwargs)
|
|
383
376
|
return attrs
|
|
384
377
|
|
|
385
378
|
|
|
386
|
-
def build_endpoint_attributes(
|
|
387
|
-
endpoint: str,
|
|
388
|
-
**kwargs
|
|
389
|
-
) -> Dict[str, Any]:
|
|
379
|
+
def build_endpoint_attributes(endpoint: str, **kwargs) -> Dict[str, Any]:
|
|
390
380
|
"""Build trace attributes for endpoint-related operations.
|
|
391
|
-
|
|
381
|
+
|
|
392
382
|
Args:
|
|
393
383
|
endpoint: The etcd endpoint
|
|
394
384
|
**kwargs: Additional attributes
|
|
395
|
-
|
|
385
|
+
|
|
396
386
|
Returns:
|
|
397
387
|
Dictionary of trace attributes
|
|
398
388
|
"""
|
|
399
389
|
attrs = {
|
|
400
390
|
TraceAttributes.ETCD_ENDPOINT: endpoint,
|
|
401
391
|
}
|
|
402
|
-
|
|
392
|
+
|
|
403
393
|
attrs.update(kwargs)
|
|
404
394
|
return attrs
|
|
405
395
|
|
|
406
396
|
|
|
407
397
|
def build_error_attributes(
|
|
408
|
-
error_code: Optional[str] = None,
|
|
409
|
-
error_message: Optional[str] = None,
|
|
410
|
-
**kwargs
|
|
398
|
+
error_code: Optional[str] = None, error_message: Optional[str] = None, **kwargs
|
|
411
399
|
) -> Dict[str, Any]:
|
|
412
400
|
"""Build trace attributes for error cases.
|
|
413
|
-
|
|
401
|
+
|
|
414
402
|
Args:
|
|
415
403
|
error_code: Error code
|
|
416
404
|
error_message: Error message
|
|
417
405
|
**kwargs: Additional attributes
|
|
418
|
-
|
|
406
|
+
|
|
419
407
|
Returns:
|
|
420
408
|
Dictionary of trace attributes
|
|
421
409
|
"""
|
|
422
410
|
attrs = {}
|
|
423
|
-
|
|
411
|
+
|
|
424
412
|
if error_code is not None:
|
|
425
413
|
attrs[TraceAttributes.ETCD_ERROR_CODE] = error_code
|
|
426
|
-
|
|
414
|
+
|
|
427
415
|
if error_message is not None:
|
|
428
416
|
# Truncate long error messages
|
|
429
417
|
if len(error_message) > 256:
|
|
430
418
|
error_message = error_message[:256] + "..."
|
|
431
419
|
attrs[TraceAttributes.ETCD_ERROR_MESSAGE] = error_message
|
|
432
|
-
|
|
420
|
+
|
|
433
421
|
attrs.update(kwargs)
|
|
434
422
|
return attrs
|
etcd3/utils.py
CHANGED
|
@@ -13,9 +13,9 @@ import grpc
|
|
|
13
13
|
# events, cancel = await etcd.watch('/key', filters=[FILTER_DELETE])
|
|
14
14
|
# # Only PUT events will be received, DELETE events are filtered out
|
|
15
15
|
#
|
|
16
|
-
FILTER_PUT = 0
|
|
17
|
-
FILTER_DELETE = 1
|
|
18
|
-
FILTER_COMMIT = 2
|
|
16
|
+
FILTER_PUT = 0 # Filter out PUT events (only DELETE events will be received)
|
|
17
|
+
FILTER_DELETE = 1 # Filter out DELETE events (only PUT events will be received)
|
|
18
|
+
FILTER_COMMIT = 2 # Filter out all events (no events will be received)
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class LoadBalancerStrategy(Enum):
|
|
@@ -27,6 +27,7 @@ class LoadBalancerStrategy(Enum):
|
|
|
27
27
|
RANDOM: Random - select random healthy endpoint
|
|
28
28
|
STICKY: Sticky - maintain connection to the same endpoint
|
|
29
29
|
"""
|
|
30
|
+
|
|
30
31
|
PRIORITY = "priority"
|
|
31
32
|
ROUND_ROBIN = "round_robin"
|
|
32
33
|
RANDOM = "random"
|
etcdrpc/__init__.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# 简单的检查,如果文件不存在则报错提示(防御性编程)
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
|
|
5
6
|
_current_dir = Path(__file__).parent
|
|
6
7
|
if not (_current_dir / "rpc_pb2.py").exists():
|
|
7
8
|
raise ImportError(
|
|
@@ -13,4 +14,4 @@ from etcdrpc.rpc_pb2 import *
|
|
|
13
14
|
from etcdrpc.rpc_pb2_grpc import *
|
|
14
15
|
|
|
15
16
|
# 获取所有非私有成员
|
|
16
|
-
__all__ = [name for name in globals().keys() if not name.startswith(
|
|
17
|
+
__all__ = [name for name in globals().keys() if not name.startswith("_")]
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-etcd3-async
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: etcd3 async sdk
|
|
5
5
|
Requires-Python: <4,>=3.12
|
|
6
|
-
Requires-Dist: grpcio==1.
|
|
6
|
+
Requires-Dist: grpcio==1.66.2
|
|
7
7
|
Requires-Dist: prometheus-client>=0.24.1
|
|
8
|
-
Requires-Dist: protobuf==6.31.1
|
|
9
8
|
Description-Content-Type: text/markdown
|
|
10
9
|
|
|
11
10
|
# python-etcd3-async
|
|
@@ -25,6 +24,7 @@ Python async client for the etcd API v3, supporting both synchronous and asynchr
|
|
|
25
24
|
- **Keepalive error propagation**: Lease keepalive errors are properly propagated for connection loss detection
|
|
26
25
|
- **Endpoint failover**: Built-in support for multiple endpoints with automatic failover
|
|
27
26
|
- **Context manager**: Clean resource management for both sync and async
|
|
27
|
+
- **Observability**: Structured logging, OpenTelemetry tracing, and Prometheus metrics
|
|
28
28
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
@@ -294,14 +294,53 @@ client = await async_client(
|
|
|
294
294
|
)
|
|
295
295
|
```
|
|
296
296
|
|
|
297
|
-
##
|
|
297
|
+
## Observability
|
|
298
298
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
### Configure via Environment
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
export ETCD_OBS_LOG_LEVEL=DEBUG
|
|
303
|
+
export ETCD_OBS_LOG_FORMAT=json
|
|
304
|
+
export ETCD_OBS_TRACING_ENABLED=true
|
|
305
|
+
export ETCD_OBS_PROMETHEUS_ENABLED=true
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Configure Programmatically
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
from etcd3 import ObservabilityConfig
|
|
312
|
+
|
|
313
|
+
config = ObservabilityConfig(
|
|
314
|
+
tracing_enabled=True,
|
|
315
|
+
log_format="json",
|
|
316
|
+
log_level="INFO",
|
|
317
|
+
prometheus_enabled=True,
|
|
318
|
+
)
|
|
319
|
+
config.apply()
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Access Metrics
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
from etcd3.exporters.prometheus import get_exporter
|
|
326
|
+
|
|
327
|
+
exporter = get_exporter()
|
|
328
|
+
if exporter:
|
|
329
|
+
print(exporter.metrics().decode())
|
|
330
|
+
```
|
|
302
331
|
|
|
303
332
|
## API Reference
|
|
304
333
|
|
|
334
|
+
### Environment Variables
|
|
335
|
+
|
|
336
|
+
| Variable | Default | Description |
|
|
337
|
+
|----------|---------|-------------|
|
|
338
|
+
| `ETCD_OBS_LOG_LEVEL` | INFO | Logging level (DEBUG, INFO, WARNING, ERROR) |
|
|
339
|
+
| `ETCD_OBS_LOG_FORMAT` | text | Log format (text, json, colored) |
|
|
340
|
+
| `ETCD_OBS_TRACING_ENABLED` | true | Enable OpenTelemetry tracing |
|
|
341
|
+
| `ETCD_OBS_TRACING_SERVICE_NAME` | etcd3-client | Service name for tracing |
|
|
342
|
+
| `ETCD_OBS_PROMETHEUS_ENABLED` | false | Enable Prometheus metrics export |
|
|
343
|
+
|
|
305
344
|
### Client Factory
|
|
306
345
|
|
|
307
346
|
| Function | Description |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
etcd3/__init__.py,sha256=_G81-O1yZsDNpMp_VvWDS8YNE9EgHEmgAhXdZ5VokP8,2811
|
|
2
2
|
etcd3/async_client.py,sha256=wnzRgPzmFN2Xe0TPxSL-bHTo_lnL01l_I2L6arMGUaw,54229
|
|
3
|
-
etcd3/async_client_extensions.py,sha256=
|
|
3
|
+
etcd3/async_client_extensions.py,sha256=VWXLhmjBNL1UNhMynZmx5P2sPn_mgTpVXvvU98GDY90,34483
|
|
4
4
|
etcd3/async_endpoint.py,sha256=nDQtXCze1H8SAHIFJ0HYc1dBY2Nc0gw_t3SVT5d1Zmg,4587
|
|
5
5
|
etcd3/async_managers.py,sha256=bUbrqkeq1Rv_qhDGOkIqgSoqA-Lyo10Vbxc60KahtXc,17620
|
|
6
6
|
etcd3/async_monitor.py,sha256=iZPac3Pqn5bI0ONguJJctQsi4b2ft4hWPknug6jj5RY,453
|
|
@@ -8,9 +8,9 @@ etcd3/async_watch.py,sha256=m6I2BAoI54J-ZPVVMxao6XJQXvVyQ88Hp2QeauD9z20,15962
|
|
|
8
8
|
etcd3/client.py,sha256=43OjwOGlxgA3pKTkMZoL4Aem0_Axk7TDrb6-TB6veos,72347
|
|
9
9
|
etcd3/endpoint.py,sha256=aSMBmEitAADW0ABAZhc8L7jPYsQo8amEWKv6LJbsmC4,2589
|
|
10
10
|
etcd3/events.py,sha256=e4gTiUE4SRon8R-if9SKORIM_jr8XtVye-GcV-owKdw,972
|
|
11
|
-
etcd3/exceptions.py,sha256=
|
|
11
|
+
etcd3/exceptions.py,sha256=W73_Brq7p25clQLW4sC0zKx_EZG7x2JToInwZ9D-gAc,998
|
|
12
12
|
etcd3/leases.py,sha256=7eVl0rA2IGIOBTHbBn0Te9SQ-TKBr4v20X7iUzWYcSo,2804
|
|
13
|
-
etcd3/locks.py,sha256=
|
|
13
|
+
etcd3/locks.py,sha256=NrLqqrloZ1HksmQRYb_NEa96Nn-tASS0EgzoTPwG6Oo,22640
|
|
14
14
|
etcd3/log.py,sha256=sMo6av48x9Nf_YDIWdSv8R-VUeVXi1n17wGDAAaFnlM,4282
|
|
15
15
|
etcd3/log_formatters.py,sha256=weWgMQjuI_cZFBEUORGCgkFJQIPvDUaiCLJN64t7s9o,7304
|
|
16
16
|
etcd3/log_sampling.py,sha256=7PhNz-HOZ6sHdBiXS29YJ3baHY_L1VwJaq4NZt2yX78,6692
|
|
@@ -18,13 +18,13 @@ etcd3/members.py,sha256=LLg6sAWDaaW0wzl_yBF3ialMQuaRKLFpFDEcmWcbqzY,1414
|
|
|
18
18
|
etcd3/observability.py,sha256=BLOUMs1H2icF-tEWB_RoZFKoCNoXZt1ZZERGfckesW4,14215
|
|
19
19
|
etcd3/shared.py,sha256=6-mhHNvGD6TPwq79EQa6oGxoZoGKR5oZSZkJeSbZpc8,16195
|
|
20
20
|
etcd3/trace.py,sha256=OtOmAZ5uz7v7dqPoAaEM8d94prK5f5tSEJq7Qi2w_0c,6650
|
|
21
|
-
etcd3/trace_attributes.py,sha256
|
|
21
|
+
etcd3/trace_attributes.py,sha256=-wk0ZFqjzQT4g7_HErWhJMsVk8ocfPcMDNLJzwDMEjc,11621
|
|
22
22
|
etcd3/transactions.py,sha256=FJe-J5QBm-pV_J9dGIMor35PHAXvb61bjSELkg5Bw4U,7587
|
|
23
|
-
etcd3/utils.py,sha256=
|
|
23
|
+
etcd3/utils.py,sha256=j10jFnxzZKy5-ImvrWVs18QPbQMvsFmnibPe0Mctm9g,4806
|
|
24
24
|
etcd3/watch.py,sha256=rPEvOm1nQOPzj00OV6GFObZ2uSQqNl2pEcT7ut7xO44,8838
|
|
25
25
|
etcd3/exporters/__init__.py,sha256=9nMfrCsQ-pN5WUIY2ZHBsY4N3xmdD2Z24mDCi19hJE8,362
|
|
26
26
|
etcd3/exporters/prometheus.py,sha256=goA42MAwuR-FI4QH5K4jMOJt51tfC2V9BTeAf9dL5hg,10211
|
|
27
|
-
etcdrpc/__init__.py,sha256
|
|
27
|
+
etcdrpc/__init__.py,sha256=-ykqbdDaroJTTyUip4RaZDewcnPPJcOwI9bXYxxXF6Q,549
|
|
28
28
|
etcdrpc/auth.proto,sha256=Py2ysZTy4i89vxRHBdXK-KcPCkojcEfWXDNbDajLRWk,1170
|
|
29
29
|
etcdrpc/auth_pb2.py,sha256=H-HBNZ64Mi0aqMIgjqvgdDcm5DBl9GIhqipRBCt1LlA,2120
|
|
30
30
|
etcdrpc/auth_pb2.pyi,sha256=vEV6IzZnKObqDI6fJPtXAqRbnKZC3vXy4UAem_XZVvY,1985
|
|
@@ -37,6 +37,6 @@ etcdrpc/rpc.proto,sha256=UD4vXbdPUNHSLSx7K_UltWqJjWswHBKSs0t9aNMA4qg,31351
|
|
|
37
37
|
etcdrpc/rpc_pb2.py,sha256=8qhnULNr8jym0qyivDVqJB86H_u1Rb_K8iY8FNT9e0s,30252
|
|
38
38
|
etcdrpc/rpc_pb2.pyi,sha256=TfPtHXIluO_D1rchVMVfoSgZTPQLk-YNhmcJBIt9XIk,35473
|
|
39
39
|
etcdrpc/rpc_pb2_grpc.py,sha256=HOifyKL0X3BmLkS1r0tWTMfyfChBiy76O6Ys12kT5n8,73810
|
|
40
|
-
python_etcd3_async-0.1.
|
|
41
|
-
python_etcd3_async-0.1.
|
|
42
|
-
python_etcd3_async-0.1.
|
|
40
|
+
python_etcd3_async-0.1.2.dist-info/METADATA,sha256=JHiGpX_FT-5svHnzKLIfiev9t9hxWqVZug3Gz_YerF4,8700
|
|
41
|
+
python_etcd3_async-0.1.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
42
|
+
python_etcd3_async-0.1.2.dist-info/RECORD,,
|