qena-shared-lib 0.1.16__py3-none-any.whl → 0.1.18__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 (33) hide show
  1. qena_shared_lib/__init__.py +3 -2
  2. qena_shared_lib/application.py +4 -4
  3. qena_shared_lib/background.py +9 -7
  4. qena_shared_lib/exception_handling.py +409 -0
  5. qena_shared_lib/exceptions.py +170 -57
  6. qena_shared_lib/http/__init__.py +90 -0
  7. qena_shared_lib/{http.py → http/_base.py} +36 -36
  8. qena_shared_lib/http/_exception_handlers.py +202 -0
  9. qena_shared_lib/kafka/__init__.py +21 -0
  10. qena_shared_lib/kafka/_base.py +233 -0
  11. qena_shared_lib/kafka/_consumer.py +597 -0
  12. qena_shared_lib/kafka/_exception_handlers.py +124 -0
  13. qena_shared_lib/kafka/_producer.py +133 -0
  14. qena_shared_lib/logging.py +17 -13
  15. qena_shared_lib/rabbitmq/__init__.py +4 -6
  16. qena_shared_lib/rabbitmq/_base.py +68 -132
  17. qena_shared_lib/rabbitmq/_channel.py +2 -4
  18. qena_shared_lib/rabbitmq/_exception_handlers.py +69 -142
  19. qena_shared_lib/rabbitmq/_listener.py +246 -157
  20. qena_shared_lib/rabbitmq/_publisher.py +5 -5
  21. qena_shared_lib/rabbitmq/_rpc_client.py +21 -22
  22. qena_shared_lib/remotelogging/_base.py +20 -20
  23. qena_shared_lib/remotelogging/logstash/_base.py +2 -2
  24. qena_shared_lib/remotelogging/logstash/_http_sender.py +2 -4
  25. qena_shared_lib/remotelogging/logstash/_tcp_sender.py +2 -2
  26. qena_shared_lib/scheduler.py +24 -15
  27. qena_shared_lib/security.py +39 -32
  28. qena_shared_lib/utils.py +13 -11
  29. {qena_shared_lib-0.1.16.dist-info → qena_shared_lib-0.1.18.dist-info}/METADATA +9 -1
  30. qena_shared_lib-0.1.18.dist-info/RECORD +38 -0
  31. qena_shared_lib/exception_handlers.py +0 -235
  32. qena_shared_lib-0.1.16.dist-info/RECORD +0 -31
  33. {qena_shared_lib-0.1.16.dist-info → qena_shared_lib-0.1.18.dist-info}/WHEEL +0 -0
@@ -3,15 +3,13 @@ from asyncio import (
3
3
  Future,
4
4
  Task,
5
5
  gather,
6
- iscoroutinefunction,
7
6
  )
8
- from functools import partial
9
7
  from random import uniform
8
+ from types import UnionType
10
9
  from typing import (
11
10
  Any,
12
11
  Awaitable,
13
12
  TypeVar,
14
- cast,
15
13
  )
16
14
 
17
15
  try:
@@ -21,21 +19,23 @@ try:
21
19
  from pika.frame import Method
22
20
  except ImportError:
23
21
  pass
24
- from prometheus_client import Counter
25
22
  from prometheus_client import Enum as PrometheusEnum
26
23
  from punq import Container, Scope
27
24
 
