diff --git a/.gitignore b/.gitignore index 69048bd..f0f2db8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea .DS_Store dump -.env \ No newline at end of file +.env +.venv \ No newline at end of file diff --git a/collector b/collector index 6794387..f0ff36f 160000 --- a/collector +++ b/collector @@ -1 +1 @@ -Subproject commit 67943874805c15f54cb6bb475d4f11ddff2f6835 +Subproject commit f0ff36fa09332233a7a02d6ef22adbf2a543fa0b diff --git a/tests/manual/sentry/README.md b/tests/manual/sentry/README.md new file mode 100644 index 0000000..879ee75 --- /dev/null +++ b/tests/manual/sentry/README.md @@ -0,0 +1,86 @@ +# Installation + +``` +pip install sentry-sdk +``` + +# Message structure + +A Sentry envelope is typically a structured format consisting of multiple JSON parts concatenated together. It starts with a header, followed by one or more items separated by **newlines**, with each item having its own header and body. + +## Structure of a Sentry Envelope +1. Envelope Header (JSON): Describes the envelope metadata (e.g., dsn, event_id). +2. Item Header (JSON): Precedes each item, describing its type (e.g., event, transaction) and optional metadata like length. +3. Item Payload (Optional JSON): The actual data of the item. + +Example Sentry Envelope: +```{"event_id":"1234", "dsn":"https://example.com"} +{"type":"event", "length":30} +{"key":"value"} +{"type":"attachment", "length":14} +"sample-attachment" +``` + +## Structure parser +``` +type SentryEnvelope struct { + Header map[string]interface{} + Items []SentryItem +} +type SentryItem struct { + Header map[string]interface{} + Payload map[string]interface{} +} + +func parseSentryEnvelope(data string, envelope *SentryEnvelope) error { + scanner := bufio.NewScanner(strings.NewReader(data)) + scanner.Split(bufio.ScanLines) + + // Parse the envelope header + if !scanner.Scan() { + return fmt.Errorf("failed to read envelope header") + } + envelopeHeader := scanner.Text() + envelope.Header = make(map[string]interface{}) + if err := json.Unmarshal([]byte(envelopeHeader), &envelope.Header); err != nil { + return fmt.Errorf("failed to parse envelope header: %w", err) + } + + // Parse each item + for scanner.Scan() { + itemHeader := scanner.Text() + var item SentryItem + item.Header = make(map[string]interface{}) + if err := json.Unmarshal([]byte(itemHeader), &item.Header); err != nil { + return fmt.Errorf("failed to parse item header: %w", err) + } + + // Parse the item payload + if scanner.Scan() { + itemPayload := scanner.Text() + item.Payload = make(map[string]interface{}) + + if err := json.Unmarshal([]byte(itemPayload), &item.Payload); err != nil { + return fmt.Errorf("failed to parse item payload: %w", err) + } + } + envelope.Items = append(envelope.Items, item) + } + + if err := scanner.Err(); err != nil { + return fmt.Errorf("error reading envelope: %w", err) + } + + return nil +} +``` +can be used as: +``` +var envelope SentryEnvelope +err = parseSentryEnvelope(jsonBody, &envelope) +if err != nil { + log.Warnf("Failed to parse Sentry envelope: %s", err) + sendAnswerHTTP(ctx, ResponseMessage{Code: 400, Error: true, Message: "Failed to parse Sentry envelope"}) + return +} +``` \ No newline at end of file diff --git a/tests/manual/sentry/sample.json b/tests/manual/sentry/sample.json new file mode 100644 index 0000000..9e87ab1 --- /dev/null +++ b/tests/manual/sentry/sample.json @@ -0,0 +1,117 @@ +{ + "event_id": "578bb342942644b3b87a2c159e93a686", + "sent_at": "2024-11-29T11:05:07.097039Z", + "trace": { + "trace_id": "8cf021164d244e678118a48f0181b712", + "environment": "production", + "release": "35c42f2ddf524bbdafe22439b981ddfd0fb3b5ad", + "public_key": "eyJpbnRlZ3JhdGlvbklkIjoiYzlmZTY1MzYtYjVkYi00NDNmLWI1MmEtMWQwNDY1OThkNDNiIiwic2VjcmV0IjoiNzAwZTAwYTQtM2E4Mi00NTQ3LTkzOGUtMTMzMGJhNzgwY2UwIn0=" + } +} +{ + "type": "event", + "content_type": "application/json", + "length": 1898 +} +{ + "level": "error", + "exception": { + "values": [ + { + "mechanism": { + "type": "excepthook", + "handled": false + }, + "module": null, + "type": "ZeroDivisionError", + "value": "division by zero", + "stacktrace": { + "frames": [ + { + "filename": "sentry-send.py", + "abs_path": "/Users/nostr/dev/codex/hawk.mono/tests/manual/sentry/sentry-send.py", + "function": "", + "module": "__main__", + "lineno": 12, + "pre_context": [ + "", + "sentry_sdk.init(", + " dsn=f\"http://{HAWK_INTEGRATION_TOKEN}@localhost:3000/0\",", + " debug=True", + ")" + ], + "context_line": "division_by_zero = 1 / 0", + "post_context": [], + "vars": { + "__name__": "'__main__'", + "__doc__": "None", + "__package__": "None", + "__loader__": "<_frozen_importlib_external.SourceFileLoader object at 0x104d9d020>", + "__spec__": "None", + "__annotations__": {}, + "__builtins__": "", + "__file__": "'/Users/nostr/dev/codex/hawk.mono/tests/manual/sentry/sentry-send.py'", + "__cached__": "None", + "sentry_sdk": "" + }, + "in_app": true + } + ] + } + } + ] + }, + "event_id": "578bb342942644b3b87a2c159e93a686", + "timestamp": "2024-11-29T11:05:07.092339Z", + "contexts": { + "trace": { + "trace_id": "8cf021164d244e678118a48f0181b712", + "span_id": "92154e1d8745dd3f", + "parent_span_id": null + }, + "runtime": { + "name": "CPython", + "version": "3.13.0", + "build": "3.13.0 (main, Oct 7 2024, 05:02:14) [Clang 16.0.0 (clang-1600.0.26.3)]" + } + }, + "transaction_info": {}, + "breadcrumbs": { + "values": [] + }, + "extra": { + "sys.argv": [ + "sentry-send.py" + ] + }, + "modules": { + "pip": "24.3.1", + "urllib3": "2.2.3", + "sentry-sdk": "2.19.0", + "certifi": "2024.8.30" + }, + "release": "35c42f2ddf524bbdafe22439b981ddfd0fb3b5ad", + "environment": "production", + "server_name": "MacBook.local", + "sdk": { + "name": "sentry.python", + "version": "2.19.0", + "packages": [ + { + "name": "pypi:sentry-sdk", + "version": "2.19.0" + } + ], + "integrations": [ + "argv", + "atexit", + "dedupe", + "excepthook", + "logging", + "modules", + "stdlib", + "threading" + ] + }, + "platform": "python" +} \ No newline at end of file diff --git a/tests/manual/sentry/sentry-send.py b/tests/manual/sentry/sentry-send.py new file mode 100644 index 0000000..209549c --- /dev/null +++ b/tests/manual/sentry/sentry-send.py @@ -0,0 +1,11 @@ +import sentry_sdk +import os + +HAWK_INTEGRATION_TOKEN = os.getenv("SENTRY_PROJECT_ID", "eyJpbnRlZ3JhdGlvbklkIjoiOWQ0MzUwMzgtMWQ3OS00NTlhLWJhMWUtZWQwMDVjYzI0NTM0Iiwic2VjcmV0IjoiZGU3ODZkMDAtNzE2Ni00ZTYzLWI5YzAtYTFjNjcyOWZlOGU5In0=") + +sentry_sdk.init( + dsn=f"http://{HAWK_INTEGRATION_TOKEN}@localhost:3000/0", + debug=True +) +division_by_zero = 1 / 0 +# raise Exception("This is a test exception") \ No newline at end of file diff --git a/workers b/workers index ced34da..053def3 160000 --- a/workers +++ b/workers @@ -1 +1 @@ -Subproject commit ced34da14ac672cbbe54c540cc4c0bce74fef100 +Subproject commit 053def398e2ee08eb385d4df11f6cfd7c884e579