Skip to content

Commit 9583de7

Browse files
committed
PYCBC-1750: Wrapper SDK Observability - Remaining Management APIs
Changes ------- * Add tracing "hooks" to all remaining management operations: Analytics Index, Eventing Function, Search Index, User and View Index management * Update request builder and implementation layers to accept and propagate observability_instruments and obs_handler throughout all management API call paths (sync, async and Twisted) * Fix req_to_dict in management type files to propagate wrapper_span_name and parent_span from obs_handler into the operation request dictionaries * Fix typo: rename search_index_mgmt_imply.py to search_index_mgmt_impl.py in both acouchbase and txcouchbase * Update cluster, bucket and scope constructors (sync, async and Twisted) to propagate observability_instruments when creating management objects * Add tracing support to txcouchbase management APIs using manual span management with addBoth/_finish_span pattern * Add span option to all management operation option classes (Analytics, Eventing, Search Index, User, Views) with docstrings and @overload signatures where applicable * Add op_type_toggle param to SearchIndexManager and ScopeSearchIndexManager control methods (pause/resume ingest, allow/disallow querying, freeze/unfreeze plan) across sync, async and Twisted managers so OpName.from_op_type() can resolve the correct operation name * Add explanatory comments to analytics managers (sync, async and Twisted) clarifying the arbitrary choice of AnalyticsLinkCreateCouchbaseRemoteLink / AnalyticsLinkReplaceCouchbaseRemoteLink as the op_type * Expand test suite to cover upsert, get, get_all and drop (plus error cases) for Search Index and User management; confirm parent span propagation for all management APIs Change-Id: Ic1b406151b79994837052e9ac97b57b6deb53f8b Reviewed-on: https://review.couchbase.org/c/couchbase-python-client/+/241426 Tested-by: Build Bot <build@couchbase.com> Reviewed-by: Sergey Avseyev <sergey.avseyev@gmail.com>
1 parent 5dc9ef7 commit 9583de7

52 files changed

Lines changed: 3740 additions & 1310 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

acouchbase/bucket.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ def view_indexes(self) -> ViewIndexManager:
224224
Returns:
225225
:class:`~acouchbase.management.views.ViewIndexManager`: A :class:`~couchbase.management.views.ViewIndexManager` instance.
226226
""" # noqa: E501
227-
return ViewIndexManager(self._impl._client_adapter, self.name)
227+
return ViewIndexManager(self._impl._client_adapter, self.name, self._impl.observability_instruments)
228228

229229

230230
Bucket = AsyncBucket

acouchbase/cluster.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ def users(self) -> UserManager:
647647
Returns:
648648
:class:`~acouchbase.management.users.UserManager`: A :class:`~couchbase.management.users.UserManager` instance.
649649
""" # noqa: E501
650-
return UserManager(self._impl._client_adapter)
650+
return UserManager(self._impl._client_adapter, self._impl.observability_instruments)
651651

652652
def query_indexes(self) -> QueryIndexManager:
653653
"""
@@ -667,7 +667,7 @@ def analytics_indexes(self) -> AnalyticsIndexManager:
667667
Returns:
668668
:class:`~acouchbase.management.analytics.AnalyticsIndexManager`: An :class:`~acouchbase.management.analytics.AnalyticsIndexManager` instance.
669669
""" # noqa: E501
670-
return AnalyticsIndexManager(self._impl._client_adapter)
670+
return AnalyticsIndexManager(self._impl._client_adapter, self._impl.observability_instruments)
671671

672672
def search_indexes(self) -> SearchIndexManager:
673673
"""
@@ -678,7 +678,7 @@ def search_indexes(self) -> SearchIndexManager:
678678
:class:`~acouchbase.management.search.SearchIndexManager`: A :class:`~acouchbase.management.search.SearchIndexManager` instance.
679679
680680
""" # noqa: E501
681-
return SearchIndexManager(self._impl._client_adapter)
681+
return SearchIndexManager(self._impl._client_adapter, self._impl.observability_instruments)
682682

