plainx-sentry 0.3.1__tar.gz → 0.4.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.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plainx-sentry
3
- Version: 0.3.1
3
+ Version: 0.4.1
4
4
  Author-email: Dave Gaeddert <dave.gaeddert@gmail.com>
5
5
  Requires-Python: >=3.11
6
- Requires-Dist: sentry-sdk>=1.8.0
6
+ Requires-Dist: sentry-sdk>=2.24.0
7
7
  Description-Content-Type: text/markdown
8
8
 
9
9
  # plainx-sentry
@@ -0,0 +1,154 @@
1
+ import sentry_sdk
2
+ from plain.runtime import settings
3
+ from sentry_sdk.tracing import TransactionSource
4
+ from sentry_sdk.utils import capture_internal_exceptions
5
+
6
+ try:
7
+ from plain.models.db import connection
8
+ except ImportError:
9
+ connection = None
10
+
11
+ import logging
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def trace_db(execute, sql, params, many, context):
17
+ with sentry_sdk.start_span(op="db", description=sql) as span:
18
+ # Mostly borrowed from the Sentry Django integration...
19
+ data = {
20
+ "db.params": params,
21
+ "db.executemany": many,
22
+ "db.system": connection.vendor,
23
+ "db.name": connection.settings_dict.get("NAME"),
24
+ "db.user": connection.settings_dict.get("USER"),
25
+ "server.address": connection.settings_dict.get("HOST"),
26
+ "server.port": connection.settings_dict.get("PORT"),
27
+ }
28
+
29
+ sentry_sdk.add_breadcrumb(message=sql, category="query", data=data)
30
+
31
+ for k, v in data.items():
32
+ span.set_data(k, v)
33
+
34
+ result = execute(sql, params, many, context)
35
+
36
+ return result
37
+
38
+
39
+ class SentryMiddleware:
40
+ def __init__(self, get_response):
41
+ self.get_response = get_response
42
+
43
+ def __call__(self, request):
44
+ # Don't do anything if Sentry is not active
45
+ if not sentry_sdk.get_client().is_active():
46
+ return self.get_response(request)
47
+
48
+ def event_processor(event, hint):
49
+ # request gets attached directly to an event,
50
+ # not necessarily in the "context"
51
+ request_info = event.setdefault("request", {})
52
+ request_info["url"] = request.build_absolute_uri()
53
+ request_info["method"] = request.method
54
+ request_info["query_string"] = request.META.get("QUERY_STRING", "")
55
+ # Headers and env need some PII filtering, ideally,
56
+ # among other filters... similar for GET/POST data?
57
+ # request_info["headers"] = dict(request.headers)
58
+ try:
59
+ request_info["data"] = request.body.decode("utf-8")
60
+ except Exception:
61
+ pass
62
+
63
+ if user := getattr(request, "user", None):
64
+ event["user"] = {"id": str(user.pk)}
65
+ if settings.SENTRY_PII_ENABLED:
66
+ if email := getattr(user, "email", None):
67
+ event["user"]["email"] = email
68
+ if username := getattr(user, "username", None):
69
+ event["user"]["username"] = username
70
+
71
+ return event
72
+
73
+ with sentry_sdk.isolation_scope() as scope:
74
+ # Reset the scope (and breadcrumbs) for each request
75
+ scope.clear()
76
+ scope.add_event_processor(event_processor)
77
+
78
+ # Sentry's Django integration patches the WSGIHandler.
79
+ # We could make our own WSGIHandler and patch it or call it directly from gunicorn,
80
+ # but putting our middleware at the top of MIDDLEWARE is pretty close and easier.
81
+ with sentry_sdk.start_transaction(
82
+ op="http.server", name=request.path_info
83
+ ) as transaction:
84
+ if connection:
85
+ # Also get spans for db queries
86
+ with connection.execute_wrapper(trace_db):
87
+ response = self.get_response(request)
88
+ else:
89
+ # No db presumably
90
+ response = self.get_response(request)
91
+
92
+ if resolver_match := getattr(request, "resolver_match", None):
93
+ # Rename the transaction using a pattern,
94
+ # and attach other url/views tags we can use to filter
95
+ transaction.name = f"route:{resolver_match.route}"
96
+ transaction.set_tag("url_namespace", resolver_match.namespace)
97
+ transaction.set_tag("url_name", resolver_match.url_name)
98
+ transaction.set_tag("view_name", resolver_match.view_name)
99
+ transaction.set_tag("view_class", resolver_match._func_path)
100
+ # Don't need to filter on this, but do want the context to view
101
+ transaction.set_context(
102
+ "url_params",
103
+ {
104
+ "args": resolver_match.args,
105
+ "kwargs": resolver_match.kwargs,
106
+ },
107
+ )
108
+
109
+ transaction.set_http_status(response.status_code)
110
+
111
+ return response
112
+
113
+
114
+ class SentryWorkerMiddleware:
115
+ def __init__(self, run_job):
116
+ self.run_job = run_job
117
+
118
+ def __call__(self, job):
119
+ # Don't do anything if Sentry is not active
120
+ if not sentry_sdk.get_client().is_active():
121
+ return self.run_job(job)
122
+
123
+ def event_processor(event, hint):
124
+ with capture_internal_exceptions():
125
+ # Attach it directly to any events
126
+ extra = event.setdefault("extra", {})
127
+ extra["plain.worker"] = {"job": job.as_json()}
128
+ return event
129
+
130
+ with sentry_sdk.isolation_scope() as scope:
131
+ # Reset the scope (and breadcrumbs) for each request
132
+ scope.clear()
133
+ scope.add_event_processor(event_processor)
134
+
135
+ with sentry_sdk.start_transaction(
136
+ op="plain.worker.job",
137
+ name=f"job:{job.job_class}",
138
+ source=TransactionSource.TASK,
139
+ ) as transaction:
140
+ if connection:
141
+ # Also get spans for db queries
142
+ with connection.execute_wrapper(trace_db):
143
+ job_result = self.run_job(job)
144
+ else:
145
+ # No db presumably
146
+ job_result = self.run_job(job)
147
+
148
+ with capture_internal_exceptions():
149
+ # Don't need to filter on this, but do want the context to view
150
+ transaction.set_context("job", job.as_json())
151
+
152
+ transaction.set_status("ok")
153
+
154
+ return job_result
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "plainx-sentry"
3
- version = "0.3.1"
3
+ version = "0.4.1"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  authors = [
@@ -8,7 +8,7 @@ authors = [
8
8
  ]
9
9
  requires-python = ">=3.11"
10
10
  dependencies = [
11
- "sentry-sdk>=1.8.0",
11
+ "sentry-sdk>=2.24.0",
12
12
  ]
13
13
 
14
14
  [dependency-groups]
@@ -34,11 +34,11 @@ wheels = [
34
34
 
35
35
  [[package]]
36
36
  name = "iniconfig"
37
- version = "2.0.0"
37
+ version = "2.1.0"
38
38
  source = { registry = "https://pypi.org/simple" }
39
- sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
39
+ sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 }
40
40
  wheels = [
41
- { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
41
+ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 },
42
42
  ]
43
43
 
44
44
  [[package]]
@@ -153,7 +153,7 @@ wheels = [
153
153
 
154
154
  [[package]]
155
155
  name = "plainx-sentry"
156
- version = "0.3.0"
156
+ version = "0.4.0"
157
157
  source = { editable = "." }
158
158
  dependencies = [
159
159
  { name = "sentry-sdk" },
@@ -167,7 +167,7 @@ dev = [
167
167
  ]
168
168
 
169
169
  [package.metadata]
170
- requires-dist = [{ name = "sentry-sdk", specifier = ">=1.8.0" }]
170
+ requires-dist = [{ name = "sentry-sdk", specifier = ">=2.24.0" }]
171
171
 
172
172
  [package.metadata.requires-dev]
173
173
  dev = [
@@ -211,40 +211,40 @@ wheels = [
211
211
 
212
212
  [[package]]
213
213
  name = "ruff"
214
- version = "0.9.10"
214
+ version = "0.11.2"
215
215
  source = { registry = "https://pypi.org/simple" }
216
- sdist = { url = "https://files.pythonhosted.org/packages/20/8e/fafaa6f15c332e73425d9c44ada85360501045d5ab0b81400076aff27cf6/ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7", size = 3759776 }
216
+ sdist = { url = "https://files.pythonhosted.org/packages/90/61/fb87430f040e4e577e784e325351186976516faef17d6fcd921fe28edfd7/ruff-0.11.2.tar.gz", hash = "sha256:ec47591497d5a1050175bdf4e1a4e6272cddff7da88a2ad595e1e326041d8d94", size = 3857511 }
217
217
  wheels = [
218
- { url = "https://files.pythonhosted.org/packages/73/b2/af7c2cc9e438cbc19fafeec4f20bfcd72165460fe75b2b6e9a0958c8c62b/ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d", size = 10049494 },
219
- { url = "https://files.pythonhosted.org/packages/6d/12/03f6dfa1b95ddd47e6969f0225d60d9d7437c91938a310835feb27927ca0/ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d", size = 10853584 },
220
- { url = "https://files.pythonhosted.org/packages/02/49/1c79e0906b6ff551fb0894168763f705bf980864739572b2815ecd3c9df0/ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d", size = 10155692 },
221
- { url = "https://files.pythonhosted.org/packages/5b/01/85e8082e41585e0e1ceb11e41c054e9e36fed45f4b210991052d8a75089f/ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c", size = 10369760 },
222
- { url = "https://files.pythonhosted.org/packages/a1/90/0bc60bd4e5db051f12445046d0c85cc2c617095c0904f1aa81067dc64aea/ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e", size = 9912196 },
223
- { url = "https://files.pythonhosted.org/packages/66/ea/0b7e8c42b1ec608033c4d5a02939c82097ddcb0b3e393e4238584b7054ab/ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12", size = 11434985 },
224
- { url = "https://files.pythonhosted.org/packages/d5/86/3171d1eff893db4f91755175a6e1163c5887be1f1e2f4f6c0c59527c2bfd/ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16", size = 12155842 },
225
- { url = "https://files.pythonhosted.org/packages/89/9e/700ca289f172a38eb0bca752056d0a42637fa17b81649b9331786cb791d7/ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52", size = 11613804 },
226
- { url = "https://files.pythonhosted.org/packages/f2/92/648020b3b5db180f41a931a68b1c8575cca3e63cec86fd26807422a0dbad/ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1", size = 13823776 },
227
- { url = "https://files.pythonhosted.org/packages/5e/a6/cc472161cd04d30a09d5c90698696b70c169eeba2c41030344194242db45/ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c", size = 11302673 },
228
- { url = "https://files.pythonhosted.org/packages/6c/db/d31c361c4025b1b9102b4d032c70a69adb9ee6fde093f6c3bf29f831c85c/ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43", size = 10235358 },
229
- { url = "https://files.pythonhosted.org/packages/d1/86/d6374e24a14d4d93ebe120f45edd82ad7dcf3ef999ffc92b197d81cdc2a5/ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c", size = 9886177 },
230
- { url = "https://files.pythonhosted.org/packages/00/62/a61691f6eaaac1e945a1f3f59f1eea9a218513139d5b6c2b8f88b43b5b8f/ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5", size = 10864747 },
231
- { url = "https://files.pythonhosted.org/packages/ee/94/2c7065e1d92a8a8a46d46d9c3cf07b0aa7e0a1e0153d74baa5e6620b4102/ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8", size = 11360441 },
232
- { url = "https://files.pythonhosted.org/packages/a7/8f/1f545ea6f9fcd7bf4368551fb91d2064d8f0577b3079bb3f0ae5779fb773/ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029", size = 10247401 },
233
- { url = "https://files.pythonhosted.org/packages/4f/18/fb703603ab108e5c165f52f5b86ee2aa9be43bb781703ec87c66a5f5d604/ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1", size = 11366360 },
234
- { url = "https://files.pythonhosted.org/packages/35/85/338e603dc68e7d9994d5d84f24adbf69bae760ba5efd3e20f5ff2cec18da/ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69", size = 10436892 },
218
+ { url = "https://files.pythonhosted.org/packages/62/99/102578506f0f5fa29fd7e0df0a273864f79af044757aef73d1cae0afe6ad/ruff-0.11.2-py3-none-linux_armv6l.whl", hash = "sha256:c69e20ea49e973f3afec2c06376eb56045709f0212615c1adb0eda35e8a4e477", size = 10113146 },
219
+ { url = "https://files.pythonhosted.org/packages/74/ad/5cd4ba58ab602a579997a8494b96f10f316e874d7c435bcc1a92e6da1b12/ruff-0.11.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:2c5424cc1c4eb1d8ecabe6d4f1b70470b4f24a0c0171356290b1953ad8f0e272", size = 10867092 },
220
+ { url = "https://files.pythonhosted.org/packages/fc/3e/d3f13619e1d152c7b600a38c1a035e833e794c6625c9a6cea6f63dbf3af4/ruff-0.11.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ecf20854cc73f42171eedb66f006a43d0a21bfb98a2523a809931cda569552d9", size = 10224082 },
221
+ { url = "https://files.pythonhosted.org/packages/90/06/f77b3d790d24a93f38e3806216f263974909888fd1e826717c3ec956bbcd/ruff-0.11.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c543bf65d5d27240321604cee0633a70c6c25c9a2f2492efa9f6d4b8e4199bb", size = 10394818 },
222
+ { url = "https://files.pythonhosted.org/packages/99/7f/78aa431d3ddebfc2418cd95b786642557ba8b3cb578c075239da9ce97ff9/ruff-0.11.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20967168cc21195db5830b9224be0e964cc9c8ecf3b5a9e3ce19876e8d3a96e3", size = 9952251 },
223
+ { url = "https://files.pythonhosted.org/packages/30/3e/f11186d1ddfaca438c3bbff73c6a2fdb5b60e6450cc466129c694b0ab7a2/ruff-0.11.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:955a9ce63483999d9f0b8f0b4a3ad669e53484232853054cc8b9d51ab4c5de74", size = 11563566 },
224
+ { url = "https://files.pythonhosted.org/packages/22/6c/6ca91befbc0a6539ee133d9a9ce60b1a354db12c3c5d11cfdbf77140f851/ruff-0.11.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:86b3a27c38b8fce73bcd262b0de32e9a6801b76d52cdb3ae4c914515f0cef608", size = 12208721 },
225
+ { url = "https://files.pythonhosted.org/packages/19/b0/24516a3b850d55b17c03fc399b681c6a549d06ce665915721dc5d6458a5c/ruff-0.11.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3b66a03b248c9fcd9d64d445bafdf1589326bee6fc5c8e92d7562e58883e30f", size = 11662274 },
226
+ { url = "https://files.pythonhosted.org/packages/d7/65/76be06d28ecb7c6070280cef2bcb20c98fbf99ff60b1c57d2fb9b8771348/ruff-0.11.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0397c2672db015be5aa3d4dac54c69aa012429097ff219392c018e21f5085147", size = 13792284 },
227
+ { url = "https://files.pythonhosted.org/packages/ce/d2/4ceed7147e05852876f3b5f3fdc23f878ce2b7e0b90dd6e698bda3d20787/ruff-0.11.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:869bcf3f9abf6457fbe39b5a37333aa4eecc52a3b99c98827ccc371a8e5b6f1b", size = 11327861 },
228
+ { url = "https://files.pythonhosted.org/packages/c4/78/4935ecba13706fd60ebe0e3dc50371f2bdc3d9bc80e68adc32ff93914534/ruff-0.11.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2a2b50ca35457ba785cd8c93ebbe529467594087b527a08d487cf0ee7b3087e9", size = 10276560 },
229
+ { url = "https://files.pythonhosted.org/packages/81/7f/1b2435c3f5245d410bb5dc80f13ec796454c21fbda12b77d7588d5cf4e29/ruff-0.11.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7c69c74bf53ddcfbc22e6eb2f31211df7f65054bfc1f72288fc71e5f82db3eab", size = 9945091 },
230
+ { url = "https://files.pythonhosted.org/packages/39/c4/692284c07e6bf2b31d82bb8c32f8840f9d0627d92983edaac991a2b66c0a/ruff-0.11.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6e8fb75e14560f7cf53b15bbc55baf5ecbe373dd5f3aab96ff7aa7777edd7630", size = 10977133 },
231
+ { url = "https://files.pythonhosted.org/packages/94/cf/8ab81cb7dd7a3b0a3960c2769825038f3adcd75faf46dd6376086df8b128/ruff-0.11.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:842a472d7b4d6f5924e9297aa38149e5dcb1e628773b70e6387ae2c97a63c58f", size = 11378514 },
232
+ { url = "https://files.pythonhosted.org/packages/d9/3a/a647fa4f316482dacf2fd68e8a386327a33d6eabd8eb2f9a0c3d291ec549/ruff-0.11.2-py3-none-win32.whl", hash = "sha256:aca01ccd0eb5eb7156b324cfaa088586f06a86d9e5314b0eb330cb48415097cc", size = 10319835 },
233
+ { url = "https://files.pythonhosted.org/packages/86/54/3c12d3af58012a5e2cd7ebdbe9983f4834af3f8cbea0e8a8c74fa1e23b2b/ruff-0.11.2-py3-none-win_amd64.whl", hash = "sha256:3170150172a8f994136c0c66f494edf199a0bbea7a409f649e4bc8f4d7084080", size = 11373713 },
234
+ { url = "https://files.pythonhosted.org/packages/d6/d4/dd813703af8a1e2ac33bf3feb27e8a5ad514c9f219df80c64d69807e7f71/ruff-0.11.2-py3-none-win_arm64.whl", hash = "sha256:52933095158ff328f4c77af3d74f0379e34fd52f175144cefc1b192e7ccd32b4", size = 10441990 },
235
235
  ]
236
236
 
237
237
  [[package]]
238
238
  name = "sentry-sdk"
239
- version = "2.22.0"
239
+ version = "2.24.1"
240
240
  source = { registry = "https://pypi.org/simple" }
241
241
  dependencies = [
242
242
  { name = "certifi" },
243
243
  { name = "urllib3" },
244
244
  ]
245
- sdist = { url = "https://files.pythonhosted.org/packages/81/b6/662988ecd2345bf6c3a5c306a9a3590852742eff91d0a78a143398b816f3/sentry_sdk-2.22.0.tar.gz", hash = "sha256:b4bf43bb38f547c84b2eadcefbe389b36ef75f3f38253d7a74d6b928c07ae944", size = 303539 }
245
+ sdist = { url = "https://files.pythonhosted.org/packages/f1/ef/4847dcd63e3f3c451cf701a825d21200f1322d46ac97586d5c90a13dfea1/sentry_sdk-2.24.1.tar.gz", hash = "sha256:8ba3c29990fa48865b908b3b9dc5ae7fa7e72407c7c9e91303e5206b32d7b8b1", size = 318124 }
246
246
  wheels = [
247
- { url = "https://files.pythonhosted.org/packages/12/7f/0e4459173e9671ba5f75a48dda2442bcc48a12c79e54e5789381c8c6a9bc/sentry_sdk-2.22.0-py2.py3-none-any.whl", hash = "sha256:3d791d631a6c97aad4da7074081a57073126c69487560c6f8bffcf586461de66", size = 325815 },
247
+ { url = "https://files.pythonhosted.org/packages/65/95/91137ffe7a5956496155af5ffbe45ee4ddfa795a569136147e766abd14b1/sentry_sdk-2.24.1-py2.py3-none-any.whl", hash = "sha256:36baa6a1128b9d98d2adc5e9b2f887eff0a6af558fc2b96ed51919042413556d", size = 336945 },
248
248
  ]
249
249
 
250
250
  [[package]]
@@ -1,144 +0,0 @@
1
- import sentry_sdk
2
- from plain.runtime import settings
3
- from sentry_sdk.tracing import TRANSACTION_SOURCE_TASK
4
- from sentry_sdk.utils import capture_internal_exceptions
5
-
6
- try:
7
- from plain.models.db import connection
8
- except ImportError:
9
- connection = None
10
-
11
- import logging
12
-
13
- logger = logging.getLogger(__name__)
14
-
15
-
16
- def trace_db(execute, sql, params, many, context):
17
- with sentry_sdk.start_span(op="db", description=sql) as span:
18
- # Mostly borrowed from the Sentry Django integration...
19
- data = {
20
- "db.params": params,
21
- "db.executemany": many,
22
- "db.system": connection.vendor,
23
- "db.name": connection.settings_dict.get("NAME"),
24
- "db.user": connection.settings_dict.get("USER"),
25
- "server.address": connection.settings_dict.get("HOST"),
26
- "server.port": connection.settings_dict.get("PORT"),
27
- }
28
-
29
- sentry_sdk.add_breadcrumb(message=sql, category="query", data=data)
30
-
31
- for k, v in data.items():
32
- span.set_data(k, v)
33
-
34
- result = execute(sql, params, many, context)
35
-
36
- return result
37
-
38
-
39
- class SentryMiddleware:
40
- def __init__(self, get_response):
41
- self.get_response = get_response
42
-
43
- def __call__(self, request):
44
- def event_processor(event, hint):
45
- # request gets attached directly to an event,
46
- # not necessarily in the "context"
47
- request_info = event.setdefault("request", {})
48
- request_info["url"] = request.build_absolute_uri()
49
- request_info["method"] = request.method
50
- request_info["query_string"] = request.META.get("QUERY_STRING", "")
51
- # Headers and env need some PII filtering, ideally,
52
- # among other filters... similar for GET/POST data?
53
- # request_info["headers"] = dict(request.headers)
54
- try:
55
- request_info["data"] = request.body.decode("utf-8")
56
- except Exception:
57
- pass
58
-
59
- if user := getattr(request, "user", None):
60
- event["user"] = {"id": str(user.pk)}
61
- if settings.SENTRY_PII_ENABLED:
62
- if email := getattr(user, "email", None):
63
- event["user"]["email"] = email
64
- if username := getattr(user, "username", None):
65
- event["user"]["username"] = username
66
-
67
- return event
68
-
69
- # Reset the scope (and breadcrumbs) for each request
70
- scope = sentry_sdk.get_isolation_scope()
71
- scope.add_event_processor(event_processor)
72
-
73
- # Sentry's Django integration patches the WSGIHandler.
74
- # We could make our own WSGIHandler and patch it or call it directly from gunicorn,
75
- # but putting our middleware at the top of MIDDLEWARE is pretty close and easier.
76
- with sentry_sdk.start_transaction(
77
- op="http.server", name=request.path_info
78
- ) as transaction:
79
- if connection:
80
- # Also get spans for db queries
81
- with connection.execute_wrapper(trace_db):
82
- response = self.get_response(request)
83
- else:
84
- # No db presumably
85
- response = self.get_response(request)
86
-
87
- if resolver_match := getattr(request, "resolver_match", None):
88
- # Rename the transaction using a pattern,
89
- # and attach other url/views tags we can use to filter
90
- transaction.name = f"route:{resolver_match.route}"
91
- transaction.set_tag("url_namespace", resolver_match.namespace)
92
- transaction.set_tag("url_name", resolver_match.url_name)
93
- transaction.set_tag("view_name", resolver_match.view_name)
94
- transaction.set_tag("view_class", resolver_match._func_path)
95
- # Don't need to filter on this, but do want the context to view
96
- transaction.set_context(
97
- "url_params",
98
- {
99
- "args": resolver_match.args,
100
- "kwargs": resolver_match.kwargs,
101
- },
102
- )
103
-
104
- transaction.set_http_status(response.status_code)
105
-
106
- return response
107
-
108
-
109
- class SentryWorkerMiddleware:
110
- def __init__(self, run_job):
111
- self.run_job = run_job
112
-
113
- def __call__(self, job):
114
- def event_processor(event, hint):
115
- with capture_internal_exceptions():
116
- # Attach it directly to any events
117
- extra = event.setdefault("extra", {})
118
- extra["plain.worker"] = {"job": job.as_json()}
119
- return event
120
-
121
- # Reset the scope (and breadcrumbs) for each job
122
- scope = sentry_sdk.get_isolation_scope()
123
- scope.add_event_processor(event_processor)
124
-
125
- with sentry_sdk.start_transaction(
126
- op="plain.worker.job",
127
- name=f"job:{job.job_class}",
128
- source=TRANSACTION_SOURCE_TASK,
129
- ) as transaction:
130
- if connection:
131
- # Also get spans for db queries
132
- with connection.execute_wrapper(trace_db):
133
- job_result = self.run_job(job)
134
- else:
135
- # No db presumably
136
- job_result = self.run_job(job)
137
-
138
- with capture_internal_exceptions():
139
- # Don't need to filter on this, but do want the context to view
140
- transaction.set_context("job", job.as_json())
141
-
142
- transaction.set_status("ok")
143
-
144
- return job_result
File without changes
File without changes