Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow some non-Golang interfaces to be passed through in Events. #606

Merged
merged 2 commits into from
Mar 29, 2023
Merged
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
29 changes: 29 additions & 0 deletions interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,34 @@ type TransactionInfo struct {
Source TransactionSource `json:"source,omitempty"`
}

// The DebugMeta interface is not used in Golang apps, but may be populated
// when proxying Events from other platforms, like iOS, Android, and the
// Web. (See: https://develop.sentry.dev/sdk/event-payloads/debugmeta/ ).
type DebugMeta struct {
SdkInfo *DebugMetaSdkInfo `json:"sdk_info,omitempty"`
Images []DebugMetaImage `json:"images,omitempty"`
}

type DebugMetaSdkInfo struct {
SdkName string `json:"sdk_name,omitempty"`
VersionMajor int `json:"version_major,omitempty"`
VersionMinor int `json:"version_minor,omitempty"`
VersionPatchlevel int `json:"version_patchlevel,omitempty"`
}

type DebugMetaImage struct {
Type string `json:"type,omitempty"` // all
ImageAddr string `json:"image_addr,omitempty"` // macho,elf,pe
ImageSize int `json:"image_size,omitempty"` // macho,elf,pe
DebugID string `json:"debug_id,omitempty"` // macho,elf,pe,wasm,sourcemap
DebugFile string `json:"debug_file,omitempty"` // macho,elf,pe,wasm
CodeID string `json:"code_id,omitempty"` // macho,elf,pe,wasm
CodeFile string `json:"code_file,omitempty"` // macho,elf,pe,wasm,sourcemap
ImageVmaddr string `json:"image_vmaddr,omitempty"` // macho,elf,pe
Arch string `json:"arch,omitempty"` // macho,elf,pe
UUID string `json:"uuid,omitempty"` // proguard
}

// EventID is a hexadecimal string representing a unique uuid4 for an Event.
// An EventID must be 32 characters long, lowercase and not have any dashes.
type EventID string
Expand Down Expand Up @@ -271,6 +299,7 @@ type Event struct {
Modules map[string]string `json:"modules,omitempty"`
Request *Request `json:"request,omitempty"`
Exception []Exception `json:"exception,omitempty"`
DebugMeta *DebugMeta `json:"debug_meta,omitempty"`

// The fields below are only relevant for transactions.

Expand Down
55 changes: 55 additions & 0 deletions interfaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,61 @@ func TestEventMarshalJSON(t *testing.T) {
}
}

func TestEventWithDebugMetaMarshalJSON(t *testing.T) {
event := NewEvent()
event.DebugMeta = &DebugMeta{
SdkInfo: &DebugMetaSdkInfo{
SdkName: "test",
VersionMajor: 1,
VersionMinor: 2,
VersionPatchlevel: 3,
},
Images: []DebugMetaImage{
{
Type: "macho",
ImageAddr: "0xabcd0000",
ImageSize: 32768,
DebugID: "42DB5B96-5144-4079-BE09-45E2142CA3E5",
DebugFile: "foo.dSYM",
CodeID: "A7AF6477-9130-4EB7-ADFE-AD0F57001DBD",
CodeFile: "foo.dylib",
ImageVmaddr: "0x0",
Arch: "arm64",
},
{
Type: "proguard",
UUID: "982E62D4-6493-4E43-864B-6523C79C7064",
},
},
}
tonyo marked this conversation as resolved.
Show resolved Hide resolved

got, err := json.Marshal(event)
if err != nil {
t.Fatal(err)
}

want := `{"sdk":{},"user":{},` +
`"debug_meta":{` +
`"sdk_info":{"sdk_name":"test","version_major":1,"version_minor":2,"version_patchlevel":3},` +
`"images":[` +
`{"type":"macho",` +
`"image_addr":"0xabcd0000",` +
`"image_size":32768,` +
`"debug_id":"42DB5B96-5144-4079-BE09-45E2142CA3E5",` +
`"debug_file":"foo.dSYM",` +
`"code_id":"A7AF6477-9130-4EB7-ADFE-AD0F57001DBD",` +
`"code_file":"foo.dylib",` +
`"image_vmaddr":"0x0",` +
`"arch":"arm64"` +
`},` +
`{"type":"proguard","uuid":"982E62D4-6493-4E43-864B-6523C79C7064"}` +
`]}}`

if diff := cmp.Diff(want, string(got)); diff != "" {
t.Errorf("Event mismatch (-want +got):\n%s", diff)
}
}

