Skip to content

Commit

Permalink
feat: send go version and configured options in notifier.diagnostic
Browse files Browse the repository at this point in the history
  • Loading branch information
waltjones committed Sep 25, 2019
1 parent 59c4066 commit 5f3a9b2
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 4 deletions.
51 changes: 48 additions & 3 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Client struct {
// implementation of the Transport interface is used.
Transport Transport
configuration configuration
diagnostic diagnostic
}

// New returns the default implementation of a Client.
Expand All @@ -38,19 +39,23 @@ func New(token, environment, codeVersion, serverHost, serverRoot string) *Client
func NewAsync(token, environment, codeVersion, serverHost, serverRoot string) *Client {
configuration := createConfiguration(token, environment, codeVersion, serverHost, serverRoot)
transport := NewTransport(token, configuration.endpoint)
diagnostic := createDiagnostic()
return &Client{
Transport: transport,
configuration: configuration,
diagnostic: diagnostic,
}
}

// NewSync builds a Client with the synchronous implementation of the transport interface.
func NewSync(token, environment, codeVersion, serverHost, serverRoot string) *Client {
configuration := createConfiguration(token, environment, codeVersion, serverHost, serverRoot)
transport := NewSyncTransport(token, configuration.endpoint)
diagnostic := createDiagnostic()
return &Client{
Transport: transport,
configuration: configuration,
diagnostic: diagnostic,
}
}