28
- from ..exceptions import (
29
- RabbitMQConnectionUnhealthyError,
25
+ from ..exception_handling import (
26
+ AbstractServiceExceptionHandler,
27
+ ExceptionHandlerServiceType,
28
+ ExceptionHandlingManager,
29
+ ServiceContext,
30
30
  )
31
- from ..logging import LoggerProvider
31
+ from ..exceptions import RabbitMQConnectionUnhealthyError
32
+ from ..logging import LoggerFactory
32
33
  from ..remotelogging import BaseRemoteLogSender
33
34
  from ..utils import AsyncEventLoopMixin
34
35
  from ._exception_handlers import (
35
- AbstractRabbitMqExceptionHandler,
36
- GeneralMqExceptionHandler,
36
+ RabbitMqGeneralExceptionHandler,
37
37
  RabbitMqServiceExceptionHandler,
38
- ValidationErrorHandler,
38
+ RabbitMqValidationErrorHandler,
39
39
  )
40
40
  from ._listener import (
41
41
  LISTENER_ATTRIBUTE,
@@ -68,21 +68,16 @@ class AbstractRabbitMQService(ABC):
68
68
 
69
69
 
70
70
  class RabbitMqManager(AsyncEventLoopMixin):
71
- RABBITMQ_CONNECTION_STATE = PrometheusEnum(
71
+ _RABBITMQ_CONNECTION_STATE = PrometheusEnum(
72
72
  name="rabbitmq_connection_state",
73
73
  documentation="Babbitmq connection state",
74
74
  states=["connected", "reconnecting", "disconnected"],
75
75
  )
76
- RABBITMQ_PUBLISHER_BLOCKED_STATE = PrometheusEnum(
76
+ _RABBITMQ_PUBLISHER_BLOCKED_STATE = PrometheusEnum(
77
77
  name="rabbitmq_publisher_blocked_state",
78
78
  documentation="Rabbitmq publisher blocked state",
79
79
  states=["blocked", "unblocked"],
80
80
  )
81
- HANDLED_EXCEPTIONS = Counter(
82
- name="handled_exceptions",
83
- documentation="Handled exceptions",
84
- labelnames=["queue", "listener_name", "exception"],
85
- )
86
81
 
87
82
  def __init__(
88
83
  self,
@@ -109,39 +104,29 @@ class RabbitMqManager(AsyncEventLoopMixin):
109
104
  self._disconnected = False
110
105
  self._connection_blocked = False
111
106
  self._services: list[AbstractRabbitMQService] = []
112
- self._exception_handlers: dict[
113
- type[Exception], AbstractRabbitMqExceptionHandler
114
- ] = {}
115
107
  self._channel_pool = ChannelPool()
116
108
  self._remote_logger = remote_logger
117
- self._logger = LoggerProvider.default().get_logger("rabbitmq")
109
+ self._exception_handler = ExceptionHandlingManager(
110
+ service_type=ExceptionHandlerServiceType.RABBIT_MQ,
111
+ container=self._container,
112
+ remote_logger=self._remote_logger,
113
+ label_name=["queue", "listener_name", "exception"],
114
+ )
115
+ self._logger = LoggerFactory.get_logger("rabbitmq")
116
+
117
+ self._exception_handler.set_exception_handling_done_hook(
118
+ self._on_exception_handler_done
119
+ )
118
120
 
119
121
  @property
120
122
  def container(self) -> Container:
121
123
  return self._container
122
124
 
123
- def set_exception_handlers(
124
- self, *exception_handlers: type[AbstractRabbitMqExceptionHandler]
125
- ) -> None:
126
- for index, exception_handler in enumerate(exception_handlers):
127
- if not isinstance(exception_handler, type) or not issubclass(
128
- exception_handler, AbstractRabbitMqExceptionHandler
129
- ):
130
- raise TypeError(
131
- f"exception handler {index} is {type(exception_handler)}, expected instance of type or subclass of `AbstractRabbitMqExceptionHandler`"
132
- )
133
-
134
- self._container.register(
135
- service=AbstractRabbitMqExceptionHandler,
136
- factory=exception_handler,
137
- scope=Scope.singleton,
138
- )
139
-
140
125
  def init_default_exception_handlers(self) -> None:
141
- self.set_exception_handlers(
126
+ self._exception_handler.set_exception_handlers(
142
127
  RabbitMqServiceExceptionHandler,
143
- ValidationErrorHandler,
144
- GeneralMqExceptionHandler,
128
+ RabbitMqValidationErrorHandler,
129
+ RabbitMqGeneralExceptionHandler,
145
130
  )
146
131
 
147
132
  def include_listener(self, listener: Listener | type[ListenerBase]) -> None:
@@ -159,6 +144,11 @@ class RabbitMqManager(AsyncEventLoopMixin):
159
144
  f"listener is {type(listener)}, expected instance of type or subclass of `Listener` or `type[ListenerBase]`"
160
145
  )
161
146
 
147
+ def set_exception_handlers(
148
+ self, *exception_handlers: type[AbstractServiceExceptionHandler]
149
+ ) -> None:
150
+ self._exception_handler.set_exception_handlers(*exception_handlers)
151
+
162
152
  def _register_listener_classes(self, listener_class: type) -> None:
163
153
  inner_listener = getattr(listener_class, LISTENER_ATTRIBUTE, None)
164
154
 
@@ -204,7 +194,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
204
194
  if not self._connected:
205
195
  self._resolve_listener_classes()
206
196
  self._resolve_service_classes()
207
- self._resolve_exception_handlers()
197
+ self._exception_handler.resolve_exception_handlers()
208
198
 
209
199
  if self._is_connection_healthy():
210
200
  raise RuntimeError("rabbitmq already connected and healthy")
@@ -231,23 +221,6 @@ class RabbitMqManager(AsyncEventLoopMixin):
231
221
  self._container.resolve_all(AbstractRabbitMQService)
232
222
  )
233
223
 
234
- def _resolve_exception_handlers(self) -> None:
235
- for exception_handler in self._container.resolve_all(
236
- AbstractRabbitMqExceptionHandler
237
- ):
238
- exception_handler = cast(
239
- AbstractRabbitMqExceptionHandler, exception_handler
240
- )
241
-
242
- if not callable(exception_handler):
243
- raise ValueError(
244
- f"exception handler {exception_handler.__class__.__name__} is not callable"
245
- )
246
-
247
- self._exception_handlers[exception_handler.exception] = (
248
- exception_handler
249
- )
250
-
251
224
  @property
252
225
  def connection(self) -> AsyncioConnection:
253
226
  if not self._is_connection_healthy():
@@ -284,7 +257,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
284
257
  exchange: str | None = None,
285
258
  procedure: str | None = None,
286
259
  headers: dict[str, str] | None = None,
287
- return_type: type[R] | None = None,
260
+ return_type: type[R] | UnionType | None = None,
288
261
  timeout: float = 15,
289
262
  ) -> RpcClient[R]:
290
263
  if timeout == 0:
@@ -333,7 +306,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
333
306
  self._connection.close()
334
307
  self._logger.info("disconnected from rabbitmq")
335
308
 
336
- self.RABBITMQ_CONNECTION_STATE.state("disconnected")
309
+ self._RABBITMQ_CONNECTION_STATE.state("disconnected")
337
310
 
338
311
  async def _wait_for_listeners_and_services(self) -> None:
339
312
  _ = await gather(
@@ -380,6 +353,8 @@ class RabbitMqManager(AsyncEventLoopMixin):
380
353
  if self._can_reconnect(exception):
381
354
  self._remote_logger.error(
382
355
  message="couldn't drain the channel pool",
356
+ tags=["rabbitmq", "channel_pool_drain_error"],
357
+ extra={"serviceType": "rabbitmq"},
383
358
  exception=exception,
384
359
  )
385
360
  self._reconnect()
@@ -401,9 +376,11 @@ class RabbitMqManager(AsyncEventLoopMixin):
401
376
  self._connection_blocked = True
402
377
 
403
378
  self._remote_logger.warning(
404
- "connection is blocked by broker, will not accept published messages"
379
+ message="connection is blocked by broker, will not accept published messages",
380
+ tags=["rabbitmq", "connection_blocked"],
381
+ extra={"serviceType": "rabbitmq"},
405
382
  )
406
- self.RABBITMQ_PUBLISHER_BLOCKED_STATE.state("blocked")
383
+ self._RABBITMQ_PUBLISHER_BLOCKED_STATE.state("blocked")
407
384
 
408
385
  def _on_connection_unblocked(
409
386
  self, connection: AsyncioConnection, method: Method
@@ -412,8 +389,12 @@ class RabbitMqManager(AsyncEventLoopMixin):
412
389
 
413
390
  self._connection_blocked = False
414
391
 
415
- self._remote_logger.info("broker resumed accepting published messages")
416
- self.RABBITMQ_PUBLISHER_BLOCKED_STATE.state("unblocked")
392
+ self._remote_logger.info(
393
+ message="broker resumed accepting published messages",
394
+ tags=["rabbitmq", "connection_unblocked"],
395
+ extra={"serviceType": "rabbitmq"},
396
+ )
397
+ self._RABBITMQ_PUBLISHER_BLOCKED_STATE.state("unblocked")
417
398
 
418
399
  def _is_connection_blocked(self) -> bool:
419
400
  return self._connection_blocked
@@ -433,6 +414,8 @@ class RabbitMqManager(AsyncEventLoopMixin):
433
414
  elif self._can_reconnect(exception):
434
415
  self._remote_logger.error(
435
416
  message="couldn't fill the channel pool",
417
+ tags=["rabbitmq", "channel_pool_fill_error"],
418
+ extra={"serviceType": "rabbitmq"},
436
419
  exception=exception,
437
420
  )
438
421
  self._reconnect()
@@ -463,7 +446,8 @@ class RabbitMqManager(AsyncEventLoopMixin):
463
446
  listener.configure(
464
447
  connection=self._connection,
465
448
  channel_pool=self._channel_pool,
466
- on_exception_callback=self._invoke_exception_handler,
449
+ on_exception_callback=self._exception_handler.submit_exception,
450
+ blocked_connection_check_callback=self._is_connection_blocked,
467
451
  container=self._container,
468
452
  remote_logger=self._remote_logger,
469
453
  global_retry_policy=self._listener_global_retry_policy,
@@ -517,6 +501,11 @@ class RabbitMqManager(AsyncEventLoopMixin):
517
501
  elif self._can_reconnect(exception):
518
502
  self._remote_logger.error(
519
503
  message="couldn't configure and initialize all listeners and services",
504
+ tags=[
505
+ "rabbitmq",
506
+ "listener_and_service_config_and_init_error",
507
+ ],
508
+ extra={"serviceType": "rabbitmq"},
520
509
  exception=exception,
521
510
  )
522
511
  self._reconnect()
@@ -547,7 +536,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
547
536
  if not self._connected_future.done():
548
537
  self._connected_future.set_result(None)
549
538
 
550
- self.RABBITMQ_CONNECTION_STATE.state("connected")
539
+ self._RABBITMQ_CONNECTION_STATE.state("connected")
551
540
 
552
541
  def _on_connection_open_error(
553
542
  self, connection: AsyncioConnection, exception: BaseException
@@ -562,73 +551,14 @@ class RabbitMqManager(AsyncEventLoopMixin):
562
551
  if self._connected and not self._disconnected:
563
552
  self._remote_logger.error(
564
553
  message="error while opening connection to rabbitmq",
554
+ tags=["rabbitmq", "connection_open_error"],
555
+ extra={"serviceType": "rabbitmq"},
565
556
  exception=exception,
566
557
  )
567
558
  self._reconnect()
568
559
 
569
- def _invoke_exception_handler(
570
- self, context: ListenerContext, exception: BaseException
571
- ) -> bool:
572
- exception_handler = None
573
-
574
- for exception_type in type(exception).mro():
575
- exception_handler = self._exception_handlers.get(exception_type)
576
-
577
- if exception_handler is not None:
578
- break
579
-
580
- if exception_handler is None:
581
- return False
582
-
583
- assert callable(exception_handler)
584
-
585
- if self._is_async_exception_handler(exception_handler):
586
- self.loop.create_task(
587
- exception_handler(context, exception)
588
- ).add_done_callback(
589
- partial(self._on_exception_handler_done, context)
590
- )
591
- else:
592
- self.loop.run_in_executor(
593
- executor=None,
594
- func=partial(exception_handler, context, exception),
595
- ).add_done_callback(
596
- partial(self._on_exception_handler_done, context)
597
- )
598
-
599
- self.HANDLED_EXCEPTIONS.labels(
600
- queue=context.queue,
601
- listener_name=context.listener_name,
602
- exception=exception.__class__.__name__,
603
- ).inc()
604
-
605
- return True
606
-
607
- def _is_async_exception_handler(
608
- self, exception_handler: AbstractRabbitMqExceptionHandler
609
- ) -> bool:
610
- exception_handler_callable = getattr(
611
- exception_handler, "__call__", None
612
- )
613
-
614
- if exception_handler_callable is None:
615
- raise RuntimeError("exception handler has not `__call__` method")
616
-
617
- return iscoroutinefunction(exception_handler_callable)
618
-
619
- def _on_exception_handler_done(
620
- self, context: ListenerContext, task_or_future: Task[Any] | Future[Any]
621
- ) -> None:
622
- if task_or_future.cancelled():
623
- return
624
-
625
- exception = task_or_future.exception()
626
-
627
- if exception is not None:
628
- self._remote_logger.error(
629
- message="error occured in listener exception handler",
630
- exception=exception,
631
- )
560
+ def _on_exception_handler_done(self, context: ServiceContext) -> None:
561
+ assert isinstance(context, ListenerContext)
632
562
 
633
563
  context.dispose()
634
564
 
@@ -645,12 +575,14 @@ class RabbitMqManager(AsyncEventLoopMixin):
645
575
  if self._can_reconnect(exception):
646
576
  self._remote_logger.error(
647
577
  message="connection to rabbitmq closed unexpectedly, attempting to reconnect",
578
+ tags=["rabbitmq", "connection_closed"],
579
+ extra={"serviceType": "rabbitmq"},
648
580
  exception=exception,
649
581
  )
650
582
  self._reconnect()
651
583
 
652
584
  def _reconnect(self) -> None:
653
- self.RABBITMQ_CONNECTION_STATE.state("reconnecting")
585
+ self._RABBITMQ_CONNECTION_STATE.state("reconnecting")
654
586
  self.loop.call_later(
655
587
  delay=self._reconnect_delay
656
588
  + uniform(*self._reconnect_delay_jitter),
@@ -666,7 +598,9 @@ class RabbitMqManager(AsyncEventLoopMixin):
666
598
  self._connected_future.set_result(None)
667
599
 
668
600
  self._remote_logger.exception(
669
- "couldn't reconnect to rabbitmq, attempting to reconnect"
601
+ message="couldn't reconnect to rabbitmq, attempting to reconnect",
602
+ tags=["rabbitmq", "connection_open_error"],
603
+ extra={"serviceType": "rabbitmq"},
670
604
  )
671
605
  self._reconnect()
672
606
 
@@ -689,6 +623,8 @@ class RabbitMqManager(AsyncEventLoopMixin):
689
623
  if self._can_reconnect(exception):
690
624
  self._remote_logger.error(
691
625
  message="couldn't reconnect to rabbitmq, attempting to reconnect",
626
+ tags=["rabbitmq", "reconnect_error"],
627
+ extra={"serviceType": "rabbitmq"},
692
628
  exception=exception,
693
629
  )
694
630
  self._reconnect()
@@ -12,7 +12,7 @@ try:
12
12
  except ImportError:
13
13
  pass
14
14
 
15
- from ..logging import LoggerProvider
15
+ from ..logging import LoggerFactory
16
16
  from ..utils import AsyncEventLoopMixin
17
17
 
18
18
  __all__ = ["BaseChannel"]
@@ -36,9 +36,7 @@ class BaseChannel(AsyncEventLoopMixin):
36
36
  self._reopen_failures = 0
37
37
  self._reserved = False
38
38
  self._can_be_disposed = False
39
- self._logger = LoggerProvider.default().get_logger(
40
- "rabbitmq.base_channel"
41
- )
39
+ self._logger = LoggerFactory.get_logger("rabbitmq.base_channel")
42
40
 
43
41
  def open(self) -> Future[UUID]:
44
42
  if self._channel is not None:
@@ -1,182 +1,109 @@
1
- from typing import cast
2
-
3
1
  from pydantic import ValidationError
4
2
 
5
- from ..exceptions import (
6
- HTTPServiceError,
7
- RabbitMQServiceException,
8
- ServiceException,
9
- Severity,
3
+ from ..exception_handling import (
4
+ ExceptionHandlerServiceType,
5
+ GeneralExceptionHandler,
6
+ ServiceExceptionHandler,
7
+ ServiceInformation,
8
+ ValidationErrorHandler,
10
9
  )
11
- from ..logging import LoggerProvider
12
- from ..remotelogging._base import BaseRemoteLogSender
10
+ from ..exceptions import ServiceException
11
+ from ..logging import LoggerFactory
12
+ from ..remotelogging import BaseRemoteLogSender
13
13
  from ._listener import ListenerContext
14
14
 
15
15
  __all__ = [
16
- "AbstractRabbitMqExceptionHandler",
17
- "GeneralMqExceptionHandler",
18
16
  "RabbitMqServiceExceptionHandler",
19
- "ValidationErrorHandler",
17
+ "RabbitMqServiceExceptionHandler",
18
+ "RabbitMqValidationErrorHandler",
20
19
  ]
21
20
 
22
21
  RABBITMQ_EXCEPTION_HANDLER_LOGGER_NAME = "rabbitmq.exception_handler"
23
22
 
24
23
 
25
- class AbstractRabbitMqExceptionHandler:
26
- @property
27
- def exception(self) -> type[Exception]:
28
- raise NotImplementedError()
29
-
30
-
31
- class RabbitMqServiceExceptionHandler(AbstractRabbitMqExceptionHandler):
32
- @property
33
- def exception(self) -> type[Exception]:
34
- return cast(type[Exception], ServiceException)
24
+ class RabbitMqServiceExceptionHandler(ServiceExceptionHandler):
25
+ def __init__(self, remote_logger: BaseRemoteLogSender):
26
+ super().__init__(remote_logger)
35
27
 
36
- def __init__(
37
- self,
38
- remote_logger: BaseRemoteLogSender,
39
- logger_provider: LoggerProvider,
40
- ):
41
- self._logger = logger_provider.get_logger(
28
+ self._logger = LoggerFactory.get_logger(
42
29
  RABBITMQ_EXCEPTION_HANDLER_LOGGER_NAME
43
30
  )
44
- self._remote_logger = remote_logger
45
31
 
46
32
  def __call__(
47
33
  self,
48
34
  context: ListenerContext,
49
35
  exception: ServiceException,
50
36
  ) -> None:
51
- tags = [
52
- "RabbitMQ",
53
- context.queue,
54
- context.listener_name or "__default__",
55
- exception.__class__.__name__,
56
- ]
57
- extra = {
58
- "serviceType": "RabbitMQ",
59
- "queue": context.queue,
60
- "listenerName": context.listener_name,
61
- "exception": exception.__class__.__name__,
62
- }
63
-
64
- match exception:
65
- case HTTPServiceError() as http_service_error:
66
- if http_service_error.status_code is not None:
67
- str_status_code = str(http_service_error.status_code)
68
- extra["statusCode"] = str_status_code
69
-
70
- tags.append(str_status_code)
71
-
72
- if http_service_error.response_code is not None:
73
- str_response_code = str(http_service_error.response_code)
74
- extra["responseCode"] = str_response_code
75
-
76
- tags.append(str_response_code)
77
- case RabbitMQServiceException() as rabbitmq_service_exception:
78
- str_error_code = str(rabbitmq_service_exception.code)
79
- extra["code"] = str_error_code
80
-
81
- tags.append(str_error_code)
82
-
83
- if exception.tags:
84
- tags.extend(exception.tags)
85
-
86
- if exception.extra:
87
- extra.update(exception.extra)
88
-
89
- exc_info = (
90
- (type(exception), exception, exception.__traceback__)
91
- if exception.extract_exc_info
92
- else None
37
+ self.handle(
38
+ service_information=ServiceInformation(
39
+ service_type=ExceptionHandlerServiceType.RABBIT_MQ,
40
+ tags=[
41
+ "RabbitMQ",
42
+ context.queue,
43
+ context.listener_name or "__default__",
44
+ exception.__class__.__name__,
45
+ ],
46
+ extra={
47
+ "serviceType": "RabbitMQ",
48
+ "queue": context.queue,
49
+ "listenerName": context.listener_name,
50
+ "exception": exception.__class__.__name__,
51
+ },
52
+ message=f"queue = `{context.queue}` listener_name = `{context.listener_name}` {exception.message}",
53
+ ),
54
+ exception=exception,
93
55
  )
94
56
 
95
- match exception.severity:
96
- case Severity.HIGH:
97
- remote_logger_method = self._remote_logger.error
98
- logger_method = self._logger.error
99
- case Severity.MEDIUM:
100
- remote_logger_method = self._remote_logger.warning
101
- logger_method = self._logger.warning
102
- case _:
103
- remote_logger_method = self._remote_logger.info
104
- logger_method = self._logger.info
105
-
106
- if exception.remote_logging:
107
- remote_logger_method(
108
- message=exception.message,
109
- tags=tags,
110
- extra=extra,
111
- exception=exception if exception.extract_exc_info else None,
112
- )
113
- else:
114
- logger_method(
115
- "\nRabbitMQ `%s` -> `%s`\n%s",
116
- context.queue,
117
- context.listener_name,
118
- exception.message,
119
- exc_info=exc_info,
120
- )
121
-
122
-
123
- class ValidationErrorHandler(AbstractRabbitMqExceptionHandler):
124
- @property
125
- def exception(self) -> type[Exception]:
126
- return cast(type[Exception], ValidationError)
127
-
128
- def __init__(self, remote_logger: BaseRemoteLogSender):
129
- self._remote_logger = remote_logger
130
57
 
58
+ class RabbitMqValidationErrorHandler(ValidationErrorHandler):
131
59
  def __call__(
132
60
  self,
133
61
  context: ListenerContext,
134
62
  exception: ValidationError,
135
63
  ) -> None:
136
- self._remote_logger.error(
137
- message=f"invalid rabbitmq request data at queue `{context.queue}` and listener `{context.listener_name}`",
138
- tags=[
139
- "RabbitMQ",
140
- context.queue,
141
- context.listener_name or "__default__",
142
- "ValidationError",
143
- ],
144
- extra={
145
- "serviceType": "RabbitMQ",
146
- "queue": context.queue,
147
- "listenerName": context.listener_name,
148
- "exception": "ValidationError",
149
- },
64
+ self.handle(
65
+ service_information=ServiceInformation(
66
+ service_type=ExceptionHandlerServiceType.RABBIT_MQ,
67
+ tags=[
68
+ "RabbitMQ",
69
+ context.queue,
70
+ context.listener_name or "__default__",
71
+ "ValidationError",
72
+ ],
73
+ extra={
74
+ "serviceType": "RabbitMQ",
75
+ "queue": context.queue,
76
+ "listenerName": context.listener_name,
77
+ "exception": "ValidationError",
78
+ },
79
+ message=f"invalid rabbitmq request data at queue `{context.queue}` and listener `{context.listener_name}`",
80
+ ),
150
81
  exception=exception,
151
82
  )
152
83
 
153
84
 
154
- class GeneralMqExceptionHandler(AbstractRabbitMqExceptionHandler):
155
- @property
156
- def exception(self) -> type[Exception]:
157
- return Exception
158
-
159
- def __init__(self, remote_logger: BaseRemoteLogSender):
160
- self._remote_logger = remote_logger
161
-
85
+ class RabbitMqGeneralExceptionHandler(GeneralExceptionHandler):
162
86
  def __call__(
163
87
  self,
164
88
  context: ListenerContext,
165
89
  exception: Exception,
166
90
  ) -> None:
167
- self._remote_logger.error(
168
- message=f"something went wrong while consuming message on queue `{context.queue}` and listener `{context.listener_name}`",
169
- tags=[
170
- "RabbitMQ",
171
- context.queue,
172
- context.listener_name or "__default__",
173
- exception.__class__.__name__,
174
- ],
175
- extra={
176
- "serviceType": "RabbitMQ",
177
- "queue": context.queue,
178
- "listenerName": context.listener_name,
179
- "exception": exception.__class__.__name__,
180
- },
91
+ self.handle(
92
+ service_information=ServiceInformation(
93
+ service_type=ExceptionHandlerServiceType.RABBIT_MQ,
94
+ tags=[
95
+ "RabbitMQ",
96
+ context.queue,
97
+ context.listener_name or "__default__",
98
+ exception.__class__.__name__,
99
+ ],
100
+ extra={
101
+ "serviceType": "RabbitMQ",
102
+ "queue": context.queue,
103
+ "listenerName": context.listener_name,
104
+ "exception": exception.__class__.__name__,
105
+ },
106
+ message=f"something went wrong while consuming message on queue `{context.queue}` and listener `{context.listener_name}`",
107
+ ),
181
108
  exception=exception,
182
109
  )