usetraceforge 1.0.0__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.
- usetraceforge-1.0.0/PKG-INFO +11 -0
- usetraceforge-1.0.0/setup.cfg +4 -0
- usetraceforge-1.0.0/setup.py +13 -0
- usetraceforge-1.0.0/traceforge/__init__.py +3 -0
- usetraceforge-1.0.0/traceforge/client.py +101 -0
- usetraceforge-1.0.0/traceforge/integrations/__init__.py +1 -0
- usetraceforge-1.0.0/traceforge/integrations/django.py +21 -0
- usetraceforge-1.0.0/traceforge/integrations/fastapi.py +32 -0
- usetraceforge-1.0.0/usetraceforge.egg-info/PKG-INFO +11 -0
- usetraceforge-1.0.0/usetraceforge.egg-info/SOURCES.txt +11 -0
- usetraceforge-1.0.0/usetraceforge.egg-info/dependency_links.txt +1 -0
- usetraceforge-1.0.0/usetraceforge.egg-info/requires.txt +1 -0
- usetraceforge-1.0.0/usetraceforge.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: usetraceforge
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: TraceForge Python SDK for unhandled panic logging
|
|
5
|
+
Home-page: https://github.com/khushalp2004/TraceForge
|
|
6
|
+
Author: Khushal Patil
|
|
7
|
+
Requires-Dist: requests>=2.31.0
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: home-page
|
|
10
|
+
Dynamic: requires-dist
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="usetraceforge",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
install_requires=[
|
|
8
|
+
"requests>=2.31.0"
|
|
9
|
+
],
|
|
10
|
+
author="Khushal Patil",
|
|
11
|
+
description="TraceForge Python SDK for unhandled panic logging",
|
|
12
|
+
url="https://github.com/khushalp2004/TraceForge"
|
|
13
|
+
)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import traceback
|
|
3
|
+
import requests
|
|
4
|
+
import threading
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
_config = {}
|
|
8
|
+
_setup_handshake_sent = False
|
|
9
|
+
|
|
10
|
+
def init(api_key: str, endpoint: str = "http://localhost:3001/ingest", auto_capture: bool = True):
|
|
11
|
+
if not api_key:
|
|
12
|
+
raise ValueError("TraceForge.init() failed: Missing API Key.")
|
|
13
|
+
|
|
14
|
+
_config["api_key"] = api_key
|
|
15
|
+
_config["endpoint"] = endpoint
|
|
16
|
+
|
|
17
|
+
# Send setup handshake
|
|
18
|
+
threading.Thread(target=_send_setup_handshake, daemon=True).start()
|
|
19
|
+
|
|
20
|
+
if auto_capture:
|
|
21
|
+
_setup_auto_capture()
|
|
22
|
+
|
|
23
|
+
def _get_setup_endpoint() -> str:
|
|
24
|
+
base = _config.get("endpoint", "").rstrip("/")
|
|
25
|
+
if base.endswith("/setup"):
|
|
26
|
+
return base
|
|
27
|
+
return f"{base}/setup"
|
|
28
|
+
|
|
29
|
+
def _send_setup_handshake():
|
|
30
|
+
global _setup_handshake_sent
|
|
31
|
+
if _setup_handshake_sent or not _config.get("api_key"):
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
res = requests.post(
|
|
36
|
+
_get_setup_endpoint(),
|
|
37
|
+
json={"environment": "python"},
|
|
38
|
+
headers={
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
"X-Traceforge-Key": _config["api_key"]
|
|
41
|
+
},
|
|
42
|
+
timeout=5
|
|
43
|
+
)
|
|
44
|
+
if res.status_code < 400:
|
|
45
|
+
_setup_handshake_sent = True
|
|
46
|
+
except Exception:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
def _send_payload(payload):
|
|
50
|
+
api_key = _config.get("api_key")
|
|
51
|
+
endpoint = _config.get("endpoint")
|
|
52
|
+
if not api_key or not endpoint:
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
headers = {
|
|
56
|
+
"X-Traceforge-Key": api_key,
|
|
57
|
+
"Content-Type": "application/json"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
requests.post(endpoint, json=payload, headers=headers, timeout=5)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def capture_exception(exc: Exception, tags: dict = None, payload: dict = None):
|
|
66
|
+
if not _config.get("api_key"):
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
message = str(exc) or exc.__class__.__name__
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
stack_trace = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
|
|
73
|
+
except Exception:
|
|
74
|
+
stack_trace = traceback.format_exc()
|
|
75
|
+
|
|
76
|
+
event = {
|
|
77
|
+
"message": message,
|
|
78
|
+
"stackTrace": stack_trace,
|
|
79
|
+
"environment": "python",
|
|
80
|
+
"tags": tags or {},
|
|
81
|
+
"payload": payload or {}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# We use threading to send this synchronously in the background
|
|
85
|
+
threading.Thread(target=_send_payload, args=(event,), daemon=True).start()
|
|
86
|
+
|
|
87
|
+
def capture_message(message: str, level: str = "info", context: dict = None):
|
|
88
|
+
# Backward compatibility
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
def _setup_auto_capture():
|
|
92
|
+
# Hook into sys.excepthook to catch all unhandled exceptions
|
|
93
|
+
original_excepthook = sys.excepthook
|
|
94
|
+
|
|
95
|
+
def traceforge_excepthook(exc_type, exc_value, exc_traceback):
|
|
96
|
+
if exc_value:
|
|
97
|
+
capture_exception(exc_value, tags={"uncaught": "true"})
|
|
98
|
+
# Call the original excepthook to not break default behavior
|
|
99
|
+
original_excepthook(exc_type, exc_value, exc_traceback)
|
|
100
|
+
|
|
101
|
+
sys.excepthook = traceforge_excepthook
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Integrations for TraceForge
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from traceforge.client import capture_exception
|
|
2
|
+
|
|
3
|
+
class TraceForgeMiddleware:
|
|
4
|
+
def __init__(self, get_response):
|
|
5
|
+
self.get_response = get_response
|
|
6
|
+
|
|
7
|
+
def __call__(self, request):
|
|
8
|
+
return self.get_response(request)
|
|
9
|
+
|
|
10
|
+
def process_exception(self, request, exception):
|
|
11
|
+
# Capture the exception asynchronously
|
|
12
|
+
payload = {
|
|
13
|
+
"url": request.build_absolute_uri(),
|
|
14
|
+
"method": request.method,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# We don't want to block the Django response
|
|
18
|
+
capture_exception(exception, tags={"framework": "django"}, payload=payload)
|
|
19
|
+
|
|
20
|
+
# Return None to let Django's default exception handling continue
|
|
21
|
+
return None
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from traceforge.client import capture_exception
|
|
2
|
+
|
|
3
|
+
def init(app):
|
|
4
|
+
"""
|
|
5
|
+
Registers a global exception handler for FastAPI/Starlette applications.
|
|
6
|
+
"""
|
|
7
|
+
try:
|
|
8
|
+
from fastapi import Request
|
|
9
|
+
from starlette.responses import JSONResponse
|
|
10
|
+
from starlette.exceptions import HTTPException
|
|
11
|
+
except ImportError:
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
@app.exception_handler(Exception)
|
|
15
|
+
async def traceforge_exception_handler(request: Request, exc: Exception):
|
|
16
|
+
# Don't capture standard HTTPExceptions (like 404s) as crashes
|
|
17
|
+
if isinstance(exc, HTTPException) and exc.status_code < 500:
|
|
18
|
+
raise exc
|
|
19
|
+
|
|
20
|
+
payload = {
|
|
21
|
+
"url": str(request.url),
|
|
22
|
+
"method": request.method,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
capture_exception(exc, tags={"framework": "fastapi"}, payload=payload)
|
|
26
|
+
|
|
27
|
+
# Re-raise the exception to let FastAPI handle it natively
|
|
28
|
+
# Or return a 500 JSON response if we prefer to mask it
|
|
29
|
+
return JSONResponse(
|
|
30
|
+
status_code=500,
|
|
31
|
+
content={"detail": "Internal Server Error"}
|
|
32
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: usetraceforge
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: TraceForge Python SDK for unhandled panic logging
|
|
5
|
+
Home-page: https://github.com/khushalp2004/TraceForge
|
|
6
|
+
Author: Khushal Patil
|
|
7
|
+
Requires-Dist: requests>=2.31.0
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: home-page
|
|
10
|
+
Dynamic: requires-dist
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
setup.py
|
|
2
|
+
traceforge/__init__.py
|
|
3
|
+
traceforge/client.py
|
|
4
|
+
traceforge/integrations/__init__.py
|
|
5
|
+
traceforge/integrations/django.py
|
|
6
|
+
traceforge/integrations/fastapi.py
|
|
7
|
+
usetraceforge.egg-info/PKG-INFO
|
|
8
|
+
usetraceforge.egg-info/SOURCES.txt
|
|
9
|
+
usetraceforge.egg-info/dependency_links.txt
|
|
10
|
+
usetraceforge.egg-info/requires.txt
|
|
11
|
+
usetraceforge.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.31.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
traceforge
|