kinto 21.1.1__py3-none-any.whl → 23.0.0__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.

Potentially problematic release.


This version of kinto might be problematic. Click here for more details.

@@ -510,17 +510,16 @@ def setup_metrics(config):
510
510
  request_labels = [
511
511
  ("method", request.method.lower()),
512
512
  ("endpoint", endpoint),
513
- ("status", str(status)),
514
513
  ] + metrics_matchdict_labels
515
514
 
516
515
  # Count served requests.
517
- metrics_service.count("request_summary", unique=request_labels)
516
+ metrics_service.count("request_summary", unique=request_labels + [("status", str(status))])
518
517
 
519
518
  try:
520
519
  current = utils.msec_time()
521
520
  duration = current - request._received_at
522
521
  metrics_service.timer(
523
- "request_duration",
522
+ "request_duration_seconds",
524
523
  value=duration,
525
524
  labels=request_labels,
526
525
  )
kinto/core/metrics.py CHANGED
@@ -13,7 +13,7 @@ class IMetricsService(Interface):
13
13
 
14
14
  def timer(key):
15
15
  """
16
- Watch execution time.
16
+ Watch execution time in seconds.
17
17
  """
18
18
 
19
19
  def observe(self, key, value, labels=[]):
@@ -68,9 +68,9 @@ def watch_execution_time(metrics_service, obj, prefix="", classname=None):
68
68
  method = getattr(obj, name)
69
69
  is_method = isinstance(method, types.MethodType)
70
70
  if not name.startswith("_") and is_method:
71
- statsd_key = f"{prefix}.{classname}"
71
+ metric_name = f"{prefix}.{classname}.seconds"
72
72
  labels = [("method", name)]
73
- decorated_method = metrics_service.timer(statsd_key, labels=labels)(method)
73
+ decorated_method = metrics_service.timer(metric_name, labels=labels)(method)
74
74
  setattr(obj, name, decorated_method)
75
75
 
76
76
 
@@ -88,7 +88,7 @@ def listener_with_timer(config, key, func):
88
88
  # not listed in the `initialization_sequence` setting.
89
89
  return func(*args, **kwargs)
90
90
  # If metrics are enabled, monitor execution time of listeners.
91
- with metrics_service.timer(key):
91
+ with metrics_service.timer(key + ".seconds" if not key.endswith(".seconds") else key):
92
92
  return func(*args, **kwargs)
93
93
 
94
94
  return wrapped
