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

NrZap attributes fix #919

Merged
merged 2 commits into from
Jul 2, 2024
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
3 changes: 0 additions & 3 deletions v3/integrations/logcontext-v2/nrzap/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@ require (
github.com/newrelic/go-agent/v3 v3.32.0
go.uber.org/zap v1.24.0
)


replace github.com/newrelic/go-agent/v3 => ../../..
25 changes: 14 additions & 11 deletions v3/integrations/logcontext-v2/nrzap/nrzap.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ func init() { internal.TrackUsage("integration", "logcontext-v2", "zap") }

// NewRelicZapCore implements zap.Core
type NewRelicZapCore struct {
core zapcore.Core
nr newrelicApplicationState
fields []zap.Field
core zapcore.Core
nr newrelicApplicationState
}

// newrelicApplicationState is a private struct that stores newrelic application data
Expand Down Expand Up @@ -147,7 +148,7 @@ func WrapBackgroundCore(core zapcore.Core, app *newrelic.Application) (*NewRelic
// Errors will be returned if the zapcore object is nil, or if the application is nil. It is up to the user to decide
// how to handle the case where the newrelic.Transaction is nil.
// In the case that the newrelic.Application is nil, a valid NewRelicZapCore object will still be returned.
func WrapTransactionCore(core zapcore.Core, txn *newrelic.Transaction) (*NewRelicZapCore, error) {
func WrapTransactionCore(core zapcore.Core, txn *newrelic.Transaction) (zapcore.Core, error) {
if core == nil {
return nil, ErrNilZapcore
}
Expand All @@ -167,9 +168,10 @@ func WrapTransactionCore(core zapcore.Core, txn *newrelic.Transaction) (*NewReli
// With makes a copy of a NewRelicZapCore with new zap.Fields. It calls zapcore.With() on the zap core object
// then makes a deepcopy of the NewRelicApplicationState object so the original
// object can be deallocated when it's no longer in scope.
func (c NewRelicZapCore) With(fields []zap.Field) zapcore.Core {
return NewRelicZapCore{
core: c.core.With(fields),
func (c *NewRelicZapCore) With(fields []zap.Field) zapcore.Core {
return &NewRelicZapCore{
core: c.core.With(fields),
fields: append(fields, c.fields...),
nr: newrelicApplicationState{
c.nr.app,
c.nr.txn,
Expand All @@ -178,24 +180,25 @@ func (c NewRelicZapCore) With(fields []zap.Field) zapcore.Core {
}

// Check simply calls zapcore.Check on the Core object.
func (c NewRelicZapCore) Check(entry zapcore.Entry, checkedEntry *zapcore.CheckedEntry) *zapcore.CheckedEntry {
func (c *NewRelicZapCore) Check(entry zapcore.Entry, checkedEntry *zapcore.CheckedEntry) *zapcore.CheckedEntry {
ce := c.core.Check(entry, checkedEntry)
ce.AddCore(entry, c)
return ce
}

// Write wraps zapcore.Write and captures the log entry and sends that data to New Relic.
func (c NewRelicZapCore) Write(entry zapcore.Entry, fields []zap.Field) error {
c.nr.recordLog(entry, fields)
func (c *NewRelicZapCore) Write(entry zapcore.Entry, fields []zap.Field) error {
allFields := append(fields, c.fields...)
c.nr.recordLog(entry, allFields)
return nil
}

// Sync simply calls zapcore.Sync on the Core object.
func (c NewRelicZapCore) Sync() error {
func (c *NewRelicZapCore) Sync() error {
return c.core.Sync()
}

// Enabled simply calls zapcore.Enabled on the zapcore.Level passed to it.
func (c NewRelicZapCore) Enabled(level zapcore.Level) bool {
func (c *NewRelicZapCore) Enabled(level zapcore.Level) bool {
return c.core.Enabled(level)
}
5 changes: 5 additions & 0 deletions v3/integrations/logcontext-v2/nrzap/nrzap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ func TestTransactionLoggerWithFields(t *testing.T) {
t.Error(err)
}

wrappedCore = wrappedCore.With([]zapcore.Field{
zap.String("foo", "bar"),
})

logger := zap.New(wrappedCore)

msg := "this is a test info message"
Expand All @@ -186,6 +190,7 @@ func TestTransactionLoggerWithFields(t *testing.T) {
"duration": 1 * time.Second,
"int": 123,
"bool": true,
"foo": "bar",
},
Severity: zap.InfoLevel.String(),
Message: msg,
Expand Down
25 changes: 3 additions & 22 deletions v3/newrelic/expect_implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"time"

"github.com/newrelic/go-agent/v3/internal"
Expand Down Expand Up @@ -250,29 +251,9 @@ func expectLogEvent(v internal.Validator, actual logEvent, want internal.WantLog
return
}

if actual.attributes != nil && want.Attributes != nil {
for k, val := range want.Attributes {
actualVal, actualOk := actual.attributes[k]
if !actualOk {
v.Error(fmt.Sprintf("expected log attribute for key %v is missing", k))
return
}

// Check if both values are maps, and if so, compare them recursively
if expectedMap, ok := val.(map[string]interface{}); ok {
if actualMap, ok := actualVal.(map[string]interface{}); ok {
if !expectLogEventAttributesMaps(expectedMap, actualMap) {
v.Error(fmt.Sprintf("unexpected log attribute for key %v: got %v, want %v", k, actualMap, expectedMap))
return
}
} else {
v.Error(fmt.Sprintf("actual value for key %v is not a map", k))
return
}
}
}
if !reflect.DeepEqual(actual.attributes, want.Attributes) {
v.Error(fmt.Sprintf("wanted the following attributes: %+v\nactual attributes are: %+v", want.Attributes, actual.attributes))
}

}

// Helper function that compares two maps for equality. This is used to compare the attribute fields of log events expected vs received
Expand Down
Loading