c2cwsgiutils 6.1.0.dev105__py3-none-any.whl → 6.1.7.dev4__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 (56) hide show
  1. c2cwsgiutils/__init__.py +14 -11
  2. c2cwsgiutils/acceptance/__init__.py +2 -3
  3. c2cwsgiutils/acceptance/connection.py +1 -2
  4. c2cwsgiutils/acceptance/image.py +17 -11
  5. c2cwsgiutils/acceptance/package-lock.json +306 -213
  6. c2cwsgiutils/acceptance/package.json +2 -2
  7. c2cwsgiutils/acceptance/print.py +7 -3
  8. c2cwsgiutils/acceptance/utils.py +1 -3
  9. c2cwsgiutils/auth.py +27 -25
  10. c2cwsgiutils/broadcast/__init__.py +15 -16
  11. c2cwsgiutils/broadcast/interface.py +3 -3
  12. c2cwsgiutils/broadcast/local.py +1 -0
  13. c2cwsgiutils/broadcast/redis.py +13 -12
  14. c2cwsgiutils/client_info.py +19 -1
  15. c2cwsgiutils/coverage_setup.py +4 -3
  16. c2cwsgiutils/db.py +35 -41
  17. c2cwsgiutils/db_maintenance_view.py +13 -13
  18. c2cwsgiutils/debug/__init__.py +2 -2
  19. c2cwsgiutils/debug/_listeners.py +2 -7
  20. c2cwsgiutils/debug/_views.py +20 -12
  21. c2cwsgiutils/debug/utils.py +9 -9
  22. c2cwsgiutils/errors.py +13 -15
  23. c2cwsgiutils/health_check.py +24 -30
  24. c2cwsgiutils/index.py +34 -13
  25. c2cwsgiutils/loader.py +21 -2
  26. c2cwsgiutils/logging_view.py +12 -12
  27. c2cwsgiutils/models_graph.py +0 -1
  28. c2cwsgiutils/pretty_json.py +0 -1
  29. c2cwsgiutils/prometheus.py +1 -7
  30. c2cwsgiutils/pyramid.py +0 -1
  31. c2cwsgiutils/pyramid_logging.py +1 -1
  32. c2cwsgiutils/redis_stats.py +9 -9
  33. c2cwsgiutils/redis_utils.py +19 -18
  34. c2cwsgiutils/request_tracking/__init__.py +13 -13
  35. c2cwsgiutils/request_tracking/_sql.py +0 -1
  36. c2cwsgiutils/scripts/genversion.py +5 -5
  37. c2cwsgiutils/scripts/stats_db.py +19 -17
  38. c2cwsgiutils/scripts/test_print.py +5 -5
  39. c2cwsgiutils/sentry.py +55 -20
  40. c2cwsgiutils/services.py +2 -2
  41. c2cwsgiutils/setup_process.py +0 -1
  42. c2cwsgiutils/sql_profiler/__init__.py +5 -6
  43. c2cwsgiutils/sql_profiler/_impl.py +18 -17
  44. c2cwsgiutils/sqlalchemylogger/README.md +30 -13
  45. c2cwsgiutils/sqlalchemylogger/handlers.py +12 -11
  46. c2cwsgiutils/stats_pyramid/__init__.py +1 -5
  47. c2cwsgiutils/stats_pyramid/_db_spy.py +2 -2
  48. c2cwsgiutils/stats_pyramid/_pyramid_spy.py +12 -1
  49. c2cwsgiutils/templates/index.html.mako +4 -1
  50. c2cwsgiutils/version.py +11 -5
  51. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dev4.dist-info}/LICENSE +1 -1
  52. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dev4.dist-info}/METADATA +18 -6
  53. c2cwsgiutils-6.1.7.dev4.dist-info/RECORD +67 -0
  54. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dev4.dist-info}/WHEEL +1 -1
  55. c2cwsgiutils-6.1.0.dev105.dist-info/RECORD +0 -67
  56. {c2cwsgiutils-6.1.0.dev105.dist-info → c2cwsgiutils-6.1.7.dev4.dist-info}/entry_points.txt +0 -0
@@ -16,7 +16,7 @@ import traceback
16
16
  from collections.abc import Mapping
17
17
  from enum import Enum
18
18
  from types import TracebackType
