-
Notifications
You must be signed in to change notification settings - Fork 242
feat: add new envelope transport #1094
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
Open
giortzisg
wants to merge
13
commits into
master
Choose a base branch
from
feat/transport-envelope
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
0c154b8
add new transport
giortzisg fc93d2c
fix lint
giortzisg 3c7498e
fix tests
giortzisg 0a406ba
modify envelope serialization and tests
giortzisg 6f9c638
change transport opts
giortzisg bf26d59
remove transport.Configure
giortzisg c7205ca
add proper await on queue flush
giortzisg 8c8a4bd
add test for marshall fallback
giortzisg 4228142
fix tests
giortzisg 803349d
add sendEvent
giortzisg 51f0373
fix dsn exporting
giortzisg 58a7b02
enhance transport test suite
giortzisg 1ed184b
change backpressure test
giortzisg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,233 +1,37 @@ | ||
package sentry | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/url" | ||
"strconv" | ||
"strings" | ||
"time" | ||
"github.com/getsentry/sentry-go/internal/protocol" | ||
) | ||
|
||
type scheme string | ||
// Re-export protocol types to maintain public API compatibility | ||
|
||
const ( | ||
schemeHTTP scheme = "http" | ||
schemeHTTPS scheme = "https" | ||
) | ||
|
||
func (scheme scheme) defaultPort() int { | ||
switch scheme { | ||
case schemeHTTPS: | ||
return 443 | ||
case schemeHTTP: | ||
return 80 | ||
default: | ||
return 80 | ||
} | ||
// Dsn is used as the remote address source to client transport. | ||
type Dsn struct { | ||
protocol.Dsn | ||
} | ||
|
||
// DsnParseError represents an error that occurs if a Sentry | ||
// DSN cannot be parsed. | ||
type DsnParseError struct { | ||
Message string | ||
} | ||
|
||
func (e DsnParseError) Error() string { | ||
return "[Sentry] DsnParseError: " + e.Message | ||
} | ||
|
||
// Dsn is used as the remote address source to client transport. | ||
type Dsn struct { | ||
scheme scheme | ||
publicKey string | ||
secretKey string | ||
host string | ||
port int | ||
path string | ||
projectID string | ||
} | ||
type DsnParseError = protocol.DsnParseError | ||
|
||
// NewDsn creates a Dsn by parsing rawURL. Most users will never call this | ||
// function directly. It is provided for use in custom Transport | ||
// implementations. | ||
func NewDsn(rawURL string) (*Dsn, error) { | ||
// Parse | ||
parsedURL, err := url.Parse(rawURL) | ||
protocolDsn, err := protocol.NewDsn(rawURL) | ||
if err != nil { | ||
return nil, &DsnParseError{fmt.Sprintf("invalid url: %v", err)} | ||
} | ||
|
||
// Scheme | ||
var scheme scheme | ||
switch parsedURL.Scheme { | ||
case "http": | ||
scheme = schemeHTTP | ||
case "https": | ||
scheme = schemeHTTPS | ||
default: | ||
return nil, &DsnParseError{"invalid scheme"} | ||
} | ||
|
||
// PublicKey | ||
publicKey := parsedURL.User.Username() | ||
if publicKey == "" { | ||
return nil, &DsnParseError{"empty username"} | ||
} | ||
|
||
// SecretKey | ||
var secretKey string | ||
if parsedSecretKey, ok := parsedURL.User.Password(); ok { | ||
secretKey = parsedSecretKey | ||
} | ||
|
||
// Host | ||
host := parsedURL.Hostname() | ||
if host == "" { | ||
return nil, &DsnParseError{"empty host"} | ||
} | ||
|
||
// Port | ||
var port int | ||
if p := parsedURL.Port(); p != "" { | ||
port, err = strconv.Atoi(p) | ||
if err != nil { | ||
return nil, &DsnParseError{"invalid port"} | ||
} | ||
} else { | ||
port = scheme.defaultPort() | ||
} | ||
|
||
// ProjectID | ||
if parsedURL.Path == "" || parsedURL.Path == "/" { | ||
return nil, &DsnParseError{"empty project id"} | ||
} | ||
pathSegments := strings.Split(parsedURL.Path[1:], "/") | ||
projectID := pathSegments[len(pathSegments)-1] | ||
|
||
if projectID == "" { | ||
return nil, &DsnParseError{"empty project id"} | ||
} | ||
|
||
// Path | ||
var path string | ||
if len(pathSegments) > 1 { | ||
path = "/" + strings.Join(pathSegments[0:len(pathSegments)-1], "/") | ||
} | ||
|
||
return &Dsn{ | ||
scheme: scheme, | ||
publicKey: publicKey, | ||
secretKey: secretKey, | ||
host: host, | ||
port: port, | ||
path: path, | ||
projectID: projectID, | ||
}, nil | ||
} | ||
|
||
// String formats Dsn struct into a valid string url. | ||
func (dsn Dsn) String() string { | ||
var url string | ||
url += fmt.Sprintf("%s://%s", dsn.scheme, dsn.publicKey) | ||
if dsn.secretKey != "" { | ||
url += fmt.Sprintf(":%s", dsn.secretKey) | ||
} | ||
url += fmt.Sprintf("@%s", dsn.host) | ||
if dsn.port != dsn.scheme.defaultPort() { | ||
url += fmt.Sprintf(":%d", dsn.port) | ||
return nil, err | ||
} | ||
if dsn.path != "" { | ||
url += dsn.path | ||
} | ||
url += fmt.Sprintf("/%s", dsn.projectID) | ||
return url | ||
} | ||
|
||
// Get the scheme of the DSN. | ||
func (dsn Dsn) GetScheme() string { | ||
return string(dsn.scheme) | ||
} | ||
|
||
// Get the public key of the DSN. | ||
func (dsn Dsn) GetPublicKey() string { | ||
return dsn.publicKey | ||
} | ||
|
||
// Get the secret key of the DSN. | ||
func (dsn Dsn) GetSecretKey() string { | ||
return dsn.secretKey | ||
} | ||
|
||
// Get the host of the DSN. | ||
func (dsn Dsn) GetHost() string { | ||
return dsn.host | ||
} | ||
|
||
// Get the port of the DSN. | ||
func (dsn Dsn) GetPort() int { | ||
return dsn.port | ||
} | ||
|
||
// Get the path of the DSN. | ||
func (dsn Dsn) GetPath() string { | ||
return dsn.path | ||
return &Dsn{Dsn: *protocolDsn}, nil | ||
} | ||
|
||
// Get the project ID of the DSN. | ||
func (dsn Dsn) GetProjectID() string { | ||
return dsn.projectID | ||
} | ||
|
||
// GetAPIURL returns the URL of the envelope endpoint of the project | ||
// associated with the DSN. | ||
func (dsn Dsn) GetAPIURL() *url.URL { | ||
var rawURL string | ||
rawURL += fmt.Sprintf("%s://%s", dsn.scheme, dsn.host) | ||
if dsn.port != dsn.scheme.defaultPort() { | ||
rawURL += fmt.Sprintf(":%d", dsn.port) | ||
} | ||
if dsn.path != "" { | ||
rawURL += dsn.path | ||
} | ||
rawURL += fmt.Sprintf("/api/%s/%s/", dsn.projectID, "envelope") | ||
parsedURL, _ := url.Parse(rawURL) | ||
return parsedURL | ||
} | ||
|
||
// RequestHeaders returns all the necessary headers that have to be used in the transport when seinding events | ||
// RequestHeaders returns all the necessary headers that have to be used in the transport when sending events | ||
// to the /store endpoint. | ||
// | ||
// Deprecated: This method shall only be used if you want to implement your own transport that sends events to | ||
// the /store endpoint. If you're using the transport provided by the SDK, all necessary headers to authenticate | ||
// against the /envelope endpoint are added automatically. | ||
func (dsn Dsn) RequestHeaders() map[string]string { | ||
auth := fmt.Sprintf("Sentry sentry_version=%s, sentry_timestamp=%d, "+ | ||
"sentry_client=sentry.go/%s, sentry_key=%s", apiVersion, time.Now().Unix(), SDKVersion, dsn.publicKey) | ||
|
||
if dsn.secretKey != "" { | ||
auth = fmt.Sprintf("%s, sentry_secret=%s", auth, dsn.secretKey) | ||
} | ||
|
||
return map[string]string{ | ||
"Content-Type": "application/json", | ||
"X-Sentry-Auth": auth, | ||
} | ||
} | ||
|
||
// MarshalJSON converts the Dsn struct to JSON. | ||
func (dsn Dsn) MarshalJSON() ([]byte, error) { | ||
return json.Marshal(dsn.String()) | ||
} | ||
|
||
// UnmarshalJSON converts JSON data to the Dsn struct. | ||
func (dsn *Dsn) UnmarshalJSON(data []byte) error { | ||
var str string | ||
_ = json.Unmarshal(data, &str) | ||
newDsn, err := NewDsn(str) | ||
if err != nil { | ||
return err | ||
} | ||
*dsn = *newDsn | ||
return nil | ||
func (dsn *Dsn) RequestHeaders() map[string]string { | ||
return dsn.Dsn.RequestHeaders(SDKVersion) | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not familiar with go, why embed instead of alias?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am extending the
RequestHeaders
method to pass the sdkVersion on the protocol level.