Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea
.DS_Store
dump
.env
.env
.venv
86 changes: 86 additions & 0 deletions tests/manual/sentry/README.md
Original file line number Diff line number Diff line change
@@ -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
}
```
117 changes: 117 additions & 0 deletions tests/manual/sentry/sample.json
Original file line number Diff line number Diff line change
@@ -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>",
"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__": "<module 'builtins' (built-in)>",
"__file__": "'/Users/nostr/dev/codex/hawk.mono/tests/manual/sentry/sentry-send.py'",
"__cached__": "None",
"sentry_sdk": "<module 'sentry_sdk' from '/Users/nostr/dev/codex/hawk.mono/.venv/lib/python3.13/site-packages/sentry_sdk/__init__.py'>"
},
"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"
}
11 changes: 11 additions & 0 deletions tests/manual/sentry/sentry-send.py
Original file line number Diff line number Diff line change
@@ -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")
Loading