19
- from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, cast
19
+ from typing import Any, Callable, Literal, Optional, Union, cast
20
20
 
21
21
  import prometheus_client
22
22
  import pyramid.config
@@ -30,13 +30,10 @@ from pyramid.httpexceptions import HTTPNotFound
30
30
  import c2cwsgiutils.db
31
31
  from c2cwsgiutils import auth, broadcast, config_utils, prometheus, redis_utils, version
32
32
 
33
- if TYPE_CHECKING:
34
- scoped_session = sqlalchemy.orm.scoped_session[sqlalchemy.orm.Session]
35
- else:
36
- scoped_session = sqlalchemy.orm.scoped_session
33
+ _scoped_session = sqlalchemy.orm.scoped_session[sqlalchemy.orm.Session]
37
34
 
38
- LOG = logging.getLogger(__name__)
39
- ALEMBIC_HEAD_RE = re.compile(r"^([a-f0-9]+) \(head\)\n$")
35
+ _LOG = logging.getLogger(__name__)
36
+ _ALEMBIC_HEAD_RE = re.compile(r"^([a-f0-9]+) \(head\)\n$")
40
37
 
41
38
  _PROMETHEUS_DB_SUMMARY = prometheus_client.Summary(
42
39
  prometheus.build_metric_name("health_check_db"),
@@ -78,14 +75,16 @@ class JsonCheckException(Exception):
78
75
  return self.message
79
76
 
80
77
  def json_data(self) -> Any:
78
+ """Return the JSON data to be returned in the response."""
81
79
  return self.json
82
80
 
83
81
 
84
82
  class _Binding:
85
83
  def name(self) -> str:
84
+ """Return the name of the binding."""
86
85
  raise NotImplementedError()
87
86
 
88
- def __enter__(self) -> scoped_session:
87
+ def __enter__(self) -> _scoped_session:
89
88
  raise NotImplementedError()
90
89
 
91
90
  def __exit__(
@@ -105,12 +104,12 @@ class _NewBinding(_Binding):
105
104
  def name(self) -> str:
106
105
  return self.session.engine_name(self.readwrite)
107
106
 
108
- def __enter__(self) -> scoped_session:
107
+ def __enter__(self) -> _scoped_session:
109
108
  return self.session(None, self.readwrite)
110
109
 
111
110
 
112
111
  class _OldBinding(_Binding):
113
- def __init__(self, session: scoped_session, engine: sqlalchemy.engine.Engine):
112
+ def __init__(self, session: _scoped_session, engine: sqlalchemy.engine.Engine):
114
113
  self.session = session
115
114
  self.engine = engine
116
115
  self.prev_bind = None
@@ -118,7 +117,7 @@ class _OldBinding(_Binding):
118
117
  def name(self) -> str:
119
118
  return cast(str, self.engine.c2c_name) # type: ignore
120
119
 
121
- def __enter__(self) -> scoped_session:
120
+ def __enter__(self) -> _scoped_session:
122
121
  self.prev_bind = self.session.bind # type: ignore
123
122
  self.session.bind = self.engine
124
123
  return self.session
@@ -134,7 +133,7 @@ class _OldBinding(_Binding):
134
133
 
135
134
 
136
135
  def _get_binding_class(
137
- session: Union[scoped_session, c2cwsgiutils.db.SessionFactory],
136
+ session: Union[_scoped_session, c2cwsgiutils.db.SessionFactory],
138
137
  ro_engin: sqlalchemy.engine.Engine,
139
138
  rw_engin: sqlalchemy.engine.Engine,
140
139
  readwrite: bool,
@@ -146,7 +145,7 @@ def _get_binding_class(
146
145
 
147
146
 
148
147
  def _get_bindings(
149
- session: Union[scoped_session, c2cwsgiutils.db.SessionFactory],
148
+ session: Union[_scoped_session, c2cwsgiutils.db.SessionFactory],
150
149
  engine_type: EngineType,
151
150
  ) -> list[_Binding]:
152
151
  if isinstance(session, c2cwsgiutils.db.SessionFactory):
@@ -184,7 +183,7 @@ def _get_alembic_version(alembic_ini_path: str, name: str) -> str:
184
183
  out = subprocess.check_output( # nosec
185
184
  ["alembic", "--config", alembic_ini_path, "--name", name, "heads"], cwd=dirname, env=env
186
185
  ).decode("utf-8")
187
- out_match = ALEMBIC_HEAD_RE.match(out)
186
+ out_match = _ALEMBIC_HEAD_RE.match(out)
188
187
  if not out_match:
189
188
  raise Exception( # pylint: disable=broad-exception-raised
190
189
  "Cannot get the alembic HEAD version from: " + out
@@ -219,8 +218,8 @@ class HealthCheck:
219
218
 
220
219
  def add_db_session_check(
221
220
  self,
222
- session: Union[scoped_session, c2cwsgiutils.db.SessionFactory],
223
- query_cb: Optional[Callable[[scoped_session], Any]] = None,
221
+ session: Union[_scoped_session, c2cwsgiutils.db.SessionFactory],
222
+ query_cb: Optional[Callable[[_scoped_session], Any]] = None,
224
223
  at_least_one_model: Optional[object] = None,
225
224
  level: int = 1,
226
225
  engine_type: EngineType = EngineType.READ_AND_WRITE,
@@ -229,7 +228,6 @@ class HealthCheck:
229
228
  Check a DB session is working. You can specify either query_cb or at_least_one_model.
230
229
 
231
230
  Arguments:
232
-
233
231
  session: a DB session created by c2cwsgiutils.db.init()
234
232
  query_cb: a callable that take a session as parameter and check it works
235
233
  at_least_one_model: a model that must have at least one entry in the DB
@@ -247,7 +245,7 @@ class HealthCheck:
247
245
 
248
246
  def add_alembic_check(
249
247
  self,
250
- session: scoped_session,
248
+ session: _scoped_session,
251
249
  alembic_ini_path: str,
252
250
  level: int = 2,
253
251
  name: str = "alembic",
@@ -258,7 +256,6 @@ class HealthCheck:
258
256
  Check the DB version against the HEAD version of Alembic.
259
257
 
260
258
  Arguments:
261
-
262
259
  session: A DB session created by c2cwsgiutils.db.init() giving access to the DB \
263
260
  managed by Alembic
264
261
  alembic_ini_path: Path to the Alembic INI file
@@ -283,7 +280,7 @@ class HealthCheck:
283
280
  assert version_table
284
281
 
285
282
  class _Check:
286
- def __init__(self, session: scoped_session) -> None:
283
+ def __init__(self, session: _scoped_session) -> None:
287
284
  self.session = session
288
285
 
289
286
  def __call__(self, request: pyramid.request.Request) -> str:
@@ -334,7 +331,6 @@ class HealthCheck:
334
331
  Check that a GET on an URL returns 2xx.
335
332
 
336
333
  Arguments:
337
-
338
334
  url: the URL to query or a function taking the request and returning it
339
335
  params: the parameters or a function taking the request and returning them
340
336
  headers: the headers or a function taking the request and returning them
@@ -367,7 +363,6 @@ class HealthCheck:
367
363
  One such check is automatically added if the broadcaster is configured with redis.
368
364
 
369
365
  Arguments:
370
-
371
366
  name: the name of the check (defaults to url)
372
367
  level: the level of the health check
373
368
  """
@@ -415,13 +410,13 @@ class HealthCheck:
415
410
  """
416
411
  Check that the version matches across all instances.
417
412
 
418
- Keyword Arguments:
419
-
413
+ Arguments:
420
414
  name: the name of the check (defaults to "version")
421
415
  level: the level of the health check
422
416
  """
423
417
 
424
418
  def check(request: pyramid.request.Request) -> dict[str, Any]:
419
+ del request # unused
425
420
  ref = version.get_version()
426
421
  all_versions = _get_all_versions()
427
422
  assert all_versions
@@ -443,7 +438,6 @@ class HealthCheck:
443
438
  in the response. In case of failure it must raise an exception.
444
439
 
445
440
  Arguments:
446
-
447
441
  name: the name of the check
448
442
  check_cb: the callback to call (takes the request as parameter)
449
443
  level: the level of the health check
@@ -489,7 +483,7 @@ class HealthCheck:
489
483
  _set_success(check_name=name)
490
484
  except Exception as e: # pylint: disable=broad-except
491
485
  _PROMETHEUS_HEALTH_CHECKS_FAILURE.labels(name=name).set(1)
492
- LOG.warning("Health check %s failed", name, exc_info=True)
486
+ _LOG.warning("Health check %s failed", name, exc_info=True)
493
487
  failure = {"message": str(e), "timing": time.perf_counter() - start, "level": level}
494
488
  if isinstance(e, JsonCheckException) and e.json_data() is not None:
495
489
  failure["result"] = e.json_data()
@@ -500,9 +494,10 @@ class HealthCheck:
500
494
  @staticmethod
501
495
  def _create_db_engine_check(
502
496
  binding: _Binding,
503
- query_cb: Callable[[scoped_session], None],
497
+ query_cb: Callable[[_scoped_session], None],
504
498
  ) -> tuple[str, Callable[[pyramid.request.Request], None]]:
505
499
  def check(request: pyramid.request.Request) -> None:
500
+ del request # unused
506
501
  with binding as session:
507
502
  with _PROMETHEUS_DB_SUMMARY.labels(
508
503
  connection=binding.name(), check="database", configuration="<default>"
@@ -512,8 +507,8 @@ class HealthCheck:
512
507
  return "db_engine_" + binding.name(), check
513
508
 
514
509
  @staticmethod
515
- def _at_least_one(model: Any) -> Callable[[scoped_session], Any]:
516
- def query(session: scoped_session) -> None:
510
+ def _at_least_one(model: Any) -> Callable[[_scoped_session], Any]:
511
+ def query(session: _scoped_session) -> None:
517
512
  result = session.query(model).first()
518
513
  if result is None:
519
514
  raise HTTPNotFound(model.__name__ + " record not found")
@@ -528,7 +523,6 @@ def _maybe_function(what: Any, request: pyramid.request.Request) -> Any:
528
523
  @broadcast.decorator(expect_answers=False)
529
524
  def _set_success(check_name: str) -> None:
530
525
  """Set check in success in all process."""
531
-
532
526
  _PROMETHEUS_HEALTH_CHECKS_FAILURE.labels(name=check_name).set(0)
533
527
 
534
528
 
c2cwsgiutils/index.py CHANGED
@@ -42,12 +42,12 @@ from c2cwsgiutils.auth import (
42
42
  )
43
43
  from c2cwsgiutils.config_utils import env_or_settings
44
44
 
45
- LOG = logging.getLogger(__name__)
45
+ _LOG = logging.getLogger(__name__)
46
46
 
47
47
  additional_title: Optional[str] = None
48
48
  additional_noauth: list[str] = []
49
49
  additional_auth: list[str] = []
50
- ELEM_ID = 0
50
+ _ELEM_ID = 0
51
51
 
52
52
 
53
53
  def _url(
@@ -113,17 +113,29 @@ def input_(
113
113
  name: str, label: Optional[str] = None, type_: Optional[str] = None, value: Union[str, int] = ""
114
114
  ) -> str:
115
115
  """Get an HTML input."""
116
- global ELEM_ID
117
- id_ = ELEM_ID
118
- ELEM_ID += 1
116
+ global _ELEM_ID # pylint: disable=global-statement
117
+ id_ = _ELEM_ID
118
+ _ELEM_ID += 1
119
119
 
120
120
  if label is None and type_ != "hidden":
121
121
  label = name.replace("_", " ").capitalize()
122
122
  if type_ is None:
123
123
  if isinstance(value, int):
124
124
  type_ = "number"
125
+ elif isinstance(value, bool):
126
+ type_ = "checkbox"
125
127
  else:
126
128
  type_ = "text"
129
+ if type_ == "checkbox":
130
+ checked = " checked" if value else ""
131
+ return f"""
132
+ <div class="form-check">
133
+ <input class="form-check-input" type="checkbox" name="{name}" value="true" id="{id_}"{checked}>
134
+ <label class="form-check-label" for="{id_}">
135
+ {label}
136
+ </label>
137
+ </div>"""
138
+
127
139
  result = ""
128
140
  if label is not None:
129
141
  result += f'<div class="row mb-3"><label class="col-sm-2 col-form-label" for="{id_}">{label}</label>'
@@ -138,7 +150,6 @@ def input_(
138
150
 
139
151
  def button(label: str) -> str:
140
152
  """Get en HTML button."""
141
-
142
153
  return f'<button class="btn btn-primary" type="submit">{label}</button>'
143
154
 
144
155
 
@@ -153,8 +164,8 @@ def _index(request: pyramid.request.Request) -> dict[str, str]:
153
164
  body = ""
154
165
  body += _health_check(request)
155
166
  body += _stats(request)
156
- body += _versions(request)
157
167
  if has_access:
168
+ body += _versions(request)
158
169
  body += _debug(request)
159
170
  body += _db_maintenance(request)
160
171
  body += _logging(request)
@@ -202,7 +213,7 @@ def _index(request: pyramid.request.Request) -> dict[str, str]:
202
213
  def _versions(request: pyramid.request.Request) -> str:
203
214
  versions_url = _url(request, "c2c_versions")
204
215
  if versions_url:
205
- return section("Versions", paragraph(link(versions_url, "Get")), sep=False)
216
+ return section("Versions " + link(versions_url, "Get"), sep=False)
206
217
  else:
207
218
  return ""
208
219
 
@@ -281,6 +292,7 @@ def _logging(request: pyramid.request.Request) -> str:
281
292
  def _debug(request: pyramid.request.Request) -> str:
282
293
  dump_memory_url = _url(request, "c2c_debug_memory")
283
294
  if dump_memory_url:
295
+ as_dot = 'as <a href="https://graphviz.org/">dot diagram</a>, can be open with <a href="https://pypi.org/project/xdot/">xdot</a>'
284
296
  return section(
285
297
  " ".join(
286
298
  [
@@ -290,32 +302,42 @@ def _debug(request: pyramid.request.Request) -> str:
290
302
  link(_url(request, "c2c_debug_memory_maps"), "Mapped memory"),
291
303
  ]
292
304
  ),
305
+ '<h2>Memory usage<span style="font-size: 0.5em;">, with <a href="https://mg.pov.lt/objgraph/">objgraph</a></span></h2>',
306
+ "<p>Runs the garbage collector and dumps the memory usage as JSON.</p>",
293
307
  form(
294
308
  dump_memory_url,
295
309
  input_("limit", value=30),
296
310
  input_("analyze_type"),
311
+ input_("python_internals_map", type_="checkbox"),
297
312
  button("Dump memory usage"),
298
313
  ),
314
+ f"<p>Runs the garbage collector and dumps the memory refs {as_dot}.</p>",
299
315
  form(
300
316
  _url(request, "c2c_debug_show_refs"),
301
317
  input_("analyze_type", value="gunicorn.app.wsgiapp.WSGIApplication"),
302
- input_("max_depth", value=3),
303
- input_("too_many", value=10),
318
+ input_("analyze_id", type_="number"),
319
+ input_("max_depth", type_="number", value=3),
320
+ input_("too_many", type_="number", value=10),
304
321
  input_("min_size_kb", type_="number"),
305
322
  button("Object refs"),
306
323
  ),
324
+ "<p>Runs the garbage collector, query the path, runs the garbage collector again, get the memory diff as JSON.</p>",
307
325
  form(
308
326
  _url(request, "c2c_debug_memory_diff"),
309
327
  input_("path"),
310
328
  input_("limit", value=30),
329
+ input_("no_warmup", type_="checkbox"),
311
330
  button("Memory diff"),
312
331
  ),
332
+ "<h2>Sleep</h2>",
313
333
  form(
314
334
  _url(request, "c2c_debug_sleep"),
315
335
  input_("time", value=1),
316
336
  button("Sleep"),
317
337
  ),
318
- form(_url(request, "c2c_debug_time"), button("Time")),
338
+ "<h2>Server times</h2>",
339
+ form(_url(request, "c2c_debug_time"), button("Get")),
340
+ "<h2>HTTP error</h2>",
319
341
  form(
320
342
  _url(request, "c2c_debug_error"),
321
343
  input_("status", value=500),
@@ -346,7 +368,6 @@ def _health_check(request: pyramid.request.Request) -> str:
346
368
 
347
369
  def _github_login(request: pyramid.request.Request) -> dict[str, Any]:
348
370
  """Get the view that start the authentication on GitHub."""
349
-
350
371
  settings = request.registry.settings
351
372
  params = dict(request.params)
352
373
  callback_url = _url(
@@ -500,7 +521,7 @@ def includeme(config: pyramid.config.Configurator) -> None:
500
521
  settings = config.get_settings()
501
522
  auth_type_ = auth_type(settings)
502
523
  if auth_type_ == AuthenticationType.SECRET:
503
- LOG.warning(
524
+ _LOG.warning(
504
525
  "It is recommended to use OAuth2 with GitHub login instead of the `C2C_SECRET` because it "
505
526
  "protects from brute force attacks and the access grant is personal and can be revoked."
506
527
  )
c2cwsgiutils/loader.py CHANGED
@@ -3,9 +3,9 @@ from typing import Optional, cast
3
3
 
4
4
  from plaster_pastedeploy import Loader as BaseLoader
5
5
 
6
- from c2cwsgiutils import get_config_defaults
6
+ from c2cwsgiutils import get_config_defaults, get_logconfig_dict
7
7
 
8
- LOG = logging.getLogger(__name__)
8
+ _LOG = logging.getLogger(__name__)
9
9
 
10
10
 
11
11
  class Loader(BaseLoader): # type: ignore
@@ -19,3 +19,22 @@ class Loader(BaseLoader): # type: ignore
19
19
  def __repr__(self) -> str:
20
20
  """Get the object representation."""
21
21
  return f'c2cwsgiutils.loader.Loader(uri="{self.uri}")'
22
+
23
+ def setup_logging(self, defaults: Optional[dict[str, str]] = None) -> None:
24
+ """
25
+ Set up logging via :func:`logging.config.dictConfig` with value returned from c2cwsgiutils.get_logconfig_dict.
26
+
27
+ Defaults are specified for the special ``__file__`` and ``here``
28
+ variables, similar to PasteDeploy config loading. Extra defaults can
29
+ optionally be specified as a dict in ``defaults``.
30
+
31
+ Arguments:
32
+ ---------
33
+ defaults: The defaults that will be used when passed to
34
+ :func:`logging.config.fileConfig`.
35
+
36
+ """
37
+ if "loggers" in self.get_sections():
38
+ logging.config.dictConfig(get_logconfig_dict(self.uri.path))
39
+ else:
40
+ logging.basicConfig()
@@ -7,10 +7,10 @@ import pyramid.request
7
7
 
8
8
  from c2cwsgiutils import auth, broadcast, config_utils, redis_utils
9
9
 
10
- LOG = logging.getLogger(__name__)
11
- CONFIG_KEY = "c2c.log_view_enabled"
12
- ENV_KEY = "C2C_LOG_VIEW_ENABLED"
13
- REDIS_PREFIX = "c2c_logging_level_"
10
+ _LOG = logging.getLogger(__name__)
11
+ _CONFIG_KEY = "c2c.log_view_enabled"
12
+ _ENV_KEY = "C2C_LOG_VIEW_ENABLED"
13
+ _REDIS_PREFIX = "c2c_logging_level_"
14
14
 
15
15
 
16
16
  def install_subscriber(config: pyramid.config.Configurator) -> None:
@@ -21,7 +21,7 @@ def install_subscriber(config: pyramid.config.Configurator) -> None:
21
21
 
22
22
  def includeme(config: pyramid.config.Configurator) -> None:
23
23
  """Install the view to configure the loggers, if configured to do so."""
24
- if auth.is_enabled(config, ENV_KEY, CONFIG_KEY):
24
+ if auth.is_enabled(config, _ENV_KEY, _CONFIG_KEY):
25
25
  config.add_route(
26
26
  "c2c_logging_level", config_utils.get_base_path(config) + r"/logging/level", request_method="GET"
27
27
  )
@@ -29,7 +29,7 @@ def includeme(config: pyramid.config.Configurator) -> None:
29
29
  _logging_change_level, route_name="c2c_logging_level", renderer="fast_json", http_cache=0
30
30
  )
31
31
  _restore_overrides(config)
32
- LOG.info("Enabled the /logging/level API")
32
+ _LOG.info("Enabled the /logging/level API")
33
33
 
34
34
 
35
35
  def _logging_change_level(request: pyramid.request.Request) -> Mapping[str, Any]:
@@ -39,7 +39,7 @@ def _logging_change_level(request: pyramid.request.Request) -> Mapping[str, Any]
39
39
  level = request.params.get("level")
40
40
  logger = logging.getLogger(name)
41
41
  if level is not None:
42
- LOG.critical(
42
+ _LOG.critical(
43
43
  "Logging of %s changed from %s to %s", name, logging.getLevelName(logger.level), level
44
44
  )
45
45
  _set_level(name=name, level=level)
@@ -63,20 +63,20 @@ def _set_level(name: str, level: str) -> bool:
63
63
  def _restore_overrides(config: pyramid.config.Configurator) -> None:
64
64
  try:
65
65
  for name, level in _list_overrides(config.get_settings()):
66
- LOG.debug("Restoring logging level override for %s: %s", name, level)
66
+ _LOG.debug("Restoring logging level override for %s: %s", name, level)
67
67
  logging.getLogger(name).setLevel(level)
68
68
  except ImportError:
69
69
  pass # don't have redis
70
70
  except Exception: # pylint: disable=broad-except
71
71
  # survive an error there. Logging levels is not business critical...
72
- LOG.warning("Cannot restore logging levels", exc_info=True)
72
+ _LOG.warning("Cannot restore logging levels", exc_info=True)
73
73
 
74
74
 
75
75
  def _store_override(settings: Mapping[str, Any], name: str, level: str) -> None:
76
76
  try:
77
77
  master, _, _ = redis_utils.get(settings)
78
78
  if master:
79
- master.set(REDIS_PREFIX + name, level)
79
+ master.set(_REDIS_PREFIX + name, level)
80
80
  except ImportError:
81
81
  pass
82
82
 
@@ -84,8 +84,8 @@ def _store_override(settings: Mapping[str, Any], name: str, level: str) -> None:
84
84
  def _list_overrides(settings: Mapping[str, Any]) -> Generator[tuple[str, str], None, None]:
85
85
  _, slave, _ = redis_utils.get(settings)
86
86
  if slave is not None:
87
- for key in slave.scan_iter(REDIS_PREFIX + "*"):
87
+ for key in slave.scan_iter(_REDIS_PREFIX + "*"):
88
88
  level = slave.get(key)
89
- name = key[len(REDIS_PREFIX) :]
89
+ name = key[len(_REDIS_PREFIX) :]
90
90
  if level is not None:
91
91
  yield name, str(level)
@@ -7,7 +7,6 @@ import sqlalchemy as sa
7
7
 
8
8
  def generate_model_graph(module: Any) -> None:
9
9
  """Generate a graphical model of the database classes."""
10
-
11
10
  base_name = None
12
11
  if len(sys.argv) == 1:
13
12
  base_name = "Base"
@@ -34,7 +34,6 @@ def init(config: pyramid.config.Configurator) -> None:
34
34
 
35
35
  def includeme(config: pyramid.config.Configurator) -> None:
36
36
  """Initialize json and fast_json renderer."""
37
-
38
37
  pretty_print = config_bool(
39
38
  env_or_config(config, "C2C_JSON_PRETTY_PRINT", "c2c.json.pretty_print", "false")
40
39
  )
@@ -24,7 +24,6 @@ MULTI_PROCESS_COLLECTOR_BROADCAST_CHANNELS = [
24
24
 
25
25
  def start(registry: Optional[prometheus_client.CollectorRegistry] = None) -> None:
26
26
  """Start separate HTTP server to provide the Prometheus metrics."""
27
-
28
27
  if os.environ.get("C2C_PROMETHEUS_PORT") is not None:
29
28
  broadcast.includeme()
30
29
 
@@ -38,20 +37,18 @@ def start(registry: Optional[prometheus_client.CollectorRegistry] = None) -> Non
38
37
 
39
38
  def includeme(config: pyramid.config.Configurator) -> None:
40
39
  """Initialize prometheus_client in pyramid context."""
41
-
40
+ del config # unused
42
41
  broadcast.subscribe("c2cwsgiutils_prometheus_collector_gc", _broadcast_collector_gc)
43
42
  broadcast.subscribe("c2cwsgiutils_prometheus_collector_process", _broadcast_collector_process)
44
43
 
45
44
 
46
45
  def build_metric_name(postfix: str) -> str:
47
46
  """Build the metric name with the prefix from the environment variable."""
48
-
49
47
  return os.environ.get("C2C_PROMETHEUS_PREFIX", "c2cwsgiutils_") + postfix
50
48
 
51
49
 
52
50
  def cleanup() -> None:
53
51
  """Cleanup the prometheus_client registry."""
54
-
55
52
  redis_utils.cleanup()
56
53
  broadcast.cleanup()
57
54
 
@@ -74,7 +71,6 @@ class SerializedMetric(TypedDict):
74
71
 
75
72
  def _broadcast_collector_gc() -> list[SerializedMetric]:
76
73
  """Get the collected GC gauges."""
77
-
78
74
  return serialize_collected_data(prometheus_client.GC_COLLECTOR)
79
75
 
80
76
 
@@ -85,7 +81,6 @@ def _broadcast_collector_process() -> list[SerializedMetric]:
85
81
 
86
82
  def serialize_collected_data(collector: prometheus_client.registry.Collector) -> list[SerializedMetric]:
87
83
  """Serialize the data from the custom collector."""
88
-
89
84
  gauges: list[SerializedMetric] = []
90
85
  for process_gauge in collector.collect():
91
86
  gauge: SerializedMetric = {
@@ -162,7 +157,6 @@ class MemoryMapCollector(prometheus_client.registry.Collector):
162
157
  Initialize.
163
158
 
164
159
  Arguments:
165
-
166
160
  memory_type: can be rss, pss or size
167
161
  pids: the list of pids or none
168
162
  """
c2cwsgiutils/pyramid.py CHANGED
@@ -30,7 +30,6 @@ def includeme(config: pyramid.config.Configurator) -> None:
30
30
  Initialize all the pyramid services and event handlers provided by this library.
31
31
 
32
32
  Arguments:
33
-
34
33
  config: The pyramid Configuration
35
34
  """
36
35
  logging.captureWarnings(True)
@@ -21,7 +21,7 @@ from typing import TYPE_CHECKING, Any, Optional, TextIO
21
21
  import cee_syslog_handler
22
22
  from pyramid.threadlocal import get_current_request
23
23
 
24
- LOG = logging.getLogger(__name__)
24
+ _LOG = logging.getLogger(__name__)
25
25
 
26
26
 
27
27
  class _PyramidFilter(logging.Filter):
@@ -7,8 +7,8 @@ import pyramid.config
7
7
 
8
8
  from c2cwsgiutils import config_utils, prometheus
9
9
 
10
- LOG = logging.getLogger(__name__)
11
- ORIG: Optional[Callable[..., Any]] = None
10
+ _LOG = logging.getLogger(__name__)
11
+ _ORIG: Optional[Callable[..., Any]] = None
12
12
 
13
13
  _PROMETHEUS_REDIS_SUMMARY = prometheus_client.Summary(
14
14
  prometheus.build_metric_name("redis"),
@@ -19,9 +19,9 @@ _PROMETHEUS_REDIS_SUMMARY = prometheus_client.Summary(
19
19
 
20
20
 
21
21
  def _execute_command_patch(self: Any, command: str, *args: Any, **options: Any) -> Any:
22
- assert ORIG is not None
22
+ assert _ORIG is not None
23
23
  with _PROMETHEUS_REDIS_SUMMARY.labels(command=command).time():
24
- return ORIG(self, command, *args, **options)
24
+ return _ORIG(self, command, *args, **options)
25
25
 
26
26
 
27
27
  def init(config: Optional[pyramid.config.Configurator] = None) -> None:
@@ -32,15 +32,15 @@ def init(config: Optional[pyramid.config.Configurator] = None) -> None:
32
32
 
33
33
  def includeme(config: Optional[pyramid.config.Configurator] = None) -> None:
34
34
  """Initialize the Redis tracking."""
35
- global ORIG
35
+ global _ORIG # pylint: disable=global-statement
36
36
  if config_utils.env_or_config(
37
37
  config, "C2C_TRACK_REDIS", "c2c.track_redis", True, config_utils.config_bool
38
38
  ):
39
39
  try:
40
- import redis.client
40
+ import redis.client # pylint: disable=import-outside-toplevel
41
41
 
42
- ORIG = redis.client.Redis.execute_command
42
+ _ORIG = redis.client.Redis.execute_command
43
43
  redis.client.Redis.execute_command = _execute_command_patch # type: ignore
44
- LOG.info("Enabled the redis tracking")
44
+ _LOG.info("Enabled the redis tracking")
45
45
  except Exception: # pragma: nocover # pylint: disable=broad-except
46
- LOG.warning("Cannot enable redis tracking", exc_info=True)
46
+ _LOG.warning("Cannot enable redis tracking", exc_info=True)