From 1d9eeeaf7aec4f5be410a12ff0b818ef2d73f6ef Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 1 Jun 2020 15:48:17 -0400 Subject: [PATCH] ref: Append Event struct with transaction --- client.go | 2 +- interfaces.go | 117 ++++++++++++------------------------ interfaces_test.go | 24 -------- testdata/transaction.golden | 34 ----------- transport.go | 68 +++------------------ 5 files changed, 49 insertions(+), 196 deletions(-) delete mode 100644 testdata/transaction.golden diff --git a/client.go b/client.go index aaf9590d9..402c4256d 100644 --- a/client.go +++ b/client.go @@ -380,7 +380,7 @@ func (client *Client) processEvent(event *Event, hint *EventHint, scope EventMod return nil } - if options.BeforeSend != nil { + if event.Type != "transaction" && options.BeforeSend != nil { h := &EventHint{} if hint != nil { h = hint diff --git a/interfaces.go b/interfaces.go index 527dd113b..a55b4ae4f 100644 --- a/interfaces.go +++ b/interfaces.go @@ -143,7 +143,40 @@ type Exception struct { type EventID string -// Events are the fundamental data structure that are send to Sentry +// TraceContext describes the context of the trace. +type TraceContext struct { + TraceID string `json:"trace_id"` + SpanID string `json:"span_id"` + Op string `json:"op,omitempty"` + Description string `json:"description,omitempty"` +} + +// Span describes a AM Span following the Sentry format. +// Experimental: This is part of a beta feature of the SDK +type Span struct { + TraceID string `json:"trace_id"` + SpanID string `json:"span_id"` + ParentSpanID string `json:"parent_span_id,omitempty"` + Description string `json:"description,omitempty"` + Op string `json:"op,omitempty"` + Tags map[string]string `json:"tags,omitempty"` + StartTimestamp time.Time `json:"start_timestamp"` + EndTimestamp time.Time `json:"timestamp"` + Status string `json:"status"` +} + +// MarshalJSON converts the Span struct to JSON. +func (s *Span) MarshalJSON() ([]byte, error) { + type alias Span + + return json.Marshal(&struct { + *alias + }{ + alias: (*alias)(s), + }) +} + +// Event is the fundamental data structure that is sent to Sentry type Event struct { Type string `json:"type,omitempty"` Breadcrumbs []*Breadcrumb `json:"breadcrumbs,omitempty"` @@ -168,8 +201,12 @@ type Event struct { Modules map[string]string `json:"modules,omitempty"` Request *Request `json:"request,omitempty"` Exception []Exception `json:"exception,omitempty"` + // Experimental: This is part of a beta feature of the SDK + StartTimestamp time.Time `json:"start_timestamp"` + Spans []*Span `json:"spans,omitempty"` } +// MarshalJSON converts the Event struct to JSON. func (e *Event) MarshalJSON() ([]byte, error) { type alias Event // encoding/json doesn't support the "omitempty" option for struct types. @@ -220,81 +257,3 @@ type EventHint struct { Request *http.Request Response *http.Response } - -// Span describes a AM Span following the Sentry format. -type Span struct { - TraceID string `json:"trace_id"` - SpanID string `json:"span_id"` - ParentSpanID string `json:"parent_span_id,omitempty"` - Description string `json:"description,omitempty"` - Op string `json:"op,omitempty"` - Tags map[string]string `json:"tags,omitempty"` - StartTimestamp time.Time `json:"start_timestamp"` - EndTimestamp time.Time `json:"timestamp"` - Status string `json:"status"` -} - -// MarshalJSON converts the Span struct to JSON. -func (s *Span) MarshalJSON() ([]byte, error) { - type alias Span - - if s.EndTimestamp.IsZero() || s.StartTimestamp.IsZero() { - return json.Marshal(&struct { - *alias - StartTimestamp json.RawMessage `json:"start_timestamp,omitempty"` - EndTimestamp json.RawMessage `json:"timestamp,omitempty"` - }{ - alias: (*alias)(s), - }) - } - - return json.Marshal(&struct { - *alias - }{ - alias: (*alias)(s), - }) -} - -// SentryEvent aliases the sentry Event type. -// Needed to Marshal the transactions into JSON properly. -type sentryEvent Event - -// TraceContext describes the trace context of a transaction. -type TraceContext struct { - TraceID string `json:"trace_id"` - SpanID string `json:"span_id"` - Op string `json:"op,omitempty"` - Description string `json:"description,omitempty"` -} - -// Transaction describes a Sentry Transaction. -type Transaction struct { - *sentryEvent - StartTimestamp time.Time `json:"start_timestamp"` - Spans []*Span `json:"spans,omitempty"` -} - -// MarshalJSON converts the Transaction struct to JSON. -func (t *Transaction) MarshalJSON() ([]byte, error) { - type alias Transaction - - if t.Timestamp.IsZero() || t.StartTimestamp.IsZero() { - return json.Marshal(&struct { - *alias - StartTimestamp json.RawMessage `json:"start_timestamp,omitempty"` - EndTimestamp json.RawMessage `json:"timestamp,omitempty"` - Type string `json:"type"` - }{ - Type: "transaction", - alias: (*alias)(t), - }) - } - - return json.Marshal(&struct { - *alias - Type string `json:"type"` - }{ - Type: "transaction", - alias: (*alias)(t), - }) -} diff --git a/interfaces_test.go b/interfaces_test.go index fab0e2c5e..a4b71837f 100644 --- a/interfaces_test.go +++ b/interfaces_test.go @@ -63,30 +63,6 @@ func TestMarshalStruct(t *testing.T) { testName: "span", sentryStruct: testSpan, }, - { - testName: "transaction", - sentryStruct: func() *Transaction { - event := NewEvent() - - event.Contexts["trace"] = TraceContext{ - TraceID: "d6c4f03650bd47699ec65c84352b6208", - SpanID: "442bd97bbe564317", - Op: "http.server", - Description: "/api/users/{user_id}", - } - - event.Tags["organization"] = "12345" - event.Timestamp = time.Unix(5, 0) - - t := &Transaction{ - sentryEvent: (*sentryEvent)(event), - StartTimestamp: time.Unix(0, 0), - Spans: []*Span{testSpan}, - } - - return t - }(), - }, } for _, test := range testCases { diff --git a/testdata/transaction.golden b/testdata/transaction.golden deleted file mode 100644 index 1dcce0b37..000000000 --- a/testdata/transaction.golden +++ /dev/null @@ -1,34 +0,0 @@ -{ - "contexts": { - "trace": { - "trace_id": "d6c4f03650bd47699ec65c84352b6208", - "span_id": "442bd97bbe564317", - "op": "http.server", - "description": "/api/users/{user_id}" - } - }, - "sdk": {}, - "tags": { - "organization": "12345" - }, - "timestamp": "1969-12-31T19:00:05-05:00", - "user": {}, - "start_timestamp": "1969-12-31T19:00:00-05:00", - "spans": [ - { - "trace_id": "d6c4f03650bd47699ec65c84352b6208", - "span_id": "1cc4b26ab9094ef0", - "parent_span_id": "442bd97bbe564317", - "description": "SELECT * FROM user WHERE \"user\".\"id\" = {id}", - "op": "db.sql", - "tags": { - "function_name": "get_users", - "status_message": "MYSQL OK" - }, - "start_timestamp": "1969-12-31T19:00:00-05:00", - "timestamp": "1969-12-31T19:00:05-05:00", - "status": "ok" - } - ], - "type": "transaction" -} \ No newline at end of file diff --git a/transport.go b/transport.go index 9d135ac0b..756caa872 100644 --- a/transport.go +++ b/transport.go @@ -4,8 +4,6 @@ import ( "bytes" "crypto/tls" "encoding/json" - "errors" - "fmt" "net/http" "net/url" "strconv" @@ -22,7 +20,6 @@ type Transport interface { Flush(timeout time.Duration) bool Configure(options ClientOptions) SendEvent(event *Event) - SendTransaction(transaction *Transaction) } func getProxyConfig(options ClientOptions) func(*http.Request) (*url.URL, error) { @@ -95,15 +92,15 @@ func getRequestBodyFromEvent(event *Event) []byte { return nil } -func getRequestBodyFromTransaction(t *Transaction) (envelope *bytes.Buffer, err error) { - var b bytes.Buffer - enc := json.NewEncoder(&b) +// func getRequestBodyFromTransaction(t *Transaction) (envelope *bytes.Buffer, err error) { +// var b bytes.Buffer +// enc := json.NewEncoder(&b) - fmt.Fprintf(&b, `{"sent_at":"%s"}`, time.Now().UTC().Format(time.RFC3339Nano)) - fmt.Fprint(&b, "\n", `{"type":"transaction"}`, "\n") - err = enc.Encode(t) - return &b, err -} +// fmt.Fprintf(&b, `{"sent_at":"%s"}`, time.Now().UTC().Format(time.RFC3339Nano)) +// fmt.Fprint(&b, "\n", `{"type":"transaction"}`, "\n") +// err = enc.Encode(t) +// return &b, err +// } // ================================ // HTTPTransport @@ -188,53 +185,6 @@ func (t *HTTPTransport) Configure(options ClientOptions) { }) } -// SendTransaction send a transaction to a remote server -func (t *HTTPTransport) SendTransaction(transaction *Transaction) error { - if t.dsn == nil { - return errors.New("Invalid DSN. Not sending Transaction") - } - - t.mu.RLock() - disabled := time.Now().Before(t.disabledUntil) - t.mu.RUnlock() - if disabled { - return errors.New("Transport is disabled, cannot send transaction") - } - - body, err := getRequestBodyFromTransaction(transaction) - if err != nil { - return err - } - - request, _ := http.NewRequest( - http.MethodPost, - t.dsn.EnvelopeAPIURL().String(), - body, - ) - - for headerKey, headerValue := range t.dsn.RequestHeaders() { - request.Header.Set(headerKey, headerValue) - } - - b := <-t.buffer - - select { - case b.items <- request: - Logger.Printf( - "Sending %s transaction [%s] to %s project: %d\n", - transaction.Level, - transaction.EventID, - t.dsn.host, - t.dsn.projectID, - ) - default: - Logger.Println("Event dropped due to transport buffer being full.") - } - - t.buffer <- b - return nil -} - // SendEvent assembles a new packet out of `Event` and sends it to remote server. func (t *HTTPTransport) SendEvent(event *Event) { if t.dsn == nil { @@ -254,6 +204,8 @@ func (t *HTTPTransport) SendEvent(event *Event) { request, _ := http.NewRequest( http.MethodPost, + // Need to skip before send + // TODO: Change based on event.type t.dsn.StoreAPIURL().String(), bytes.NewBuffer(body), )