683683
def eventing_functions(self) -> EventingFunctionManager:
684684
"""
@@ -693,7 +693,7 @@ def eventing_functions(self) -> EventingFunctionManager:
693693
:class:`~acouchbase.management.eventing.EventingFunctionManager`: An :class:`~acouchbase.management.eventing.EventingFunctionManager` instance.
694694
695695
""" # noqa: E501
696-
return EventingFunctionManager(self._impl._client_adapter)
696+
return EventingFunctionManager(self._impl._client_adapter, self._impl.observability_instruments)
697697

698698
@staticmethod
699699
async def connect(connstr, # type: str

acouchbase/management/analytics.py

Lines changed: 84 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222
Optional)
2323

2424
from acouchbase.management.logic.analytics_mgmt_impl import AsyncAnalyticsMgmtImpl
25+
from couchbase.logic.observability import ObservableRequestHandler
26+
from couchbase.logic.operation_types import AnalyticsMgmtOperationType
2527
from couchbase.management.logic.analytics_mgmt_types import (AnalyticsDataset,
2628
AnalyticsDataType,
2729
AnalyticsIndex,
2830
AnalyticsLink)
2931

3032
if TYPE_CHECKING:
3133
from acouchbase.logic.client_adapter import AsyncClientAdapter
34+
from couchbase.logic.observability import ObservabilityInstruments
3235
from couchbase.management.options import (ConnectLinkOptions,
3336
CreateAnalyticsIndexOptions,
3437
CreateDatasetOptions,
@@ -48,48 +51,61 @@
4851

4952
class AnalyticsIndexManager:
5053

51-
def __init__(self, client_adapter: AsyncClientAdapter) -> None:
52-
self._impl = AsyncAnalyticsMgmtImpl(client_adapter)
54+
def __init__(self, client_adapter: AsyncClientAdapter, observability_instruments: ObservabilityInstruments) -> None:
55+
self._impl = AsyncAnalyticsMgmtImpl(client_adapter, observability_instruments)
5356

5457
async def create_dataverse(self,
5558
dataverse_name, # type: str
5659
options=None, # type: Optional[CreateDataverseOptions]
5760
**kwargs # type: Any
5861
) -> None:
59-
req = self._impl.request_builder.build_create_dataverse_request(dataverse_name, options, **kwargs)
60-
await self._impl.create_dataverse(req)
62+
op_type = AnalyticsMgmtOperationType.AnalyticsDataverseCreate
63+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
64+
req = self._impl.request_builder.build_create_dataverse_request(
65+
dataverse_name, obs_handler, options, **kwargs)
66+
await self._impl.create_dataverse(req, obs_handler)
6167

6268
async def drop_dataverse(self,
6369
dataverse_name, # type: str
6470
options=None, # type: Optional[DropDataverseOptions]
6571
**kwargs # type: Any
6672
) -> None:
67-
req = self._impl.request_builder.build_drop_dataverse_request(dataverse_name, options, **kwargs)
68-
await self._impl.drop_dataverse(req)
73+
op_type = AnalyticsMgmtOperationType.AnalyticsDataverseDrop
74+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
75+
req = self._impl.request_builder.build_drop_dataverse_request(
76+
dataverse_name, obs_handler, options, **kwargs)
77+
await self._impl.drop_dataverse(req, obs_handler)
6978

7079
async def create_dataset(self,
7180
dataset_name, # type: str
7281
bucket_name, # type: str
7382
options=None, # type: Optional[CreateDatasetOptions]
7483
**kwargs # type: Any
7584
) -> None:
76-
req = self._impl.request_builder.build_create_dataset_request(dataset_name, bucket_name, options, **kwargs)
77-
await self._impl.create_dataset(req)
85+
op_type = AnalyticsMgmtOperationType.AnalyticsDatasetCreate
86+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
87+
req = self._impl.request_builder.build_create_dataset_request(
88+
dataset_name, bucket_name, obs_handler, options, **kwargs)
89+
await self._impl.create_dataset(req, obs_handler)
7890

7991
async def drop_dataset(self,
8092
dataset_name, # type: str
8193
options=None, # type: Optional[DropDatasetOptions]
8294
**kwargs # type: Any
8395
) -> None:
84-
req = self._impl.request_builder.build_drop_dataset_request(dataset_name, options, **kwargs)
85-
await self._impl.drop_dataset(req)
96+
op_type = AnalyticsMgmtOperationType.AnalyticsDatasetDrop
97+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
98+
req = self._impl.request_builder.build_drop_dataset_request(dataset_name, obs_handler, options, **kwargs)
99+
await self._impl.drop_dataset(req, obs_handler)
86100

87101
async def get_all_datasets(self,
88102
options=None, # type: Optional[GetAllDatasetOptions]
89103
**kwargs # type: Any
90104
) -> Iterable[AnalyticsDataset]:
91-
req = self._impl.request_builder.build_get_all_datasets_request(options, **kwargs)
92-
return await self._impl.get_all_datasets(req)
105+
op_type = AnalyticsMgmtOperationType.AnalyticsDatasetGetAll
106+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
107+
req = self._impl.request_builder.build_get_all_datasets_request(obs_handler, options, **kwargs)
108+
return await self._impl.get_all_datasets(req, obs_handler)
93109

94110
async def create_index(self,
95111
index_name, # type: str
@@ -98,81 +114,110 @@ async def create_index(self,
98114
options=None, # type: Optional[CreateAnalyticsIndexOptions]
99115
**kwargs # type: Any
100116
) -> None:
101-
req = self._impl.request_builder.build_create_index_request(index_name,
102-
dataset_name,
103-
fields,
104-
options,
105-
**kwargs)
106-
await self._impl.create_index(req)
117+
op_type = AnalyticsMgmtOperationType.AnalyticsIndexCreate
118+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
119+
req = self._impl.request_builder.build_create_index_request(index_name,
120+
dataset_name,
121+
fields,
122+
obs_handler,
123+
options,
124+
**kwargs)
125+
await self._impl.create_index(req, obs_handler)
107126

108127
async def drop_index(self,
109128
index_name, # type: str
110129
dataset_name, # type: str
111130
options=None, # type: Optional[DropAnalyticsIndexOptions]
112131
**kwargs # type: Any
113132
) -> None:
114-
req = self._impl.request_builder.build_drop_index_request(index_name,
115-
dataset_name,
116-
options,
117-
**kwargs)
118-
await self._impl.drop_index(req)
133+
op_type = AnalyticsMgmtOperationType.AnalyticsIndexDrop
134+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
135+
req = self._impl.request_builder.build_drop_index_request(index_name,
136+
dataset_name,
137+
obs_handler,
138+
options,
139+
**kwargs)
140+
await self._impl.drop_index(req, obs_handler)
119141

120142
async def get_all_indexes(self,
121143
options=None, # type: Optional[GetAllAnalyticsIndexesOptions]
122144
**kwargs # type: Any
123145
) -> Iterable[AnalyticsIndex]:
124-
req = self._impl.request_builder.build_get_all_indexes_request(options, **kwargs)
125-
return await self._impl.get_all_indexes(req)
146+
op_type = AnalyticsMgmtOperationType.AnalyticsIndexGetAll
147+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
148+
req = self._impl.request_builder.build_get_all_indexes_request(obs_handler, options, **kwargs)
149+
return await self._impl.get_all_indexes(req, obs_handler)
126150

127151
async def connect_link(self,
128152
options=None, # type: Optional[ConnectLinkOptions]
129153
**kwargs # type: Any
130154
) -> None:
131-
req = self._impl.request_builder.build_connect_link_request(options, **kwargs)
132-
await self._impl.connect_link(req)
155+
op_type = AnalyticsMgmtOperationType.AnalyticsLinkConnect
156+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
157+
req = self._impl.request_builder.build_connect_link_request(obs_handler, options, **kwargs)
158+
await self._impl.connect_link(req, obs_handler)
133159

134160
async def disconnect_link(self,
135161
options=None, # type: Optional[DisconnectLinkOptions]
136162
**kwargs # type: Any
137163
) -> None:
138-
req = self._impl.request_builder.build_disconnect_link_request(options, **kwargs)
139-
await self._impl.disconnect_link(req)
164+
op_type = AnalyticsMgmtOperationType.AnalyticsLinkDisconnect
165+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
166+
req = self._impl.request_builder.build_disconnect_link_request(obs_handler, options, **kwargs)
167+
await self._impl.disconnect_link(req, obs_handler)
140168

141169
async def get_pending_mutations(self,
142170
options=None, # type: Optional[GetPendingMutationsOptions]
143171
**kwargs # type: Any
144172
) -> Dict[str, int]:
145-
req = self._impl.request_builder.build_get_pending_mutations_request(options, **kwargs)
146-
return await self._impl.get_pending_mutations(req)
173+
op_type = AnalyticsMgmtOperationType.AnalyticsGetPendingMutations
174+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
175+
req = self._impl.request_builder.build_get_pending_mutations_request(obs_handler, options, **kwargs)
176+
return await self._impl.get_pending_mutations(req, obs_handler)
147177

148178
async def create_link(self,
149179
link, # type: AnalyticsLink
150180
options=None, # type: Optional[CreateLinkAnalyticsOptions]
151181
**kwargs # type: Any
152182
) -> None:
153-
req = self._impl.request_builder.build_create_link_request(link, options, **kwargs)
154-
await self._impl.create_link(req)
183+
# We choose AnalyticsLinkCreateCouchbaseRemoteLink arbitrarily b/c the ObservableRequestHandler will
184+
# translate all LinkCreate options in AnalyticsMgmtOperationType to the appropriate op name and
185+
# the request builder will build the appropriate request type based on the link passed in.
186+
op_type = AnalyticsMgmtOperationType.AnalyticsLinkCreateCouchbaseRemoteLink
187+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
188+
req = self._impl.request_builder.build_create_link_request(link, obs_handler, options, **kwargs)
189+
await self._impl.create_link(req, obs_handler)
155190

156191
async def replace_link(self,
157192
link, # type: AnalyticsLink
158193
options=None, # type: Optional[ReplaceLinkAnalyticsOptions]
159194
**kwargs # type: Any
160195
) -> None:
161-
req = self._impl.request_builder.build_replace_link_request(link, options, **kwargs)
162-
await self._impl.replace_link(req)
196+
# We choose AnalyticsLinkReplaceCouchbaseRemoteLink arbitrarily b/c the ObservableRequestHandler will
197+
# translate all LinkReplace options in AnalyticsMgmtOperationType to the appropriate op name and
198+
# the request builder will build the appropriate request type based on the link passed in.
199+
op_type = AnalyticsMgmtOperationType.AnalyticsLinkReplaceCouchbaseRemoteLink
200+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
201+
req = self._impl.request_builder.build_replace_link_request(link, obs_handler, options, **kwargs)
202+
await self._impl.replace_link(req, obs_handler)
163203

164204
async def drop_link(self,
165205
link_name, # type: str
166206
dataverse_name, # type: str
167207
options=None, # type: Optional[DropLinkAnalyticsOptions]
168208
**kwargs # type: Any
169209
) -> None:
170-
req = self._impl.request_builder.build_drop_link_request(link_name, dataverse_name, options, **kwargs)
171-
await self._impl.drop_link(req)
210+
op_type = AnalyticsMgmtOperationType.AnalyticsLinkDrop
211+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
212+
req = self._impl.request_builder.build_drop_link_request(
213+
link_name, dataverse_name, obs_handler, options, **kwargs)
214+
await self._impl.drop_link(req, obs_handler)
172215

173216
async def get_links(self,
174217
options=None, # type: Optional[GetLinksAnalyticsOptions]
175218
**kwargs # type: Any
176219
) -> Iterable[AnalyticsLink]:
177-
req = self._impl.request_builder.build_get_links_request(options, **kwargs)
178-
return await self._impl.get_links(req)
220+
op_type = AnalyticsMgmtOperationType.AnalyticsLinkGetAll
221+
async with ObservableRequestHandler(op_type, self._impl.observability_instruments) as obs_handler:
222+
req = self._impl.request_builder.build_get_links_request(obs_handler, options, **kwargs)
223+
return await self._impl.get_links(req, obs_handler)

0 commit comments

Comments
 (0)