Skip to content

Commit

Permalink
module/apmmongo: mongo.CommandError ErrorDetailer
Browse files Browse the repository at this point in the history
Register an ErrorDetailer for mongo.CommandError,
extract the error code and labels.
  • Loading branch information
axw committed Feb 26, 2019
1 parent c1cd527 commit 447cc27
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 2 deletions.
6 changes: 5 additions & 1 deletion error.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,8 @@ var (
)

// ErrorDetails holds details of an error, which can be altered or
// extended by registering an ErrorDetailer with RegisterErrorDetailer.
// extended by registering an ErrorDetailer with RegisterErrorDetailer
// or RegisterTypeErrorDetailer.
type ErrorDetails struct {
attrs map[string]interface{}

Expand Down Expand Up @@ -615,6 +616,9 @@ func (d *ErrorDetails) SetAttr(k string, v interface{}) {
}

// ErrorDetailer defines an interface for altering or extending the ErrorDetails for an error.
//
// ErrorDetailers can be registered using the package-level functions RegisterErrorDetailer and
// RegisterTypeErrorDetailer.
type ErrorDetailer interface {
// ErrorDetails is called to update or alter details for err.
ErrorDetails(err error, details *ErrorDetails)
Expand Down
15 changes: 15 additions & 0 deletions module/apmmongo/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ package apmmongo

import (
"context"
"reflect"
"sync"
"time"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/bson/bsonrw"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo"

"go.elastic.co/apm"
)
Expand All @@ -39,6 +41,19 @@ var (
}
)

func init() {
apm.RegisterTypeErrorDetailer(
reflect.TypeOf(mongo.CommandError{}),
apm.ErrorDetailerFunc(func(err error, details *apm.ErrorDetails) {
commandErr := err.(mongo.CommandError)
details.Code.String = commandErr.Name
if len(commandErr.Labels) > 0 {
details.SetAttr("labels", commandErr.Labels)
}
}),
)
}

// CommandMonitor returns a new event.CommandMonitor which will report a span
// for each command executed within a context containing a sampled transaction.
func CommandMonitor(opts ...Option) *event.CommandMonitor {
Expand Down
2 changes: 1 addition & 1 deletion module/apmmongo/monitor_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,5 @@ func (suite *IntegrationSuite) TestCommandMonitor() {
suite.Require().Len(errs, 1)
suite.Equal(tx.ID, errs[0].ParentID)
suite.Equal("(UserNotFound) User 'bob@test_db' not found", errs[0].Exception.Message)
suite.Equal(model.ExceptionCode{}, errs[0].Exception.Code) // BUG(axw) https://github.com/elastic/apm-agent-go/issues/447
suite.Equal(model.ExceptionCode{String: "UserNotFound"}, errs[0].Exception.Code)
}
26 changes: 26 additions & 0 deletions module/apmmongo/monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import (
"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo"

"go.elastic.co/apm"
"go.elastic.co/apm/apmtest"
"go.elastic.co/apm/model"
"go.elastic.co/apm/module/apmmongo"
Expand Down Expand Up @@ -179,6 +181,30 @@ func TestCommandMonitorFinishedNotStarted(t *testing.T) {
assert.Empty(t, errs)
}

func TestCommandErrorDetails(t *testing.T) {
_, _, errs := apmtest.WithTransaction(func(ctx context.Context) {
apm.CaptureError(ctx, mongo.CommandError{
Code: 11,
Name: "UserNotFound",
Message: "Robert'); DROP TABLE Students;-- not found",
Labels: []string{"black", "blue", "red"},
}).Send()
})
require.Len(t, errs, 1)

errs[0].Exception.Stacktrace = nil
assert.Equal(t, model.Exception{
Message: `(UserNotFound) Robert'); DROP TABLE Students;-- not found`,
Type: "CommandError",
Module: "go.mongodb.org/mongo-driver/mongo",
Code: model.ExceptionCode{String: "UserNotFound"},
Handled: true,
Attributes: map[string]interface{}{
"labels": []interface{}{"black", "blue", "red"},
},
}, errs[0].Exception)
}

func mustRawBSON(val interface{}) bson.Raw {
out, err := bson.Marshal(val)
if err != nil {
Expand Down

0 comments on commit 447cc27

Please sign in to comment.