func TestMechanismMarshalJSON(t *testing.T) {
mechanism := &Mechanism{
Type: "some type",
Expand Down
20 changes: 13 additions & 7 deletions stacktrace.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,7 @@ type Frame struct {
Symbol string `json:"symbol,omitempty"`
// Module is, despite the name, the Sentry protocol equivalent of a Go
// package's import path.
Module string `json:"module,omitempty"`
// Package is not used for Go stack trace frames. In other platforms it
// refers to a container where the Module can be found. For example, a
// Java JAR, a .NET Assembly, or a native dynamic library.
// It exists for completeness, allowing the construction and reporting
// of custom event payloads.
Package string `json:"package,omitempty"`
Module string `json:"module,omitempty"`
Filename string `json:"filename,omitempty"`
AbsPath string `json:"abs_path,omitempty"`
Lineno int `json:"lineno,omitempty"`
Expand All @@ -182,6 +176,18 @@ type Frame struct {
PostContext []string `json:"post_context,omitempty"`
InApp bool `json:"in_app,omitempty"`
Vars map[string]interface{} `json:"vars,omitempty"`
// Package and the below are not used for Go stack trace frames. In
// other platforms it refers to a container where the Module can be
// found. For example, a Java JAR, a .NET Assembly, or a native
// dynamic library. They exists for completeness, allowing the
// construction and reporting of custom event payloads.
Package string `json:"package,omitempty"`
InstructionAddr string `json:"instruction_addr,omitempty"`
AddrMode string `json:"addr_mode,omitempty"`
SymbolAddr string `json:"symbol_addr,omitempty"`
ImageAddr string `json:"image_addr,omitempty"`
Platform string `json:"platform,omitempty"`
StackStart bool `json:"stack_start,omitempty"`
}

// NewFrame assembles a stacktrace frame out of runtime.Frame.
Expand Down
73 changes: 73 additions & 0 deletions stacktrace_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sentry

import (
"encoding/json"
"errors"
"testing"

Expand Down Expand Up @@ -169,3 +170,75 @@ func TestExtractXErrorsPC(t *testing.T) {
t.Errorf("got %#v, want nil", got)
}
}

func TestEventWithExceptionStacktraceMarshalJSON(t *testing.T) {
event := NewEvent()
event.Exception = []Exception{
{
Stacktrace: &Stacktrace{
Frames: []Frame{
{
Function: "gofunc",
Symbol: "gosym",
Module: "gopkg/gopath",
Filename: "foo.go",
AbsPath: "/something/foo.go",
Lineno: 35,
Colno: 72,
PreContext: []string{"pre", "context"},
ContextLine: "contextline",
PostContext: []string{"post", "context"},
InApp: true,
Vars: map[string]interface{}{
"foostr": "bar",
"fooint": 25,
},
},
{
Symbol: "nativesym",
Package: "my.dylib",
InstructionAddr: "0xabcd0010",
AddrMode: "abs",
SymbolAddr: "0xabcd0000",
ImageAddr: "0xabc00000",
Platform: "native",
StackStart: false,
},
},
},
},
}

got, err := json.Marshal(event)
if err != nil {
t.Fatal(err)
}

want := `{"sdk":{},"user":{},` +
`"exception":[{"stacktrace":{"frames":[` +
`{"function":"gofunc",` +
`"symbol":"gosym",` +
`"module":"gopkg/gopath",` +
`"filename":"foo.go",` +
`"abs_path":"/something/foo.go",` +
`"lineno":35,` +
`"colno":72,` +
`"pre_context":["pre","context"],` +
`"context_line":"contextline",` +
`"post_context":["post","context"],` +
`"in_app":true,` +
`"vars":{"fooint":25,"foostr":"bar"}` +
`},{` +
`"symbol":"nativesym",` +
`"package":"my.dylib",` +
`"instruction_addr":"0xabcd0010",` +
`"addr_mode":"abs",` +
`"symbol_addr":"0xabcd0000",` +
`"image_addr":"0xabc00000",` +
`"platform":"native"` +
`}]}}]}`

if diff := cmp.Diff(want, string(got)); diff != "" {
t.Errorf("Event mismatch (-want +got):\n%s", diff)
}
}