jararaca 0.3.26__py3-none-any.whl → 0.3.29__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 jararaca might be problematic. Click here for more details.

jararaca/__init__.py CHANGED
@@ -18,12 +18,20 @@ if TYPE_CHECKING:
18
18
  use_app_type,
19
19
  )
20
20
  from jararaca.observability.decorators import TracedClass, TracedFunc, traced_class
21
+ from jararaca.observability.fastapi_exception_handler import (
22
+ setup_fastapi_exception_handler,
23
+ )
21
24
  from jararaca.observability.hooks import (
22
25
  add_event,
26
+ add_span_link,
27
+ get_current_span,
28
+ get_current_span_context,
23
29
  get_tracing_provider,
24
30
  record_exception,
31
+ set_span_attribute,
25
32
  set_span_status,
26
33
  spawn_trace,
34
+ start_span,
27
35
  )
28
36
  from jararaca.observability.interceptor import ObservabilityInterceptor
29
37
  from jararaca.observability.providers.otel import OtelObservabilityProvider
@@ -233,8 +241,14 @@ if TYPE_CHECKING:
233
241
  "TracedFunc",
234
242
  "TracedClass",
235
243
  "traced_class",
244
+ "start_span",
245
+ "add_span_link",
246
+ "get_current_span",
247
+ "get_current_span_context",
236
248
  "spawn_trace",
249
+ "set_span_attribute",
237
250
  "add_event",
251
+ "setup_fastapi_exception_handler",
238
252
  "set_span_status",
239
253
  "record_exception",
240
254
  "get_tracing_provider",
