diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f64a57..b800d86 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 diff --git a/backtracepython/__init__.py b/backtracepython/__init__.py index c4a8028..5782668 100644 --- a/backtracepython/__init__.py +++ b/backtracepython/__init__.py @@ -9,6 +9,11 @@ import simplejson as json +if sys.version_info.major >= 3: + from urllib.parse import urlencode +else: + from urllib import urlencode + __all__ = ["BacktraceReport", "initialize", "finalize", "terminate", "version", "version_string", "send_last_exception", "send_report"] class version: @@ -20,7 +25,6 @@ class version: class globs: endpoint = None - token = None next_except_hook = None debug_backtrace = False timeout = None @@ -199,7 +203,6 @@ def send(self): 'report': self.report, 'context_line_count': globs.context_line_count, 'timeout': globs.timeout, - 'token': globs.token, 'endpoint': globs.endpoint, 'tab_width': globs.tab_width, 'debug_backtrace': globs.debug_backtrace, @@ -234,8 +237,7 @@ def bt_except_hook(ex_type, ex_value, ex_traceback): globs.next_except_hook(ex_type, ex_value, ex_traceback) def initialize(**kwargs): - globs.endpoint = kwargs['endpoint'] - globs.token = kwargs['token'] + globs.endpoint = construct_submission_url(kwargs['endpoint'], kwargs.get('token', None)) globs.debug_backtrace = kwargs.get('debug_backtrace', False) globs.timeout = kwargs.get('timeout', 4) globs.tab_width = kwargs.get('tab_width', 8) @@ -251,6 +253,15 @@ def initialize(**kwargs): globs.next_except_hook = sys.excepthook sys.excepthook = bt_except_hook +def construct_submission_url(endpoint, token): + if "submit.backtrace.io" in endpoint or token is None: + return endpoint + + return "{}/post?{}".format(endpoint, urlencode({ + 'token': token, + 'format': "json", + })) + def finalize(): send_worker_msg({ 'id': 'terminate' }) if not globs.debug_backtrace: diff --git a/backtracepython/child.py b/backtracepython/child.py index dc3ccb9..99ba8d9 100644 --- a/backtracepython/child.py +++ b/backtracepython/child.py @@ -1,14 +1,14 @@ from __future__ import print_function -import sys + import os +import sys + import simplejson as json if sys.version_info.major >= 3: - from urllib.parse import urlencode from urllib.request import Request from urllib.request import urlopen else: - from urllib import urlencode from urllib2 import urlopen from urllib2 import Request @@ -20,16 +20,15 @@ class globs: def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) -def post_json(endpoint, path, query, obj): +def post_json(full_url, obj): if globs.debug_backtrace: + eprint(full_url) eprint(json.dumps(obj, indent=2, ignore_nan=True)) payload = json.dumps(obj, ignore_nan=True).encode('utf-8') - query = urlencode(query) headers = { 'Content-Type': "application/json", 'Content-Length': len(payload), } - full_url = "{}/post?{}".format(endpoint, query) req = Request(full_url, payload, headers) resp = urlopen(req) if resp.code != 200: @@ -75,13 +74,7 @@ def prepare_and_send_report(msg): source_code = msg['source_code'] collect_source_code(report, source_code) - endpoint = msg['endpoint'] - token = msg['token'] - query = { - 'token': token, - 'format': "json", - } - post_json(endpoint, "/post", query, report) + post_json(msg['endpoint'], report) for line in sys.stdin: msg = json.loads(line) @@ -90,4 +83,4 @@ def prepare_and_send_report(msg): elif msg['id'] == 'send': prepare_and_send_report(msg) else: - raise Error("invalid message id", msg['id']) + raise Exception("invalid message id", msg['id']) diff --git a/example/__init__.py b/example/__init__.py new file mode 100644 index 0000000..0a26ece --- /dev/null +++ b/example/__init__.py @@ -0,0 +1,32 @@ +import os + +import backtracepython as backtrace + + +def open_file(name): + open(name).read() + +def main(): + backtrace.initialize( + endpoint= os.getenv('BACKTRACE_SUBMISSION_URL', '"https://submit.backtrace.io/your-universe/token/json"'), + attributes = { + 'application': 'example-app', + 'application.version': '1.0.0', + 'version': '1.0.0' + } + ) + + # send an exception from the try/catch block + try: + open_file("not existing file") + except: + backtrace.send_last_exception() + + # send a message + backtrace.send_report("test message") + + # generate and send unhandled exception + open_file("not existing file") + +if __name__ == "__main__": + main() diff --git a/tests/test_submission_url.py b/tests/test_submission_url.py new file mode 100644 index 0000000..e70c9f4 --- /dev/null +++ b/tests/test_submission_url.py @@ -0,0 +1,16 @@ +from backtracepython import construct_submission_url + +universe = "test" +hostname = "https://{}.sp.backtrace.io".format(universe) +token = "1234567812345678123456781234567812345678123456781234567812345678" + +submit_url = "https://submit.backtrace.io/{}/{}/json".format(universe, token) +def test_direct_submission_url(): + expected_direct_submission_url = "{}/post?token={}&format=json".format(hostname, token) + assert construct_submission_url(hostname, token) == expected_direct_submission_url + +def test_submit_submission_url(): + assert construct_submission_url(submit_url, None) == submit_url + +def test_submit_submission_url_when_token_available(): + assert construct_submission_url(submit_url, token) == submit_url