grpcio-observability 1.71.0__cp310-cp310-musllinux_1_1_aarch64.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.
- grpc_observability/__init__.py +17 -0
- grpc_observability/_cyobservability.cpython-310-aarch64-linux-gnu.so +0 -0
- grpc_observability/_measures.py +91 -0
- grpc_observability/_observability.py +119 -0
- grpc_observability/_observability_config.py +129 -0
- grpc_observability/_open_census_exporter.py +301 -0
- grpc_observability/_open_telemetry_measures.py +98 -0
- grpc_observability/_open_telemetry_observability.py +525 -0
- grpc_observability/_open_telemetry_plugin.py +171 -0
- grpc_observability/_views.py +287 -0
- grpcio_observability-1.71.0.dist-info/LICENSE +610 -0
- grpcio_observability-1.71.0.dist-info/METADATA +109 -0
- grpcio_observability-1.71.0.dist-info/RECORD +15 -0
- grpcio_observability-1.71.0.dist-info/WHEEL +5 -0
- grpcio_observability-1.71.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
# Copyright 2023 gRPC authors.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from typing import AnyStr, Callable, Dict, Iterable, List, Optional
|
16
|
+
|
17
|
+
# pytype: disable=pyi-error
|
18
|
+
from grpc_observability import _open_telemetry_observability
|
19
|
+
from grpc_observability._observability import OptionalLabelType
|
20
|
+
from opentelemetry.metrics import MeterProvider
|
21
|
+
|
22
|
+
GRPC_METHOD_LABEL = "grpc.method"
|
23
|
+
GRPC_TARGET_LABEL = "grpc.target"
|
24
|
+
GRPC_CLIENT_METRIC_PREFIX = "grpc.client"
|
25
|
+
GRPC_OTHER_LABEL_VALUE = "other"
|
26
|
+
|
27
|
+
|
28
|
+
class OpenTelemetryLabelInjector:
|
29
|
+
"""
|
30
|
+
An interface that allows you to add additional labels on the calls traced.
|
31
|
+
"""
|
32
|
+
|
33
|
+
def get_labels_for_exchange(self) -> Dict[str, AnyStr]:
|
34
|
+
"""
|
35
|
+
Get labels used for metadata exchange.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
A dict of labels, with a string as key representing label name, string or bytes
|
39
|
+
as value representing label value.
|
40
|
+
"""
|
41
|
+
raise NotImplementedError()
|
42
|
+
|
43
|
+
def get_additional_labels(
|
44
|
+
self, include_exchange_labels: bool
|
45
|
+
) -> Dict[str, str]:
|
46
|
+
"""
|
47
|
+
Get additional labels added by this injector.
|
48
|
+
|
49
|
+
The return value from this method will be added directly to metric data.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
include_exchange_labels: Whether to add additional metadata exchange related labels.
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
A dict of labels.
|
56
|
+
"""
|
57
|
+
raise NotImplementedError()
|
58
|
+
|
59
|
+
# pylint: disable=no-self-use
|
60
|
+
def deserialize_labels(
|
61
|
+
self, labels: Dict[str, AnyStr]
|
62
|
+
) -> Dict[str, AnyStr]:
|
63
|
+
"""
|
64
|
+
Deserialize the labels if required.
|
65
|
+
|
66
|
+
If this injector added labels for metadata exchange, this method will be called to
|
67
|
+
deserialize the exchanged labels.
|
68
|
+
|
69
|
+
For example, if this injector added xds_peer_metadata_label for exchange:
|
70
|
+
|
71
|
+
labels: {"labelA": b"valueA", "xds_peer_metadata_label": b"exchanged_bytes"}
|
72
|
+
|
73
|
+
This method should deserialize xds_peer_metadata_label and return labels as:
|
74
|
+
|
75
|
+
labels: {"labelA": b"valueA", "xds_label_A": "xds_label_A",
|
76
|
+
"xds_label_B": "xds_label_B"}
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
A dict of deserialized labels.
|
80
|
+
"""
|
81
|
+
return labels
|
82
|
+
|
83
|
+
|
84
|
+
class OpenTelemetryPluginOption:
|
85
|
+
"""
|
86
|
+
An interface that allows you to add additional function to OpenTelemetryPlugin.
|
87
|
+
"""
|
88
|
+
|
89
|
+
|
90
|
+
# pylint: disable=no-self-use
|
91
|
+
class OpenTelemetryPlugin:
|
92
|
+
"""Describes a Plugin for OpenTelemetry observability."""
|
93
|
+
|
94
|
+
plugin_options: Iterable[OpenTelemetryPluginOption]
|
95
|
+
meter_provider: Optional[MeterProvider]
|
96
|
+
target_attribute_filter: Callable[[str], bool]
|
97
|
+
generic_method_attribute_filter: Callable[[str], bool]
|
98
|
+
_plugins: List[_open_telemetry_observability._OpenTelemetryPlugin]
|
99
|
+
|
100
|
+
def __init__(
|
101
|
+
self,
|
102
|
+
*,
|
103
|
+
plugin_options: Iterable[OpenTelemetryPluginOption] = [],
|
104
|
+
meter_provider: Optional[MeterProvider] = None,
|
105
|
+
target_attribute_filter: Optional[Callable[[str], bool]] = None,
|
106
|
+
generic_method_attribute_filter: Optional[Callable[[str], bool]] = None,
|
107
|
+
):
|
108
|
+
"""
|
109
|
+
Args:
|
110
|
+
plugin_options: An Iterable of OpenTelemetryPluginOption which will be
|
111
|
+
enabled for this OpenTelemetryPlugin.
|
112
|
+
meter_provider: A MeterProvider which will be used to collect telemetry data,
|
113
|
+
or None which means no metrics will be collected.
|
114
|
+
target_attribute_filter: [DEPRECATED] This attribute is deprecated and should
|
115
|
+
not be used.
|
116
|
+
Once provided, this will be called per channel to decide whether to record the
|
117
|
+
target attribute on client or to replace it with "other".
|
118
|
+
This helps reduce the cardinality on metrics in cases where many channels
|
119
|
+
are created with different targets in the same binary (which might happen
|
120
|
+
for example, if the channel target string uses IP addresses directly).
|
121
|
+
Return True means the original target string will be used, False means target string
|
122
|
+
will be replaced with "other".
|
123
|
+
generic_method_attribute_filter: Once provided, this will be called with a generic
|
124
|
+
method type to decide whether to record the method name or to replace it with
|
125
|
+
"other". Note that pre-registered methods will always be recorded no matter what
|
126
|
+
this function returns.
|
127
|
+
Return True means the original method name will be used, False means method name will
|
128
|
+
be replaced with "other".
|
129
|
+
"""
|
130
|
+
self.plugin_options = plugin_options
|
131
|
+
self.meter_provider = meter_provider
|
132
|
+
self.target_attribute_filter = target_attribute_filter or (
|
133
|
+
lambda target: True
|
134
|
+
)
|
135
|
+
self.generic_method_attribute_filter = (
|
136
|
+
generic_method_attribute_filter or (lambda target: False)
|
137
|
+
)
|
138
|
+
self._plugins = [
|
139
|
+
_open_telemetry_observability._OpenTelemetryPlugin(self)
|
140
|
+
]
|
141
|
+
|
142
|
+
def register_global(self) -> None:
|
143
|
+
"""
|
144
|
+
Registers a global plugin that acts on all channels and servers running on the process.
|
145
|
+
|
146
|
+
Raises:
|
147
|
+
RuntimeError: If a global plugin was already registered.
|
148
|
+
"""
|
149
|
+
_open_telemetry_observability.start_open_telemetry_observability(
|
150
|
+
plugins=self._plugins
|
151
|
+
)
|
152
|
+
|
153
|
+
def deregister_global(self) -> None:
|
154
|
+
"""
|
155
|
+
De-register the global plugin that acts on all channels and servers running on the process.
|
156
|
+
|
157
|
+
Raises:
|
158
|
+
RuntimeError: If no global plugin was registered.
|
159
|
+
"""
|
160
|
+
_open_telemetry_observability.end_open_telemetry_observability()
|
161
|
+
|
162
|
+
def __enter__(self) -> None:
|
163
|
+
_open_telemetry_observability.start_open_telemetry_observability(
|
164
|
+
plugins=self._plugins
|
165
|
+
)
|
166
|
+
|
167
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
168
|
+
_open_telemetry_observability.end_open_telemetry_observability()
|
169
|
+
|
170
|
+
def _get_enabled_optional_labels(self) -> List[OptionalLabelType]:
|
171
|
+
return []
|
@@ -0,0 +1,287 @@
|
|
1
|
+
# Copyright 2023 gRPC authors.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from typing import Mapping
|
16
|
+
|
17
|
+
from grpc_observability import _measures
|
18
|
+
from grpc_observability._cyobservability import MetricsName
|
19
|
+
from opencensus.stats import aggregation
|
20
|
+
from opencensus.stats import view as view_module
|
21
|
+
from opencensus.tags.tag_key import TagKey
|
22
|
+
|
23
|
+
METRICS_NAME_TO_MEASURE = {
|
24
|
+
MetricsName.CLIENT_STARTED_RPCS: _measures.CLIENT_STARTED_RPCS_MEASURE,
|
25
|
+
MetricsName.CLIENT_ROUNDTRIP_LATENCY: _measures.CLIENT_ROUNDTRIP_LATENCY_MEASURE,
|
26
|
+
MetricsName.CLIENT_COMPLETED_RPC: _measures.CLIENT_COMPLETED_RPCS_MEASURE,
|
27
|
+
MetricsName.CLIENT_API_LATENCY: _measures.CLIENT_API_LATENCY_MEASURE,
|
28
|
+
MetricsName.CLIENT_SEND_BYTES_PER_RPC: _measures.CLIENT_SEND_BYTES_PER_RPC_MEASURE,
|
29
|
+
MetricsName.CLIENT_RECEIVED_BYTES_PER_RPC: _measures.CLIENT_RECEIVED_BYTES_PER_RPC_MEASURE,
|
30
|
+
MetricsName.SERVER_STARTED_RPCS: _measures.SERVER_STARTED_RPCS_MEASURE,
|
31
|
+
MetricsName.SERVER_SENT_BYTES_PER_RPC: _measures.SERVER_SENT_BYTES_PER_RPC_MEASURE,
|
32
|
+
MetricsName.SERVER_RECEIVED_BYTES_PER_RPC: _measures.SERVER_RECEIVED_BYTES_PER_RPC_MEASURE,
|
33
|
+
MetricsName.SERVER_SERVER_LATENCY: _measures.SERVER_SERVER_LATENCY_MEASURE,
|
34
|
+
MetricsName.SERVER_COMPLETED_RPC: _measures.SERVER_COMPLETED_RPCS_MEASURE,
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
# These measure definitions should be kept in sync across opencensus
|
39
|
+
# implementations--see
|
40
|
+
# https://github.com/census-instrumentation/opencensus-java/blob/master/contrib/grpc_metrics/src/main/java/io/opencensus/contrib/grpc/metrics/RpcMeasureConstants.java.
|
41
|
+
def client_method_tag_key():
|
42
|
+
return TagKey("grpc_client_method")
|
43
|
+
|
44
|
+
|
45
|
+
def client_status_tag_key():
|
46
|
+
return TagKey("grpc_client_status")
|
47
|
+
|
48
|
+
|
49
|
+
def server_method_tag_key():
|
50
|
+
return TagKey("grpc_server_method")
|
51
|
+
|
52
|
+
|
53
|
+
def server_status_tag_key():
|
54
|
+
return TagKey("server_status_tag_key")
|
55
|
+
|
56
|
+
|
57
|
+
def count_distribution_aggregation() -> aggregation.DistributionAggregation:
|
58
|
+
exponential_boundaries = _get_exponential_boundaries(17, 1.0, 2.0)
|
59
|
+
return aggregation.DistributionAggregation(exponential_boundaries)
|
60
|
+
|
61
|
+
|
62
|
+
def bytes_distribution_aggregation() -> aggregation.DistributionAggregation:
|
63
|
+
return aggregation.DistributionAggregation(
|
64
|
+
[
|
65
|
+
1024,
|
66
|
+
2048,
|
67
|
+
4096,
|
68
|
+
16384,
|
69
|
+
65536,
|
70
|
+
262144,
|
71
|
+
1048576,
|
72
|
+
4194304,
|
73
|
+
16777216,
|
74
|
+
67108864,
|
75
|
+
268435456,
|
76
|
+
1073741824,
|
77
|
+
4294967296,
|
78
|
+
]
|
79
|
+
)
|
80
|
+
|
81
|
+
|
82
|
+
def millis_distribution_aggregation() -> aggregation.DistributionAggregation:
|
83
|
+
return aggregation.DistributionAggregation(
|
84
|
+
[
|
85
|
+
0.01,
|
86
|
+
0.05,
|
87
|
+
0.1,
|
88
|
+
0.3,
|
89
|
+
0.6,
|
90
|
+
0.8,
|
91
|
+
1,
|
92
|
+
2,
|
93
|
+
3,
|
94
|
+
4,
|
95
|
+
5,
|
96
|
+
6,
|
97
|
+
8,
|
98
|
+
10,
|
99
|
+
13,
|
100
|
+
16,
|
101
|
+
20,
|
102
|
+
25,
|
103
|
+
30,
|
104
|
+
40,
|
105
|
+
50,
|
106
|
+
65,
|
107
|
+
80,
|
108
|
+
100,
|
109
|
+
130,
|
110
|
+
160,
|
111
|
+
200,
|
112
|
+
250,
|
113
|
+
300,
|
114
|
+
400,
|
115
|
+
500,
|
116
|
+
650,
|
117
|
+
800,
|
118
|
+
1000,
|
119
|
+
2000,
|
120
|
+
5000,
|
121
|
+
10000,
|
122
|
+
20000,
|
123
|
+
50000,
|
124
|
+
100000,
|
125
|
+
]
|
126
|
+
)
|
127
|
+
|
128
|
+
|
129
|
+
# Client
|
130
|
+
def client_started_rpcs(labels: Mapping[str, str]) -> view_module.View:
|
131
|
+
view = view_module.View(
|
132
|
+
"grpc.io/client/started_rpcs",
|
133
|
+
"The count of RPCs ever received at the server, including RPCs"
|
134
|
+
+ " that have not completed.",
|
135
|
+
[TagKey(key) for key in labels.keys()] + [client_method_tag_key()],
|
136
|
+
_measures.CLIENT_STARTED_RPCS_MEASURE,
|
137
|
+
aggregation.CountAggregation(),
|
138
|
+
)
|
139
|
+
return view
|
140
|
+
|
141
|
+
|
142
|
+
def client_completed_rpcs(labels: Mapping[str, str]) -> view_module.View:
|
143
|
+
view = view_module.View(
|
144
|
+
"grpc.io/client/completed_rpcs",
|
145
|
+
"The total count of RPCs completed, for example, when a response"
|
146
|
+
+ " is sent by the server.",
|
147
|
+
[TagKey(key) for key in labels.keys()]
|
148
|
+
+ [client_method_tag_key(), client_status_tag_key()],
|
149
|
+
_measures.CLIENT_COMPLETED_RPCS_MEASURE,
|
150
|
+
aggregation.CountAggregation(),
|
151
|
+
)
|
152
|
+
return view
|
153
|
+
|
154
|
+
|
155
|
+
def client_roundtrip_latency(labels: Mapping[str, str]) -> view_module.View:
|
156
|
+
view = view_module.View(
|
157
|
+
"grpc.io/client/roundtrip_latency",
|
158
|
+
"End-to-end time taken to complete an RPC attempt including the time"
|
159
|
+
+ " it takes to pick a subchannel.",
|
160
|
+
[TagKey(key) for key in labels.keys()] + [client_method_tag_key()],
|
161
|
+
_measures.CLIENT_ROUNDTRIP_LATENCY_MEASURE,
|
162
|
+
millis_distribution_aggregation(),
|
163
|
+
)
|
164
|
+
return view
|
165
|
+
|
166
|
+
|
167
|
+
def client_api_latency(labels: Mapping[str, str]) -> view_module.View:
|
168
|
+
view = view_module.View(
|
169
|
+
"grpc.io/client/api_latency",
|
170
|
+
"The total time taken by the gRPC library to complete an RPC from"
|
171
|
+
+ " the application's perspective.",
|
172
|
+
[TagKey(key) for key in labels.keys()]
|
173
|
+
+ [client_method_tag_key(), client_status_tag_key()],
|
174
|
+
_measures.CLIENT_API_LATENCY_MEASURE,
|
175
|
+
millis_distribution_aggregation(),
|
176
|
+
)
|
177
|
+
return view
|
178
|
+
|
179
|
+
|
180
|
+
def client_sent_compressed_message_bytes_per_rpc(
|
181
|
+
labels: Mapping[str, str]
|
182
|
+
) -> view_module.View:
|
183
|
+
view = view_module.View(
|
184
|
+
"grpc.io/client/sent_compressed_message_bytes_per_rpc",
|
185
|
+
"The total bytes (compressed, not encrypted) sent across all"
|
186
|
+
+ " request messages per RPC attempt.",
|
187
|
+
[TagKey(key) for key in labels.keys()]
|
188
|
+
+ [client_method_tag_key(), client_status_tag_key()],
|
189
|
+
_measures.CLIENT_SEND_BYTES_PER_RPC_MEASURE,
|
190
|
+
bytes_distribution_aggregation(),
|
191
|
+
)
|
192
|
+
return view
|
193
|
+
|
194
|
+
|
195
|
+
def client_received_compressed_message_bytes_per_rpc(
|
196
|
+
labels: Mapping[str, str]
|
197
|
+
) -> view_module.View:
|
198
|
+
view = view_module.View(
|
199
|
+
"grpc.io/client/received_compressed_message_bytes_per_rpc",
|
200
|
+
"The total bytes (compressed, not encrypted) received across"
|
201
|
+
+ " all response messages per RPC attempt.",
|
202
|
+
[TagKey(key) for key in labels.keys()]
|
203
|
+
+ [client_method_tag_key(), client_status_tag_key()],
|
204
|
+
_measures.CLIENT_RECEIVED_BYTES_PER_RPC_MEASURE,
|
205
|
+
bytes_distribution_aggregation(),
|
206
|
+
)
|
207
|
+
return view
|
208
|
+
|
209
|
+
|
210
|
+
# Server
|
211
|
+
def server_started_rpcs(labels: Mapping[str, str]) -> view_module.View:
|
212
|
+
view = view_module.View(
|
213
|
+
"grpc.io/server/started_rpcs",
|
214
|
+
"The count of RPCs ever received at the server, including RPCs"
|
215
|
+
+ " that have not completed.",
|
216
|
+
[TagKey(key) for key in labels.keys()] + [server_method_tag_key()],
|
217
|
+
_measures.SERVER_STARTED_RPCS_MEASURE,
|
218
|
+
aggregation.CountAggregation(),
|
219
|
+
)
|
220
|
+
return view
|
221
|
+
|
222
|
+
|
223
|
+
def server_completed_rpcs(labels: Mapping[str, str]) -> view_module.View:
|
224
|
+
view = view_module.View(
|
225
|
+
"grpc.io/server/completed_rpcs",
|
226
|
+
"The total count of RPCs completed, for example, when a response"
|
227
|
+
+ " is sent by the server.",
|
228
|
+
[TagKey(key) for key in labels.keys()]
|
229
|
+
+ [server_method_tag_key(), server_status_tag_key()],
|
230
|
+
_measures.SERVER_COMPLETED_RPCS_MEASURE,
|
231
|
+
aggregation.CountAggregation(),
|
232
|
+
)
|
233
|
+
return view
|
234
|
+
|
235
|
+
|
236
|
+
def server_sent_compressed_message_bytes_per_rpc(
|
237
|
+
labels: Mapping[str, str]
|
238
|
+
) -> view_module.View:
|
239
|
+
view = view_module.View(
|
240
|
+
"grpc.io/server/sent_compressed_message_bytes_per_rpc",
|
241
|
+
"The total bytes (compressed not encrypted) sent across all response"
|
242
|
+
+ " messages per RPC.",
|
243
|
+
[TagKey(key) for key in labels.keys()]
|
244
|
+
+ [server_method_tag_key(), server_status_tag_key()],
|
245
|
+
_measures.SERVER_SENT_BYTES_PER_RPC_MEASURE,
|
246
|
+
bytes_distribution_aggregation(),
|
247
|
+
)
|
248
|
+
return view
|
249
|
+
|
250
|
+
|
251
|
+
def server_received_compressed_message_bytes_per_rpc(
|
252
|
+
labels: Mapping[str, str]
|
253
|
+
) -> view_module.View:
|
254
|
+
view = view_module.View(
|
255
|
+
"grpc.io/server/received_compressed_message_bytes_per_rpc",
|
256
|
+
"The total bytes (compressed not encrypted) received across all"
|
257
|
+
+ " request messages per RPC.",
|
258
|
+
[TagKey(key) for key in labels.keys()]
|
259
|
+
+ [server_method_tag_key(), server_status_tag_key()],
|
260
|
+
_measures.SERVER_RECEIVED_BYTES_PER_RPC_MEASURE,
|
261
|
+
bytes_distribution_aggregation(),
|
262
|
+
)
|
263
|
+
return view
|
264
|
+
|
265
|
+
|
266
|
+
def server_server_latency(labels: Mapping[str, str]) -> view_module.View:
|
267
|
+
view = view_module.View(
|
268
|
+
"grpc.io/server/server_latency",
|
269
|
+
"The total time taken by an RPC from server transport's"
|
270
|
+
+ " (HTTP2 / inproc / cronet) perspective.",
|
271
|
+
[TagKey(key) for key in labels.keys()]
|
272
|
+
+ [server_method_tag_key(), server_status_tag_key()],
|
273
|
+
_measures.SERVER_SERVER_LATENCY_MEASURE,
|
274
|
+
millis_distribution_aggregation(),
|
275
|
+
)
|
276
|
+
return view
|
277
|
+
|
278
|
+
|
279
|
+
def _get_exponential_boundaries(
|
280
|
+
num_finite_buckets: int, scale: float, grrowth_factor: float
|
281
|
+
) -> list:
|
282
|
+
boundaries = []
|
283
|
+
upper_bound = scale
|
284
|
+
for _ in range(num_finite_buckets):
|
285
|
+
boundaries.append(upper_bound)
|
286
|
+
upper_bound *= grrowth_factor
|
287
|
+
return boundaries
|