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

feat: add service version in service context for error reporting #37

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
vendor/
.idea
19 changes: 15 additions & 4 deletions core.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ type driverConfig struct {

// ServiceName is added as `ServiceContext()` to all logs when set
ServiceName string

// ServiceVersion is added as `ServiceVersionContext()` to all logs when set
ServiceVersion string
}

// Core is a zapdriver specific core wrapped around the default zap core. It
Expand Down Expand Up @@ -58,6 +61,14 @@ func ServiceName(name string) func(*core) {
}
}

// zapdriver core option to add `ServiceVersion()` to all logs with `version` as
// service version
func ServiceVersion(version string) func(*core) {
return func(c *core) {
c.config.ServiceVersion = version
}
}

// WrapCore returns a `zap.Option` that wraps the default core with the
// zapdriver one.
func WrapCore(options ...func(*core)) zap.Option {
Expand Down Expand Up @@ -124,14 +135,14 @@ func (c *core) Write(ent zapcore.Entry, fields []zapcore.Field) error {
fields = append(fields, labelsField(c.allLabels()))
fields = c.withSourceLocation(ent, fields)
if c.config.ServiceName != "" {
fields = c.withServiceContext(c.config.ServiceName, fields)
fields = c.withServiceContext(c.config.ServiceName, c.config.ServiceVersion, fields)
}
if c.config.ReportAllErrors && zapcore.ErrorLevel.Enabled(ent.Level) {
fields = c.withErrorReport(ent, fields)
if c.config.ServiceName == "" {
// A service name was not set but error report needs it
// So attempt to add a generic service name
fields = c.withServiceContext("unknown", fields)
fields = c.withServiceContext("unknown", c.config.ServiceVersion, fields)
}
}

Expand Down Expand Up @@ -216,15 +227,15 @@ func (c *core) withSourceLocation(ent zapcore.Entry, fields []zapcore.Field) []z
return append(fields, SourceLocation(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true))
}

func (c *core) withServiceContext(name string, fields []zapcore.Field) []zapcore.Field {
func (c *core) withServiceContext(name, version string, fields []zapcore.Field) []zapcore.Field {
// If the service context was manually set, don't overwrite it
for i := range fields {
if fields[i].Key == serviceContextKey {
return fields
}
}

return append(fields, ServiceContext(name))
return append(fields, ServiceContext(name, version))
}

func (c *core) withErrorReport(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field {
Expand Down
12 changes: 8 additions & 4 deletions core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ func TestWithServiceContext(t *testing.T) {

want := []zap.Field{
zap.String("hello", "world"),
zap.Object(serviceContextKey, newServiceContext("test service")),
zap.Object(serviceContextKey, newServiceContext("test service", "test version")),
}

assert.Equal(t, want, (&core{}).withServiceContext("test service", fields))
assert.Equal(t, want, (&core{}).withServiceContext("test service", "test version", fields))
}

func TestWithServiceContext_DoesNotOverwrite(t *testing.T) {
Expand All @@ -154,7 +154,7 @@ func TestWithServiceContext_DoesNotOverwrite(t *testing.T) {
zap.String(serviceContextKey, "world"),
}

assert.Equal(t, want, (&core{}).withServiceContext("test service", fields))
assert.Equal(t, want, (&core{}).withServiceContext("test service", "test version", fields))
}

func TestWrite(t *testing.T) {
Expand Down Expand Up @@ -299,7 +299,8 @@ func TestWriteServiceContext(t *testing.T) {
permLabels: newLabels(),
tempLabels: newLabels(),
config: driverConfig{
ServiceName: "test service",
ServiceName: "test service",
ServiceVersion: "v0.0.1",
},
})

Expand All @@ -309,6 +310,7 @@ func TestWriteServiceContext(t *testing.T) {
// Assert that a service context was attached even though service name was not set
serviceContext := logs.All()[0].ContextMap()[serviceContextKey].(map[string]interface{})
assert.Equal(t, "test service", serviceContext["service"])
assert.Equal(t, "v0.0.1", serviceContext["version"])
}

func TestWriteReportAllErrors_WithServiceContext(t *testing.T) {
Expand All @@ -320,6 +322,7 @@ func TestWriteReportAllErrors_WithServiceContext(t *testing.T) {
config: driverConfig{
ReportAllErrors: true,
ServiceName: "test service",
ServiceVersion: "v0.0.1",
},
})

Expand All @@ -335,6 +338,7 @@ func TestWriteReportAllErrors_WithServiceContext(t *testing.T) {
// Assert that a service context was attached even though service name was not set
serviceContext := logs.All()[0].ContextMap()[serviceContextKey].(map[string]interface{})
assert.Equal(t, "test service", serviceContext["service"])
assert.Equal(t, "v0.0.1", serviceContext["version"])
}

func TestWriteReportAllErrors_InfoLog(t *testing.T) {
Expand Down
14 changes: 8 additions & 6 deletions service.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,27 @@ const serviceContextKey = "serviceContext"
//
// see: https://cloud.google.com/error-reporting/reference/rest/v1beta1/ServiceContext
// see: https://cloud.google.com/error-reporting/docs/formatting-error-messages
func ServiceContext(name string) zap.Field {
return zap.Object(serviceContextKey, newServiceContext(name))
func ServiceContext(name, version string) zap.Field {
return zap.Object(serviceContextKey, newServiceContext(name, version))
}

// serviceContext describes a running service that sends errors.
// Currently it only describes a service name.
type serviceContext struct {
Name string `json:"service"`
Name string `json:"service"`
Version string `json:"version"`
}

// MarshalLogObject implements zapcore.ObjectMarshaller interface.
func (service_context serviceContext) MarshalLogObject(enc zapcore.ObjectEncoder) error {
enc.AddString("service", service_context.Name)

enc.AddString("version", service_context.Version)
return nil
}

func newServiceContext(name string) *serviceContext {
func newServiceContext(name, version string) *serviceContext {
return &serviceContext{
Name: name,
Name: name,
Version: version,
}
}
6 changes: 4 additions & 2 deletions service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import (
func TestServiceContext(t *testing.T) {
t.Parallel()

got := ServiceContext("test service name").Interface.(*serviceContext)
got := ServiceContext("test service name", "v1").Interface.(*serviceContext)

assert.Equal(t, "test service name", got.Name)
assert.Equal(t, "v1", got.Version)
}

func TestNewServiceContext(t *testing.T) {
t.Parallel()

got := newServiceContext("test service name")
got := newServiceContext("test service name", "v1")

assert.Equal(t, "test service name", got.Name)
assert.Equal(t, "v1", got.Version)
}