@@ -53,7 +53,7 @@ class Timer:
53
53
  """
54
54
  A decorator to time the execution of a function. It will use the
55
55
  `prometheus_client.Histogram` to record the time taken by the function
56
- in milliseconds. The histogram is passed as an argument to the
56
+ in seconds. The histogram is passed as an argument to the
57
57
  constructor.
58
58
 
59
59
  Main limitation: it does not support `labels` on the decorator.
@@ -78,8 +78,8 @@ class Timer:
78
78
  try:
79
79
  return f(*args, **kwargs)
80
80
  finally:
81
- dt_ms = 1000.0 * (time_now() - start_time)
82
- self.histogram.observe(dt_ms)
81
+ dt_sec = time_now() - start_time
82
+ self.histogram.observe(dt_sec)
83
83
 
84
84
  return _wrapped
85
85
 
@@ -96,14 +96,22 @@ class Timer:
96
96
  def stop(self):
97
97
  if self._start_time is None: # pragma: nocover
98
98
  raise RuntimeError("Timer has not started.")
99
- dt_ms = 1000.0 * (time_now() - self._start_time)
100
- self.histogram.observe(dt_ms)
99
+ dt_sec = time_now() - self._start_time
100
+ self.histogram.observe(dt_sec)
101
+ return self
102
+
103
+
104
+ class NoOpHistogram: # pragma: no cover
105
+ def observe(self, value):
106
+ pass
107
+
108
+ def labels(self, *args):
101
109
  return self
102
110
 
103
111
 
104
112
  @implementer(metrics.IMetricsService)
105
113
  class PrometheusService:
106
- def __init__(self, prefix="", exclude_labels=None):
114
+ def __init__(self, prefix="", disabled_metrics=[], histogram_buckets=None):
107
115
  prefix_clean = ""
108
116
  if prefix:
109
117
  # In GCP Console, the metrics are grouped by the first
@@ -112,26 +120,23 @@ class PrometheusService:
112
120
  # (eg. `remote-settings` -> `remotesettings_`, `kinto_` -> `kinto_`)
113
121
  prefix_clean = _fix_metric_name(prefix).replace("_", "") + "_"
114
122
  self.prefix = prefix_clean.lower()
115
- self.exclude_labels = exclude_labels or []
116
-
117
- def _exclude_labels(self, labels):
118
- return [
119
- (label_name, label_value)
120
- for label_name, label_value in labels
121
- if label_name not in self.exclude_labels
122
- ]
123
+ self.disabled_metrics = [m.replace(self.prefix, "") for m in disabled_metrics]
124
+ self.histogram_buckets = histogram_buckets
123
125
 
124
126
  def timer(self, key, value=None, labels=[]):
125
127
  global _METRICS
126
- key = self.prefix + key
127
- labels = self._exclude_labels(labels)
128
128
 
129
+ key = _fix_metric_name(key)
130
+ if key in self.disabled_metrics:
131
+ return Timer(histogram=NoOpHistogram())
132
+
133
+ key = self.prefix + key
129
134
  if key not in _METRICS:
130
135
  _METRICS[key] = prometheus_module.Histogram(
131
- _fix_metric_name(key),
136
+ key,
132
137
  f"Histogram of {key}",
133
- registry=get_registry(),
134
138
  labelnames=[label_name for label_name, _ in labels],
139
+ buckets=self.histogram_buckets,
135
140
  )
136
141
 
137
142
  if not isinstance(_METRICS[key], prometheus_module.Histogram):
@@ -139,7 +144,7 @@ class PrometheusService:
139
144
  f"Metric {key} already exists with different type ({_METRICS[key]})"
140
145
  )
141
146
 
142
- timer = Timer(_METRICS[key])
147
+ timer = Timer(histogram=_METRICS[key])
143
148
  timer.set_labels(labels)
144
149
 
145
150
  if value is not None:
@@ -153,15 +158,17 @@ class PrometheusService:
153
158
 
154
159
  def observe(self, key, value, labels=[]):
155
160
  global _METRICS
156
- key = self.prefix + key
157
- labels = self._exclude_labels(labels)
158
161
 
162
+ key = _fix_metric_name(key)
163
+ if key in self.disabled_metrics:
164
+ return
165
+
166
+ key = self.prefix + key
159
167
  if key not in _METRICS:
160
168
  _METRICS[key] = prometheus_module.Summary(
161
- _fix_metric_name(key),
169
+ key,
162
170
  f"Summary of {key}",
163
171
  labelnames=[label_name for label_name, _ in labels],
164
- registry=get_registry(),
165
172
  )
166
173
 
167
174
  if not isinstance(_METRICS[key], prometheus_module.Summary):
@@ -177,10 +184,12 @@ class PrometheusService:
177
184
 
178
185
  def count(self, key, count=1, unique=None):
179
186
  global _METRICS
180
- key = self.prefix + key
181
187
 
182
- labels = []
188
+ key = _fix_metric_name(key)
189
+ if key in self.disabled_metrics:
190
+ return
183
191
 
192
+ labels = []
184
193
  if unique:
185
194
  if isinstance(unique, str):
186
195
  warnings.warn(
@@ -195,17 +204,16 @@ class PrometheusService:
195
204
  label_name, label_value = unique.rsplit(".", 1)
196
205
  unique = [(label_name, label_value)]
197
206
 
198
- unique = self._exclude_labels(unique)
199
207
  labels = [
200
208
  (_fix_metric_name(label_name), label_value) for label_name, label_value in unique
201
209
  ]
202
210
 
211
+ key = self.prefix + key
203
212
  if key not in _METRICS:
204
213
  _METRICS[key] = prometheus_module.Counter(
205
- _fix_metric_name(key),
214
+ key,
206
215
  f"Counter of {key}",
207
216
  labelnames=[label_name for label_name, _ in labels],
208
- registry=get_registry(),
209
217
  )
210
218
 
211
219
  if not isinstance(_METRICS[key], prometheus_module.Counter):
@@ -234,6 +242,19 @@ def _reset_multiproc_folder_content(): # pragma: no cover
234
242
  os.makedirs(PROMETHEUS_MULTIPROC_DIR, exist_ok=True)
235
243
 
236
244
 
245
+ def reset_registry():
246
+ # This is mainly useful in tests, where the plugin is included
247
+ # several times with different settings.
248
+ registry = get_registry()
249
+
250
+ for collector in _METRICS.values():
251
+ try:
252
+ registry.unregister(collector)
253
+ except KeyError: # pragma: no cover
254
+ pass
255
+ _METRICS.clear()
256
+
257
+
237
258
  def includeme(config):
238
259
  if prometheus_module is None:
239
260
  error_msg = (
@@ -246,34 +267,34 @@ def includeme(config):
246
267
  if not asbool(settings.get("prometheus_created_metrics_enabled", True)):
247
268
  prometheus_module.disable_created_metrics()
248
269
 
270
+ prefix = settings.get("prometheus_prefix", settings["project_name"])
271
+ disabled_metrics = aslist(settings.get("prometheus_disabled_metrics", ""))
272
+
273
+ # Default buckets for histogram metrics are (.005, .01, .025, .05, .075, .1, .25, .5, .75, 1.0, 2.5, 5.0, 7.5, 10.0, INF)
274
+ # we reduce it from 15 to 8 values by default here, and let the user override it if needed.
275
+ histogram_buckets_values = aslist(
276
+ settings.get(
277
+ "prometheus_histogram_buckets", "0.01 0.05 0.1 0.5 1.0 3.0 6.0 Inf"
278
+ ) # Note: Inf is added by default.
279
+ )
280
+ histogram_buckets = [float(x) for x in histogram_buckets_values]
281
+ # Note: we don't need to check for INF or list size, it's done in the prometheus_client library.
282
+
283
+ get_registry() # Initialize the registry.
284
+
285
+ metrics_impl = PrometheusService(
286
+ prefix=prefix, disabled_metrics=disabled_metrics, histogram_buckets=histogram_buckets
287
+ )
288
+
249
289
  config.add_api_capability(
250
290
  "prometheus",
251
291
  description="Prometheus metrics.",
252
292
  url="https://github.com/Kinto/kinto/",
293
+ prefix=metrics_impl.prefix,
294
+ disabled_metrics=disabled_metrics,
253
295
  )
254
296
 
255
297
  config.add_route("prometheus_metrics", "/__metrics__")
256
298
  config.add_view(metrics_view, route_name="prometheus_metrics")
257
299
 
258
- # Reinitialize the registry on initialization.
259
- # This is mainly useful in tests, where the plugin is included
260
- # several times with different settings.
261
- registry = get_registry()
262
-
263
- for collector in _METRICS.values():
264
- try:
265
- registry.unregister(collector)
266
- except KeyError: # pragma: no cover
267
- pass
268
- _METRICS.clear()
269
-
270
- prefix = settings.get("prometheus_prefix", settings["project_name"])
271
-
272
- # If we want to reduce the metrics cardinality, we can exclude certain
273
- # labels (eg. records_id). This way all metrics will be grouped by the
274
- # remaining labels.
275
- exclude_labels = aslist(settings.get("prometheus_exclude_labels", ""))
276
-
277
- config.registry.registerUtility(
278
- PrometheusService(prefix=prefix, exclude_labels=exclude_labels), metrics.IMetricsService
279
- )
300
+ config.registry.registerUtility(metrics_impl, metrics.IMetricsService)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kinto
3
- Version: 21.1.1
3
+ Version: 23.0.0
4
4
  Summary: Kinto Web Service - Store, Sync, Share, and Self-Host.
5
5
  Author-email: Mozilla Services <developers@kinto-storage.org>
6
6
  License: Copyright 2012 - Mozilla Foundation
@@ -70,6 +70,7 @@ Provides-Extra: dev
70
70
  Requires-Dist: build; extra == "dev"
71
71
  Requires-Dist: ruff; extra == "dev"
72
72
  Requires-Dist: twine; extra == "dev"
73
+ Requires-Dist: uwsgi; extra == "dev"
73
74
  Dynamic: license-file
74
75
 
75
76
  Kinto
@@ -12,8 +12,8 @@ kinto/core/authorization.py,sha256=GywY25KEzuSSAI709dFHDfdLnKxy3SLEYGwW5FkQ7Qc,1
12
12
  kinto/core/decorators.py,sha256=3SAPWXlyPNUSICZ9mz04bcN-UdbnDuFOtU0bQHHzLis,2178
13
13
  kinto/core/errors.py,sha256=JXZjkPYjjC0I6x02d2VJRGeaQ2yZYS2zm5o7_ljfyes,8946
14
14
  kinto/core/events.py,sha256=SYpXgKMtVjiD9fwYJA2Omdom9yA3nBqi9btdvU1I_nc,10345
15
- kinto/core/initialization.py,sha256=OMnwre6roy_JkOCA0wf47wUJv7erxOfACI9CT78tD5k,26329
16
- kinto/core/metrics.py,sha256=h582cAZawzgJ9AL16t1ScgyVi0trXoJx-6147Ig-Vns,2693
15
+ kinto/core/initialization.py,sha256=sK_YSg6OcqCEIPAH--aiTnMD0ztV_90gkpxUI4v1LiM,26328
16
+ kinto/core/metrics.py,sha256=wlTThw_pSESrgwJfGdVBcM3r0b09gleZV4aSiu5pWq8,2768
17
17
  kinto/core/openapi.py,sha256=92sZviff4NCxN0jMnu5lPUnF5iQbrKMGy7Cegf-VAME,3876
18
18
  kinto/core/schema.py,sha256=d5L5TQynRYJPkZ8Mu2X7F72xEh6SKDbrHK1CNTdOf2E,3646
19
19
  kinto/core/scripts.py,sha256=02SXVjo579W82AsDF8dyVCRxYVcrMFkjjaNVIgLChh0,1412
@@ -100,7 +100,7 @@ kinto/core/views/openapi.py,sha256=PgxplQX1D0zqzlvRxBvd5SzrNMJmsaLfDta_fh-Pr-A,9
100
100
  kinto/core/views/version.py,sha256=-m5G_o0oHTpCgrtfFrHFve6Zqw_gs_szT0Bd8jnNmD4,1419
101
101
  kinto/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
102
102
  kinto/plugins/flush.py,sha256=poiBOLGXjml0xXHjqDMRdbXJSd6N3SL0mfeGK2vxeHY,812
103
- kinto/plugins/prometheus.py,sha256=WyE3jULDSMe35S4SJiKbh05AVGDyU9Hc-UR3-7baaGs,8957
103
+ kinto/plugins/prometheus.py,sha256=MXI79XQ9Uq_1hwAONgiySiKrLP-cwa26A_s4eeHrAvY,9621
104
104
  kinto/plugins/statsd.py,sha256=k9sewYZUwm60k9Z799VxbShBP3uPwGVlImaGCPnIrkE,2801
105
105
  kinto/plugins/accounts/__init__.py,sha256=2DeIaXJmMqRca3xVHeJ6xBWmeXAfrCdyg3EvK5jzIak,3670
106
106
  kinto/plugins/accounts/authentication.py,sha256=pCb269FquKGFd6DH8AVTjFnBFlfxcDEYVyxhQp5Y08o,2117
@@ -141,9 +141,9 @@ kinto/views/contribute.py,sha256=PJoIMLj9_IszSjgZkaCd_TUjekDgNqjpmVTmRN9ztaA,983
141
141
  kinto/views/groups.py,sha256=jOq5fX0-4lwZE8k1q5HME2tU7x9052rtBPF7YqcJ-Qg,3181
142
142
  kinto/views/permissions.py,sha256=F0_eKx201WyLonXJ5vLdGKa9RcFKjvAihrEEhU1JuLw,9069
143
143
  kinto/views/records.py,sha256=lYfACW2L8qcQoyYBD5IX-fTPjFWmGp7GjHq_U4InlyE,5037
144
- kinto-21.1.1.dist-info/licenses/LICENSE,sha256=oNEIMTuTJzppR5ZEyi86yvvtSagveMYXTYFn56zF0Uk,561
145
- kinto-21.1.1.dist-info/METADATA,sha256=BxBYIcWxOiJ3ahr2dfZrcd7fGnCjtcFVdyAyieI281E,8731
146
- kinto-21.1.1.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
147
- kinto-21.1.1.dist-info/entry_points.txt,sha256=3KlqBWPKY81mrCe_oX0I5s1cRO7Q53nCLbnVr5P9LH4,85
148
- kinto-21.1.1.dist-info/top_level.txt,sha256=EG_YmbZL6FAug9VwopG7JtF9SvH_r0DEnFp-3twPPys,6
149
- kinto-21.1.1.dist-info/RECORD,,
144
+ kinto-23.0.0.dist-info/licenses/LICENSE,sha256=oNEIMTuTJzppR5ZEyi86yvvtSagveMYXTYFn56zF0Uk,561
145
+ kinto-23.0.0.dist-info/METADATA,sha256=_o35lUZjDWY1dFgcRi431FWEvSt20k_e1fnkry9e7NY,8768
146
+ kinto-23.0.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
147
+ kinto-23.0.0.dist-info/entry_points.txt,sha256=3KlqBWPKY81mrCe_oX0I5s1cRO7Q53nCLbnVr5P9LH4,85
148
+ kinto-23.0.0.dist-info/top_level.txt,sha256=EG_YmbZL6FAug9VwopG7JtF9SvH_r0DEnFp-3twPPys,6
149
+ kinto-23.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (80.3.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5