Expand All @@ -73,33 +78,39 @@ func (c *Client) SetToken(token string) {

// SetEnvironment sets the environment under which all errors and messages will be submitted.
func (c *Client) SetEnvironment(environment string) {
c.diagnostic.configuredOptions["environment"] = environment
c.configuration.environment = environment
}

// SetEndpoint sets the endpoint to post items to. This also configures the underlying Transport.
func (c *Client) SetEndpoint(endpoint string) {
c.diagnostic.configuredOptions["endpoint"] = endpoint
c.configuration.endpoint = endpoint
c.Transport.SetEndpoint(endpoint)
}

// SetPlatform sets the platform to be reported for all items.
func (c *Client) SetPlatform(platform string) {
c.diagnostic.configuredOptions["platform"] = platform
c.configuration.platform = platform
}

// SetCodeVersion sets the string describing the running code version on the server.
func (c *Client) SetCodeVersion(codeVersion string) {
c.diagnostic.configuredOptions["codeVersion"] = codeVersion
c.configuration.codeVersion = codeVersion
}

// SetServerHost sets the hostname sent with each item. This value will be indexed.
func (c *Client) SetServerHost(serverHost string) {
c.diagnostic.configuredOptions["serverHost"] = serverHost
c.configuration.serverHost = serverHost
}

// SetServerRoot sets the path to the application code root, not including the final slash.
// This is used to collapse non-project code when displaying tracebacks.
func (c *Client) SetServerRoot(serverRoot string) {
c.diagnostic.configuredOptions["serverRoot"] = serverRoot
c.configuration.serverRoot = serverRoot
}

Expand All @@ -112,22 +123,33 @@ func (c *Client) SetCustom(custom map[string]interface{}) {
// any subsequent errors or messages. Only id is required to be
// non-empty.
func (c *Client) SetPerson(id, username, email string) {
c.configuration.person = Person{
person := Person{
Id: id,
Username: username,
Email: email,
}

c.diagnostic.configuredOptions["person"] = map[string]string{
"Id": id,
"Username": username,
"Email": email,
}
c.configuration.person = person
}

// ClearPerson clears any previously set person information. See `SetPerson` for more
// information.
func (c *Client) ClearPerson() {
c.configuration.person = Person{}
person := Person{}

c.diagnostic.configuredOptions["person"] = map[string]string{}
c.configuration.person = person
}

// SetFingerprint sets whether or not to use a custom client-side fingerprint. The default value is
// false.
func (c *Client) SetFingerprint(fingerprint bool) {
c.diagnostic.configuredOptions["fingerprint"] = fingerprint
c.configuration.fingerprint = fingerprint
}

Expand All @@ -139,12 +161,14 @@ func (c *Client) SetLogger(logger ClientLogger) {
// SetScrubHeaders sets the regular expression used to match headers for scrubbing.
// The default value is regexp.MustCompile("Authorization")
func (c *Client) SetScrubHeaders(headers *regexp.Regexp) {
c.diagnostic.configuredOptions["scrubHeaders"] = headers
c.configuration.scrubHeaders = headers
}

// SetScrubFields sets the regular expression to match keys in the item payload for scrubbing.
// The default vlaue is regexp.MustCompile("password|secret|token"),
func (c *Client) SetScrubFields(fields *regexp.Regexp) {
c.diagnostic.configuredOptions["scrubFields"] = fields
c.configuration.scrubFields = fields
}

Expand All @@ -160,6 +184,7 @@ func (c *Client) SetScrubFields(fields *regexp.Regexp) {
// make before it is finally sent. Be careful with the modifications you make as they could lead to
// the payload being malformed from the perspective of the API.
func (c *Client) SetTransform(transform func(map[string]interface{})) {
c.diagnostic.configuredOptions["transform"] = functionToString(transform)
c.configuration.transform = transform
}

Expand All @@ -171,6 +196,7 @@ func (c *Client) SetTransform(transform func(map[string]interface{})) {
// In order to preserve the default unwrapping behavior, callers of SetUnwrapper may wish to include
// a call to DefaultUnwrapper in their custom unwrapper function. See the example on the SetUnwrapper function.
func (c *Client) SetUnwrapper(unwrapper UnwrapperFunc) {
c.diagnostic.configuredOptions["unwrapper"] = functionToString(unwrapper)
c.configuration.unwrapper = unwrapper
}

Expand All @@ -183,6 +209,7 @@ func (c *Client) SetUnwrapper(unwrapper UnwrapperFunc) {
// to include a call to DefaultStackTracer in their custom tracing function. See the example
// on the SetStackTracer function.
func (c *Client) SetStackTracer(stackTracer StackTracerFunc) {
c.diagnostic.configuredOptions["stackTracer"] = functionToString(stackTracer)
c.configuration.stackTracer = stackTracer
}

Expand All @@ -193,6 +220,7 @@ func (c *Client) SetStackTracer(stackTracer StackTracerFunc) {
// this function is called with the result of calling Error(), otherwise
// the string representation of the value is passed to this function.
func (c *Client) SetCheckIgnore(checkIgnore func(string) bool) {
c.diagnostic.configuredOptions["checkIgnore"] = functionToString(checkIgnore)
c.configuration.checkIgnore = checkIgnore
}

Expand All @@ -201,6 +229,7 @@ func (c *Client) SetCheckIgnore(checkIgnore func(string) bool) {
// CaptureIpAnonymize means apply a pseudo-anonymization.
// CaptureIpNone means do not capture anything.
func (c *Client) SetCaptureIp(captureIp captureIp) {
c.diagnostic.configuredOptions["captureIp"] = captureIp
c.configuration.captureIp = captureIp
}

Expand Down Expand Up @@ -560,7 +589,7 @@ func (c *Client) Close() error {
}

func (c *Client) buildBody(ctx context.Context, level, title string, extras map[string]interface{}) map[string]interface{} {
return buildBody(ctx, c.configuration, level, title, extras)
return buildBody(ctx, c.configuration, c.diagnostic, level, title, extras)
}

func (c *Client) requestDetails(r *http.Request) map[string]interface{} {
Expand Down Expand Up @@ -652,6 +681,18 @@ func createConfiguration(token, environment, codeVersion, serverHost, serverRoot
}
}

type diagnostic struct {
languageVersion string
configuredOptions map[string]interface{}
}

func createDiagnostic() diagnostic {
return diagnostic{
languageVersion: runtime.Version(),
configuredOptions: map[string]interface{}{},
}
}

// clientPost returns an error which indicates the type of error that occured while attempting to
// send the body input to the endpoint given, or nil if no error occurred. If error is not nil, the
// boolean return parameter indicates whether the error is temporary or not. If this boolean return
Expand Down Expand Up @@ -716,3 +757,7 @@ func isTemporary(err error) bool {
}
return false
}

func functionToString(function interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name()
}
46 changes: 46 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"context"
"reflect"
"testing"
"strings"
rollbarErrors "github.com/rollbar/rollbar-go/errors"
pkgerr "github.com/pkg/errors"
)

type TestTransport struct {
Expand Down Expand Up @@ -452,6 +455,35 @@ func TestTransform(t *testing.T) {
if data["some_custom_field"] != "hello_world" {
t.Error("data should have field set by transform")
}
configuredOptions := configuredOptionsFromData(data)
if !strings.Contains(configuredOptions["transform"].(string), "TestTransform.func1") {
t.Error("data should have transform in diagnostic object")
}
} else {
t.Fail()
}
}

func TestStackTracer(t *testing.T) {
client := testClient()
client.SetStackTracer(rollbarErrors.StackTracer)

client.ErrorWithLevel(rollbar.ERR, pkgerr.New("Bork"))

if transport, ok := client.Transport.(*TestTransport); ok {
body := transport.Body
if body["data"] == nil {
t.Error("body should have data")
}
data := body["data"].(map[string]interface{})
framesLen := framesLenFromData(data)
if framesLen == 0 {
t.Error("data should have frames set by stackTracer")
}
configuredOptions := configuredOptionsFromData(data)
if !strings.Contains(configuredOptions["stackTracer"].(string), "errors.StackTracer") {
t.Error("data should have stackTracer in diagnostic object")
}
} else {
t.Fail()
}
Expand Down Expand Up @@ -484,3 +516,17 @@ func TestEnabled(t *testing.T) {
t.Fail()
}
}

func configuredOptionsFromData(data map[string]interface{}) map[string]interface{} {
notifier := data["notifier"].(map[string]interface{})
diagnostic := notifier["diagnostic"].(map[string]interface{})
configuredOptions := diagnostic["configuredOptions"].(map[string]interface{})
return configuredOptions
}

func framesLenFromData(data map[string]interface{}) int {
body := data["body"].(map[string]interface{})
trace_chain := body["trace_chain"].([]map[string]interface{})
frames := reflect.ValueOf(trace_chain[0]["frames"])
return frames.Len()
}
8 changes: 7 additions & 1 deletion transforms.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (

// Build the main JSON structure that will be sent to Rollbar with the
// appropriate metadata.
func buildBody(ctx context.Context, configuration configuration, level, title string, extras map[string]interface{}) map[string]interface{} {
func buildBody(ctx context.Context, configuration configuration, diagnostic diagnostic,
level, title string, extras map[string]interface{}) map[string]interface{} {

timestamp := time.Now().Unix()

data := map[string]interface{}{
Expand All @@ -31,6 +33,10 @@ func buildBody(ctx context.Context, configuration configuration, level, title st
"notifier": map[string]interface{}{
"name": NAME,
"version": VERSION,
"diagnostic": map[string]interface{}{
"languageVersion": diagnostic.languageVersion,
"configuredOptions": diagnostic.configuredOptions,
},
},
}

Expand Down

0 comments on commit 5f3a9b2

Please sign in to comment.