@@ -412,6 +426,16 @@ _dynamic_imports: "dict[str, tuple[str, str, str | None]]" = {
412
426
  "TracedClass": (__SPEC_PARENT__, "observability.decorators", None),
413
427
  "traced_class": (__SPEC_PARENT__, "observability.decorators", None),
414
428
  "spawn_trace": (__SPEC_PARENT__, "observability.hooks", None),
429
+ "setup_fastapi_exception_handler": (
430
+ __SPEC_PARENT__,
431
+ "observability.fastapi_exception_handler",
432
+ None,
433
+ ),
434
+ "set_span_attribute": (__SPEC_PARENT__, "observability.hooks", None),
435
+ "start_span": (__SPEC_PARENT__, "observability.hooks", None),
436
+ "add_span_link": (__SPEC_PARENT__, "observability.hooks", None),
437
+ "get_current_span": (__SPEC_PARENT__, "observability.hooks", None),
438
+ "get_current_span_context": (__SPEC_PARENT__, "observability.hooks", None),
415
439
  "add_event": (__SPEC_PARENT__, "observability.hooks", None),
416
440
  "set_span_status": (__SPEC_PARENT__, "observability.hooks", None),
417
441
  "record_exception": (__SPEC_PARENT__, "observability.hooks", None),
@@ -0,0 +1,3 @@
1
+ TRACEPARENT_KEY = "traceparent"
2
+
3
+ __all__ = ["TRACEPARENT_KEY"]
@@ -35,9 +35,15 @@ AttributeValue = Union[
35
35
  AttributeMap = Mapping[str, AttributeValue]
36
36
 
37
37
 
38
+ class TracingSpan(Protocol): ...
39
+
40
+
41
+ class TracingSpanContext(Protocol): ...
42
+
43
+
38
44
  class TracingContextProvider(Protocol):
39
45
 
40
- def start_trace_context(
46
+ def start_span_context(
41
47
  self, trace_name: str, context_attributes: AttributeMap | None
42
48
  ) -> ContextManager[Any]: ...
43
49
 
@@ -56,6 +62,19 @@ class TracingContextProvider(Protocol):
56
62
  escaped: bool = False,
57
63
  ) -> None: ...
58
64
 
65
+ def set_span_attribute(
66
+ self,
67
+ key: str,
68
+ value: AttributeValue,
69
+ ) -> None: ...
70
+
71
+ def update_span_name(self, new_name: str) -> None: ...
72
+
73
+ def add_link(self, span_context: TracingSpanContext) -> None: ...
74
+
75
+ def get_current_span(self) -> TracingSpan | None: ...
76
+ def get_current_span_context(self) -> TracingSpanContext | None: ...
77
+
59
78
 
60
79
  class TracingContextProviderFactory(Protocol):
61
80
 
@@ -117,7 +136,7 @@ class TracedFunc:
117
136
  ) -> Any:
118
137
 
119
138
  if ctx_provider := get_tracing_ctx_provider():
120
- with ctx_provider.start_trace_context(
139
+ with ctx_provider.start_span_context(
121
140
  self.trace_name,
122
141
  self.trace_mapper(*args, **kwargs),
123
142
  ):
@@ -0,0 +1,33 @@
1
+ from fastapi import FastAPI, Request, Response
2
+ from fastapi.exception_handlers import (
3
+ http_exception_handler,
4
+ request_validation_exception_handler,
5
+ )
6
+ from fastapi.exceptions import RequestValidationError
7
+ from fastapi.responses import JSONResponse
8
+ from starlette.exceptions import HTTPException
9
+
10
+ from jararaca.observability.constants import TRACEPARENT_KEY
11
+
12
+
13
+ def setup_fastapi_exception_handler(
14
+ app: FastAPI, trace_header_name: str = "traceparent"
15
+ ) -> None:
16
+ async def base_http_exception_handler(
17
+ request: Request, exc: HTTPException | RequestValidationError
18
+ ) -> JSONResponse | Response:
19
+
20
+ if isinstance(exc, RequestValidationError):
21
+ response = await request_validation_exception_handler(request, exc)
22
+ response.headers[trace_header_name] = request.scope.get(TRACEPARENT_KEY, "")
23
+ return response
24
+ else:
25
+ err_response = await http_exception_handler(request, exc)
26
+
27
+ err_response.headers[trace_header_name] = request.scope.get(
28
+ TRACEPARENT_KEY, ""
29
+ )
30
+ return err_response
31
+
32
+ app.exception_handlers[HTTPException] = base_http_exception_handler
33
+ app.exception_handlers[RequestValidationError] = base_http_exception_handler
@@ -1,21 +1,25 @@
1
+ import logging
1
2
  from contextlib import contextmanager
2
3
  from typing import Any, Generator, Literal
3
4
 
4
5
  from jararaca.observability.decorators import (
5
6
  AttributeMap,
7
+ AttributeValue,
6
8
  TracingContextProvider,
9
+ TracingSpan,
10
+ TracingSpanContext,
7
11
  get_tracing_ctx_provider,
8
12
  )
9
13
 
10
14
 
11
15
  @contextmanager
12
- def spawn_trace(
16
+ def start_span(
13
17
  name: str,
14
18
  attributes: AttributeMap | None = None,
15
19
  ) -> Generator[None, Any, None]:
16
20
 
17
21
  if trace_context_provider := get_tracing_ctx_provider():
18
- with trace_context_provider.start_trace_context(
22
+ with trace_context_provider.start_span_context(
19
23
  trace_name=name, context_attributes=attributes
20
24
  ):
21
25
  yield
@@ -23,6 +27,19 @@ def spawn_trace(
23
27
  yield
24
28
 
25
29
 
30
+ def spawn_trace(
31
+ name: str,
32
+ attributes: AttributeMap | None = None,
33
+ ) -> None:
34
+ logging.warning(
35
+ "spawn_trace is deprecated, use start_span as context manager instead."
36
+ )
37
+ if trace_context_provider := get_tracing_ctx_provider():
38
+ trace_context_provider.start_span_context(
39
+ trace_name=name, context_attributes=attributes
40
+ )
41
+
42
+
26
43
  def add_event(
27
44
  name: str,
28
45
  attributes: AttributeMap | None = None,
@@ -55,5 +72,37 @@ def record_exception(
55
72
  )
56
73
 
57
74
 
75
+ def set_span_attribute(
76
+ key: str,
77
+ value: AttributeValue,
78
+ ) -> None:
79
+
80
+ if trace_context_provider := get_tracing_ctx_provider():
81
+ trace_context_provider.set_span_attribute(
82
+ key=key,
83
+ value=value,
84
+ )
85
+
86
+
58
87
  def get_tracing_provider() -> TracingContextProvider | None:
59
88
  return get_tracing_ctx_provider()
89
+
90
+
91
+ def get_current_span_context() -> TracingSpanContext | None:
92
+
93
+ if trace_context_provider := get_tracing_ctx_provider():
94
+ return trace_context_provider.get_current_span_context()
95
+ return None
96
+
97
+
98
+ def get_current_span() -> TracingSpan | None:
99
+
100
+ if trace_context_provider := get_tracing_ctx_provider():
101
+ return trace_context_provider.get_current_span()
102
+ return None
103
+
104
+
105
+ def add_span_link(span_context: TracingSpanContext) -> None:
106
+
107
+ if trace_context_provider := get_tracing_ctx_provider():
108
+ trace_context_provider.add_link(span_context=span_context)
@@ -34,23 +34,39 @@ from jararaca.microservice import (
34
34
  Microservice,
35
35
  use_app_transaction_context,
36
36
  )
37
+ from jararaca.observability.constants import TRACEPARENT_KEY
37
38
  from jararaca.observability.decorators import (
38
39
  AttributeMap,
40
+ AttributeValue,
39
41
  TracingContextProvider,
40
42
  TracingContextProviderFactory,
43
+ TracingSpan,
44
+ TracingSpanContext,
41
45
  )
42
46
  from jararaca.observability.interceptor import ObservabilityProvider
43
47
 
44
48
  tracer: trace.Tracer = trace.get_tracer(__name__)
45
49
 
46
50
 
51
+ class OtelTracingSpan(TracingSpan):
52
+
53
+ def __init__(self, span: trace.Span) -> None:
54
+ self.span = span
55
+
56
+
57
+ class OtelTracingSpanContext(TracingSpanContext):
58
+
59
+ def __init__(self, span_context: trace.SpanContext) -> None:
60
+ self.span_context = span_context
61
+
62
+
47
63
  class OtelTracingContextProvider(TracingContextProvider):
48
64
 
49
65
  def __init__(self, app_context: AppTransactionContext) -> None:
50
66
  self.app_context = app_context
51
67
 
52
68
  @contextmanager
53
- def start_trace_context(
69
+ def start_span_context(
54
70
  self,
55
71
  trace_name: str,
56
72
  context_attributes: AttributeMap | None,
@@ -82,6 +98,27 @@ class OtelTracingContextProvider(TracingContextProvider):
82
98
  span = trace.get_current_span()
83
99
  span.record_exception(exception, attributes=attributes, escaped=escaped)
84
100
 
101
+ def set_span_attribute(self, key: str, value: AttributeValue) -> None:
102
+ span = trace.get_current_span()
103
+ span.set_attribute(key, value)
104
+
105
+ def update_span_name(self, new_name: str) -> None:
106
+ span = trace.get_current_span()
107
+
108
+ span.update_name(new_name)
109
+
110
+ def add_link(self, span_context: TracingSpanContext) -> None:
111
+ if not isinstance(span_context, OtelTracingSpanContext):
112
+ return
113
+ span = trace.get_current_span()
114
+ span.add_link(span_context.span_context)
115
+
116
+ def get_current_span(self) -> TracingSpan | None:
117
+ return OtelTracingSpan(trace.get_current_span())
118
+
119
+ def get_current_span_context(self) -> TracingSpanContext | None:
120
+ return OtelTracingSpanContext(trace.get_current_span().get_span_context())
121
+
85
122
 
86
123
  class OtelTracingContextProviderFactory(TracingContextProviderFactory):
87
124
 
@@ -185,10 +222,15 @@ class OtelTracingContextProviderFactory(TracingContextProviderFactory):
185
222
  },
186
223
  ) as root_span:
187
224
  cx = root_span.get_span_context()
225
+ span_traceparent_id = hex(cx.trace_id)[2:].rjust(32, "0")
188
226
  if app_tx_ctx.transaction_data.context_type == "http":
189
- app_tx_ctx.transaction_data.response.headers["traceparent"] = hex(
190
- cx.trace_id
191
- )[2:].rjust(32, "0")
227
+ app_tx_ctx.transaction_data.request.scope[TRACEPARENT_KEY] = (
228
+ span_traceparent_id
229
+ )
230
+ elif app_tx_ctx.transaction_data.context_type == "websocket":
231
+ app_tx_ctx.transaction_data.websocket.scope[TRACEPARENT_KEY] = (
232
+ span_traceparent_id
233
+ )
192
234
  tracing_headers: ImplicitHeaders = {}
193
235
  TraceContextTextMapPropagator().inject(tracing_headers)
194
236
  W3CBaggagePropagator().inject(tracing_headers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jararaca
3
- Version: 0.3.26
3
+ Version: 0.3.29
4
4
  Summary: A simple and fast API framework for Python
5
5
  Home-page: https://github.com/LuscasLeo/jararaca
6
6
  Author: Lucas S
@@ -1,7 +1,7 @@
1
1
  LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
2
2
  README.md,sha256=YmCngjU8llW0l7L3tuXkkfr8qH7V9aBMgfp2jEzeiKg,3517
3
- pyproject.toml,sha256=JXte3h2WM1G5riLSBoE2nBXWnybbJhqtoFl-N6Vt3ZI,2739
4
- jararaca/__init__.py,sha256=zQRbt5BrXFVvJW8pKaA9_KdkGFB6Njmr-9SyX0ZfenM,23331
3
+ pyproject.toml,sha256=onnmUnr1FXl1m5F5BLHvwPeJjoQrCzetXPaqxh7F2Ao,2739
4
+ jararaca/__init__.py,sha256=LH6u63yz8UTABwH4EMSrOprxw6Szn0nQWJB5A9U4VjY,24259
5
5
  jararaca/__main__.py,sha256=-O3vsB5lHdqNFjUtoELDF81IYFtR-DSiiFMzRaiSsv4,67
6
6
  jararaca/broker_backend/__init__.py,sha256=GzEIuHR1xzgCJD4FE3harNjoaYzxHMHoEL0_clUaC-k,3528
7
7
  jararaca/broker_backend/mapper.py,sha256=vTsi7sWpNvlga1PWPFg0rCJ5joJ0cdzykkIc2Tuvenc,696
@@ -26,11 +26,13 @@ jararaca/messagebus/message.py,sha256=U6cyd2XknX8mtm0333slz5fanky2PFLWCmokAO56vv
26
26
  jararaca/messagebus/publisher.py,sha256=JTkxdKbvxvDWT8nK8PVEyyX061vYYbKQMxRHXrZtcEY,2173
27
27
  jararaca/messagebus/worker.py,sha256=DiKDUhcU4rEjjA_3KqCmnN3X5yyokZq_-SbLryjS_PM,69237
28
28
  jararaca/microservice.py,sha256=DW4RVeqgrx4J-dAg17sbzTn_sLXuvV1UOQFde2fpqds,11471
29
- jararaca/observability/decorators.py,sha256=xTt4HEmpm_m1OUS29kaoZLMCT2YYToJUzQziepl8qfQ,6062
30
- jararaca/observability/hooks.py,sha256=vQCxb5m4uFse0lJIAuzSd84acu7iGDNgf4kpaWYkju8,1499
29
+ jararaca/observability/constants.py,sha256=quhqXBjDWVrr8Vr3tglgYo7zsQyz_y-z_dtqfUzYaa8,63
30
+ jararaca/observability/decorators.py,sha256=1mxIhBduikOYayq-cW9Pq1hbTzztUkjx0uzKJSSMEU4,6511
31
+ jararaca/observability/fastapi_exception_handler.py,sha256=jSLhuR5Og3vRnIoZucRA5jPnvR6DEsM1ax7tQuEo5rc,1264
32
+ jararaca/observability/hooks.py,sha256=RRv5q57bRurOUR4AIZpl1K07j9tSduj6LrBNc4xwfRs,2778
31
33
  jararaca/observability/interceptor.py,sha256=U4ZLM0f8j6Q7gMUKKnA85bnvD-Qa0ii79Qa_X8KsXAQ,1498
32
34
  jararaca/observability/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- jararaca/observability/providers/otel.py,sha256=DCNjGhcpF-XdlGTiYoQg9F_1ftcggTItDfJ_PjlZm0s,10808
35
+ jararaca/observability/providers/otel.py,sha256=08G1-dHzckKo9DQiteJl8KUukH_5tL31b2YrTDEnuDA,12262
34
36
  jararaca/persistence/base.py,sha256=xnGUbsLNz3gO-9iJt-Sn5NY13Yc9-misP8wLwQuGGoM,1024
35
37
  jararaca/persistence/exports.py,sha256=Ghx4yoFaB4QVTb9WxrFYgmcSATXMNvrOvT8ybPNKXCA,62
36
38
  jararaca/persistence/interceptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -76,8 +78,8 @@ jararaca/tools/typescript/interface_parser.py,sha256=VBx-TYQPjAiHLiYgzGdRl_p4xDb
76
78
  jararaca/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
79
  jararaca/utils/rabbitmq_utils.py,sha256=ytdAFUyv-OBkaVnxezuJaJoLrmN7giZgtKeet_IsMBs,10918
78
80
  jararaca/utils/retry.py,sha256=DzPX_fXUvTqej6BQ8Mt2dvLo9nNlTBm7Kx2pFZ26P2Q,4668
79
- jararaca-0.3.26.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
80
- jararaca-0.3.26.dist-info/METADATA,sha256=tQ8LaLhplQLYw8LPWadDAQ-lJw7Air5NCI_UGhAN550,5149
81
- jararaca-0.3.26.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
82
- jararaca-0.3.26.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
83
- jararaca-0.3.26.dist-info/RECORD,,
81
+ jararaca-0.3.29.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
82
+ jararaca-0.3.29.dist-info/METADATA,sha256=SF-nYBMhJ-gK7OxaQ3Y75sVExlh7vCcyldV5hWT1NBg,5149
83
+ jararaca-0.3.29.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
84
+ jararaca-0.3.29.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
85
+ jararaca-0.3.29.dist-info/RECORD,,
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.3.26"
3
+ version = "0.3.29"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"