logbrew-flask 0.1.1__tar.gz

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.
@@ -0,0 +1,156 @@
1
+ Metadata-Version: 2.4
2
+ Name: logbrew-flask
3
+ Version: 0.1.1
4
+ Summary: Flask integration for capturing LogBrew request spans and exceptions.
5
+ Author: LogBrew
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/LogBrewCo/sdk
8
+ Keywords: logbrew,observability,flask,wsgi,logs
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Framework :: Flask
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: Flask>=3.1
21
+ Requires-Dist: logbrew-sdk<0.2.0,>=0.1.1
22
+
23
+ # logbrew-flask
24
+
25
+ Flask integration for capturing LogBrew request spans and exceptions with the public Python SDK.
26
+
27
+ This package is source-only until its first PyPI release. The pip command below requires the package to be available on PyPI; use a local checkout or local wheel when evaluating it before release.
28
+
29
+ ```bash
30
+ python3 -m pip install logbrew-sdk logbrew-flask
31
+ ```
32
+
33
+ The package is typed, ships `py.typed`, depends on the core `logbrew-sdk`, and keeps Flask as a normal framework dependency instead of monkeypatching Flask globally.
34
+
35
+ Use a project-scoped server ingest key, for example `LOGBREW_SERVER_API_KEY`.
36
+
37
+ ```python
38
+ import os
39
+
40
+ from flask import Flask
41
+ from logbrew_flask import add_logbrew_middleware
42
+ from logbrew_sdk import LogBrewClient
43
+
44
+ client = LogBrewClient.create(
45
+ api_key=os.environ["LOGBREW_SERVER_API_KEY"],
46
+ release=os.environ.get("LOGBREW_RELEASE"),
47
+ environment=os.environ.get("LOGBREW_ENVIRONMENT"),
48
+ sdk_name="checkout-api",
49
+ sdk_version="1.0.0",
50
+ )
51
+
52
+ app = Flask(__name__)
53
+ add_logbrew_middleware(app, client=client)
54
+
55
+
56
+ @app.get("/health")
57
+ def health() -> dict[str, bool]:
58
+ return {"ok": True}
59
+ ```
60
+
61
+ ## What It Captures
62
+
63
+ The middleware records one request span for each captured response. It can also record request duration metrics and exception issues.
64
+
65
+ Request spans use the Flask route template, such as `GET /orders/<int:order_id>`, for low-noise grouping. Span metadata includes `routeTemplate`; concrete dynamic paths are not emitted when a route template is available. Valid inbound W3C `traceparent` headers are continued with a fresh child span id.
66
+
67
+ Handlers can call `get_active_logbrew_trace()` or use `LogBrewLoggingHandler`; logs emitted during the request share the active request trace and span.
68
+
69
+ ```python
70
+ from logbrew_flask import get_active_logbrew_trace
71
+
72
+
73
+ @app.get("/orders/<int:order_id>")
74
+ def order_detail(order_id: int) -> dict[str, str | None]:
75
+ trace = get_active_logbrew_trace()
76
+ return {"traceId": trace.trace_id if trace else None}
77
+ ```
78
+
79
+ Set `capture_request_metrics=True` to emit an explicit `http.server.duration` histogram for each request. Apps can pass `span_id_factory` when deterministic child span ids are useful for controlled diagnostics; production apps usually let LogBrew generate span ids.
80
+
81
+ ## Outbound HTTP Child Spans
82
+
83
+ When a handler calls another service, use the core Python HTTP helpers inside the Flask request. They automatically reuse the active Flask request trace, create a child span, and inject one W3C `traceparent` header whose span id matches the emitted outbound span.
84
+
85
+ ```python
86
+ from logbrew_sdk import requests_request_with_logbrew_span
87
+
88
+
89
+ @app.post("/checkout/<order_id>")
90
+ def checkout(order_id: str) -> dict[str, bool]:
91
+ response = requests_request_with_logbrew_span(
92
+ "POST",
93
+ "https://payments.example.com/payments/authorize",
94
+ client=client,
95
+ event_id="evt_checkout_payment",
96
+ route_template="/payments/authorize",
97
+ )
98
+ return {"accepted": response.status_code == 202}
99
+ ```
100
+
101
+ The helper does not patch `requests` globally. It records method, low-cardinality route template, status code, trace id, span id, and parent span id. It does not capture full URLs, query strings, request bodies, response bodies, arbitrary headers, cookies, baggage, or tracestate.
102
+
103
+ ## Database, Cache, And Queue Child Spans
104
+
105
+ Use the core dependency helpers inside a Flask handler to connect database, cache, and queue work to the active request trace.
106
+
107
+ ```python
108
+ from logbrew_sdk import (
109
+ cache_operation_with_logbrew_span,
110
+ database_operation_with_logbrew_span,
111
+ queue_operation_with_logbrew_span,
112
+ )
113
+
114
+
115
+ @app.post("/checkout/<order_id>")
116
+ def checkout(order_id: str) -> dict[str, bool]:
117
+ inventory = database_operation_with_logbrew_span(
118
+ "SELECT inventory",
119
+ client=client,
120
+ operation=lambda: database.execute("SELECT quantity FROM inventory WHERE sku = ?", ("sku_123",)).fetchone(),
121
+ system="sqlite",
122
+ statement_template="SELECT inventory WHERE sku = ?",
123
+ )
124
+ cached_inventory = cache_operation_with_logbrew_span(
125
+ "GET inventory",
126
+ client=client,
127
+ operation=lambda: cache["sku_123"],
128
+ system="memory-cache",
129
+ cache_name="inventory-cache",
130
+ cache_hit=True,
131
+ )
132
+ published = queue_operation_with_logbrew_span(
133
+ "PUBLISH checkout.completed",
134
+ client=client,
135
+ operation=lambda: queue.append("checkout.completed") or len(queue),
136
+ system="memory-queue",
137
+ operation_kind="publish",
138
+ queue_name="checkout-events",
139
+ task_name="checkout.completed",
140
+ )
141
+ return {"ok": inventory is not None and cached_inventory > 0 and published == 1}
142
+ ```
143
+
144
+ Run `python -m logbrew_flask.examples dependency-spans` to see a request span with database, cache, and queue child spans under the same trace. These helpers record operation names, systems, status, trace ids, span ids, parent span ids, and primitive metadata. They do not capture SQL bind values, result payloads, queue message payloads, cache values, arbitrary headers, baggage, or tracestate.
145
+
146
+ ## Privacy Defaults
147
+
148
+ LogBrew does not capture request bodies, response bodies, cookies, arbitrary headers, query strings, raw `traceparent` values, baggage, or tracestate. Exception issues include the exception type and message but not stack frames.
149
+
150
+ ## Delivery Failures
151
+
152
+ By default, transport failures do not break the Flask response path. Set `raise_flush_errors=True` only when your app wants delivery failures to surface as request errors in controlled diagnostics.
153
+
154
+ ## Tradeoff
155
+
156
+ Sentry, Datadog, and OpenTelemetry provide broader automatic Flask, outbound HTTP, and dependency instrumentation, including global patching and deeper view/template/client hooks. LogBrew starts with explicit app-owned Flask and dependency helpers because that keeps setup reversible, simple to reason about, and safer for privacy-sensitive services.
@@ -0,0 +1,134 @@
1
+ # logbrew-flask
2
+
3
+ Flask integration for capturing LogBrew request spans and exceptions with the public Python SDK.
4
+
5
+ This package is source-only until its first PyPI release. The pip command below requires the package to be available on PyPI; use a local checkout or local wheel when evaluating it before release.
6
+
7
+ ```bash
8
+ python3 -m pip install logbrew-sdk logbrew-flask
9
+ ```
10
+
11
+ The package is typed, ships `py.typed`, depends on the core `logbrew-sdk`, and keeps Flask as a normal framework dependency instead of monkeypatching Flask globally.
12
+
13
+ Use a project-scoped server ingest key, for example `LOGBREW_SERVER_API_KEY`.
14
+
15
+ ```python
16
+ import os
17
+
18
+ from flask import Flask
19
+ from logbrew_flask import add_logbrew_middleware
20
+ from logbrew_sdk import LogBrewClient
21
+
22
+ client = LogBrewClient.create(
23
+ api_key=os.environ["LOGBREW_SERVER_API_KEY"],
24
+ release=os.environ.get("LOGBREW_RELEASE"),
25
+ environment=os.environ.get("LOGBREW_ENVIRONMENT"),
26
+ sdk_name="checkout-api",
27
+ sdk_version="1.0.0",
28
+ )
29
+
30
+ app = Flask(__name__)
31
+ add_logbrew_middleware(app, client=client)
32
+
33
+
34
+ @app.get("/health")
35
+ def health() -> dict[str, bool]:
36
+ return {"ok": True}
37
+ ```
38
+
39
+ ## What It Captures
40
+
41
+ The middleware records one request span for each captured response. It can also record request duration metrics and exception issues.
42
+
43
+ Request spans use the Flask route template, such as `GET /orders/<int:order_id>`, for low-noise grouping. Span metadata includes `routeTemplate`; concrete dynamic paths are not emitted when a route template is available. Valid inbound W3C `traceparent` headers are continued with a fresh child span id.
44
+
45
+ Handlers can call `get_active_logbrew_trace()` or use `LogBrewLoggingHandler`; logs emitted during the request share the active request trace and span.
46
+
47
+ ```python
48
+ from logbrew_flask import get_active_logbrew_trace
49
+
50
+
51
+ @app.get("/orders/<int:order_id>")
52
+ def order_detail(order_id: int) -> dict[str, str | None]:
53
+ trace = get_active_logbrew_trace()
54
+ return {"traceId": trace.trace_id if trace else None}
55
+ ```
56
+
57
+ Set `capture_request_metrics=True` to emit an explicit `http.server.duration` histogram for each request. Apps can pass `span_id_factory` when deterministic child span ids are useful for controlled diagnostics; production apps usually let LogBrew generate span ids.
58
+
59
+ ## Outbound HTTP Child Spans
60
+
61
+ When a handler calls another service, use the core Python HTTP helpers inside the Flask request. They automatically reuse the active Flask request trace, create a child span, and inject one W3C `traceparent` header whose span id matches the emitted outbound span.
62
+
63
+ ```python
64
+ from logbrew_sdk import requests_request_with_logbrew_span
65
+
66
+
67
+ @app.post("/checkout/<order_id>")
68
+ def checkout(order_id: str) -> dict[str, bool]:
69
+ response = requests_request_with_logbrew_span(
70
+ "POST",
71
+ "https://payments.example.com/payments/authorize",
72
+ client=client,
73
+ event_id="evt_checkout_payment",
74
+ route_template="/payments/authorize",
75
+ )
76
+ return {"accepted": response.status_code == 202}
77
+ ```
78
+
79
+ The helper does not patch `requests` globally. It records method, low-cardinality route template, status code, trace id, span id, and parent span id. It does not capture full URLs, query strings, request bodies, response bodies, arbitrary headers, cookies, baggage, or tracestate.
80
+
81
+ ## Database, Cache, And Queue Child Spans
82
+
83
+ Use the core dependency helpers inside a Flask handler to connect database, cache, and queue work to the active request trace.
84
+
85
+ ```python
86
+ from logbrew_sdk import (
87
+ cache_operation_with_logbrew_span,
88
+ database_operation_with_logbrew_span,
89
+ queue_operation_with_logbrew_span,
90
+ )
91
+
92
+
93
+ @app.post("/checkout/<order_id>")
94
+ def checkout(order_id: str) -> dict[str, bool]:
95
+ inventory = database_operation_with_logbrew_span(
96
+ "SELECT inventory",
97
+ client=client,
98
+ operation=lambda: database.execute("SELECT quantity FROM inventory WHERE sku = ?", ("sku_123",)).fetchone(),
99
+ system="sqlite",
100
+ statement_template="SELECT inventory WHERE sku = ?",
101
+ )
102
+ cached_inventory = cache_operation_with_logbrew_span(
103
+ "GET inventory",
104
+ client=client,
105
+ operation=lambda: cache["sku_123"],
106
+ system="memory-cache",
107
+ cache_name="inventory-cache",
108
+ cache_hit=True,
109
+ )
110
+ published = queue_operation_with_logbrew_span(
111
+ "PUBLISH checkout.completed",
112
+ client=client,
113
+ operation=lambda: queue.append("checkout.completed") or len(queue),
114
+ system="memory-queue",
115
+ operation_kind="publish",
116
+ queue_name="checkout-events",
117
+ task_name="checkout.completed",
118
+ )
119
+ return {"ok": inventory is not None and cached_inventory > 0 and published == 1}
120
+ ```
121
+
122
+ Run `python -m logbrew_flask.examples dependency-spans` to see a request span with database, cache, and queue child spans under the same trace. These helpers record operation names, systems, status, trace ids, span ids, parent span ids, and primitive metadata. They do not capture SQL bind values, result payloads, queue message payloads, cache values, arbitrary headers, baggage, or tracestate.
123
+
124
+ ## Privacy Defaults
125
+
126
+ LogBrew does not capture request bodies, response bodies, cookies, arbitrary headers, query strings, raw `traceparent` values, baggage, or tracestate. Exception issues include the exception type and message but not stack frames.
127
+
128
+ ## Delivery Failures
129
+
130
+ By default, transport failures do not break the Flask response path. Set `raise_flush_errors=True` only when your app wants delivery failures to surface as request errors in controlled diagnostics.
131
+
132
+ ## Tradeoff
133
+
134
+ Sentry, Datadog, and OpenTelemetry provide broader automatic Flask, outbound HTTP, and dependency instrumentation, including global patching and deeper view/template/client hooks. LogBrew starts with explicit app-owned Flask and dependency helpers because that keeps setup reversible, simple to reason about, and safer for privacy-sensitive services.
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=80"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "logbrew-flask"
7
+ version = "0.1.1"
8
+ description = "Flask integration for capturing LogBrew request spans and exceptions."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ { name = "LogBrew" }
14
+ ]
15
+ keywords = ["logbrew", "observability", "flask", "wsgi", "logs"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Framework :: Flask",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3 :: Only",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Typing :: Typed"
26
+ ]
27
+ dependencies = [
28
+ "Flask>=3.1",
29
+ "logbrew-sdk>=0.1.1,<0.2.0"
30
+ ]
31
+
32
+ [project.urls]
33
+ Repository = "https://github.com/LogBrewCo/sdk"
34
+
35
+ [tool.setuptools]
36
+ package-dir = {"" = "src"}
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+
41
+ [tool.setuptools.package-data]
42
+ logbrew_flask = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+