From 4cf876bbc21e375a852d13191c366e68f2429095 Mon Sep 17 00:00:00 2001 From: Oleksii Khliupin Date: Tue, 5 Feb 2019 14:24:21 -0500 Subject: [PATCH 1/5] Add resource information to logger of GKE, GCE and AWS EC2 --- server/kit/kitserver.go | 2 +- server/kit/log.go | 24 +++++++++------ server/kit/{gae_log.go => sd_log.go} | 46 +++++++++++++++++++--------- 3 files changed, 47 insertions(+), 25 deletions(-) rename server/kit/{gae_log.go => sd_log.go} (80%) diff --git a/server/kit/kitserver.go b/server/kit/kitserver.go index 262255991..e983bcd5a 100644 --- a/server/kit/kitserver.go +++ b/server/kit/kitserver.go @@ -79,7 +79,7 @@ func NewServer(svc Service) *Server { ctx := context.Background() - lg, logClose, err := NewLogger(ctx) + lg, logClose, err := NewLogger(ctx, "stdout") if err != nil { stdlog.Fatalf("unable to start up logger: %s", err) } diff --git a/server/kit/log.go b/server/kit/log.go index 05aacc25a..9e7d1dfce 100644 --- a/server/kit/log.go +++ b/server/kit/log.go @@ -9,22 +9,26 @@ import ( "google.golang.org/grpc/metadata" ) -// NewLogger will inspect the environment and, if running in the Google App Engine -// environment, it will return a new Stackdriver logger annotated with the current -// server's project ID, service ID and version. If not in App Engine, a normal JSON -// logger pointing to stdout will be returned. +// NewLogger will inspect the environment and, if running in the Google App Engine, +// Google Kubernetes Engine, Google Compute Engine or AWS EC2 environment, +// it will return a new Stackdriver logger annotated with the current +// server's project ID, service ID and version and other environment specific values. +// If not in App Engine, GKE, GCE or AWS EC2 - a normal JSON logger pointing to stdout +// will be returned. // This function can be used for services that need to log information outside the // context of an inbound request. // When using the Stackdriver logger, any go-kit/log/levels will be translated to // Stackdriver severity levels. -func NewLogger(ctx context.Context) (log.Logger, func() error, error) { - // running locally or in a non-GAE environment? use JSON - if !isGAE() { +// logID identifies, for Stackdriver, the resource name of the log to which this log entry belongs. +func NewLogger(ctx context.Context, logID string) (log.Logger, func() error, error) { + projectID, serviceID, svcVersion := getGAEInfo() + lg, cl, err := newStackdriverLogger(ctx, logID, projectID, serviceID, svcVersion) + // if Stackdriver logger was not able to find information about monitored resource it returns nil. + if lg == nil { + // running locally or in a non-GAE environment? use JSON return log.NewJSONLogger(log.NewSyncWriter(os.Stdout)), func() error { return nil }, nil } - - projectID, serviceID, svcVersion := getGAEInfo() - return newAppEngineLogger(ctx, projectID, serviceID, svcVersion) + return lg, cl, err } // Logger will return a kit/log.Logger that has been injected into the context by the kit diff --git a/server/kit/gae_log.go b/server/kit/sd_log.go similarity index 80% rename from server/kit/gae_log.go rename to server/kit/sd_log.go index 05fbf9122..25eeb7a66 100644 --- a/server/kit/gae_log.go +++ b/server/kit/sd_log.go @@ -10,6 +10,7 @@ import ( "strings" "cloud.google.com/go/logging" + "contrib.go.opencensus.io/exporter/stackdriver/monitoredresource" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/pkg/errors" @@ -27,34 +28,51 @@ func isGAE() bool { return os.Getenv("GAE_DEPLOYMENT_ID") != "" } -type gaeLogger struct { +type sdLogger struct { project string monRes *monitoredres.MonitoredResource lc *logging.Client lgr *logging.Logger } -func newAppEngineLogger(ctx context.Context, projectID, service, version string) (log.Logger, func() error, error) { +func newStackdriverLogger(ctx context.Context, logID, projectID, service, version string) (log.Logger, func() error, error) { + resource := &monitoredres.MonitoredResource{ + Labels: map[string]string{ + "module_id": service, + "project_id": projectID, + "version_id": version, + }, + } + if lid := os.Getenv("SD_LOG_ID"); lid != "" { + logID = lid + } + if isGAE() { + resource.Type = "gae_app" + logID = "app_logs" + } else if mr := monitoredresource.Autodetect(); mr != nil { + typ, lbls := mr.MonitoredResource() + for f, v := range lbls { + resource.Labels[f] = v + } + resource.Type = typ + } else { + return nil, nil, nil + } + client, err := logging.NewClient(ctx, fmt.Sprintf("projects/%s", projectID)) if err != nil { return nil, nil, errors.Wrap(err, "unable to initiate stackdriver log client") } - return gaeLogger{ + + return sdLogger{ lc: client, - lgr: client.Logger("app_logs"), + lgr: client.Logger(logID), project: projectID, - monRes: &monitoredres.MonitoredResource{ - Labels: map[string]string{ - "module_id": service, - "project_id": projectID, - "version_id": version, - }, - Type: "gae_app", - }, + monRes: resource, }, client.Close, nil } -func (l gaeLogger) Log(keyvals ...interface{}) error { +func (l sdLogger) Log(keyvals ...interface{}) error { kvs, lvl, traceContext := logKeyValsToMap(keyvals...) var traceID string if traceContext != "" { @@ -87,7 +105,7 @@ func (l gaeLogger) Log(keyvals ...interface{}) error { return nil } -func (l gaeLogger) getTraceID(traceCtx string) string { +func (l sdLogger) getTraceID(traceCtx string) string { return "projects/" + l.project + "/traces/" + strings.Split(traceCtx, "/")[0] } From ac280389f63e6778a30025cf93cc6b1509513e28 Mon Sep 17 00:00:00 2001 From: Oleksii Khliupin Date: Tue, 5 Feb 2019 14:54:55 -0500 Subject: [PATCH 2/5] Remove env var. Add return error --- server/kit/sd_log.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server/kit/sd_log.go b/server/kit/sd_log.go index 25eeb7a66..646440cf3 100644 --- a/server/kit/sd_log.go +++ b/server/kit/sd_log.go @@ -43,9 +43,6 @@ func newStackdriverLogger(ctx context.Context, logID, projectID, service, versio "version_id": version, }, } - if lid := os.Getenv("SD_LOG_ID"); lid != "" { - logID = lid - } if isGAE() { resource.Type = "gae_app" logID = "app_logs" @@ -56,7 +53,7 @@ func newStackdriverLogger(ctx context.Context, logID, projectID, service, versio } resource.Type = typ } else { - return nil, nil, nil + return nil, nil, errors.New("unable to find monitored resource") } client, err := logging.NewClient(ctx, fmt.Sprintf("projects/%s", projectID)) From b313d00cf8d47604bddf1db8cdc14fbb89764d81 Mon Sep 17 00:00:00 2001 From: Oleksii Khliupin Date: Tue, 5 Feb 2019 14:58:33 -0500 Subject: [PATCH 3/5] Handling error of stackdriver logger creation --- server/kit/log.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/kit/log.go b/server/kit/log.go index 9e7d1dfce..7b5db24cc 100644 --- a/server/kit/log.go +++ b/server/kit/log.go @@ -26,7 +26,12 @@ func NewLogger(ctx context.Context, logID string) (log.Logger, func() error, err // if Stackdriver logger was not able to find information about monitored resource it returns nil. if lg == nil { // running locally or in a non-GAE environment? use JSON - return log.NewJSONLogger(log.NewSyncWriter(os.Stdout)), func() error { return nil }, nil + lg := log.NewJSONLogger(log.NewSyncWriter(os.Stdout)) + if err != nil { + lg.Log("error", err, + "message", "unable to initialize stackdriver logger. Fallback to JSON logger.") + } + return lg, func() error { return nil }, nil } return lg, cl, err } From 3cd096f644fa6ded975e13f6761f32091f0f924e Mon Sep 17 00:00:00 2001 From: Oleksii Khliupin Date: Tue, 5 Feb 2019 15:16:55 -0500 Subject: [PATCH 4/5] Handling error of stackdriver logger creation --- server/kit/log.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/server/kit/log.go b/server/kit/log.go index 7b5db24cc..5368ae92e 100644 --- a/server/kit/log.go +++ b/server/kit/log.go @@ -24,13 +24,11 @@ func NewLogger(ctx context.Context, logID string) (log.Logger, func() error, err projectID, serviceID, svcVersion := getGAEInfo() lg, cl, err := newStackdriverLogger(ctx, logID, projectID, serviceID, svcVersion) // if Stackdriver logger was not able to find information about monitored resource it returns nil. - if lg == nil { + if err != nil { // running locally or in a non-GAE environment? use JSON lg := log.NewJSONLogger(log.NewSyncWriter(os.Stdout)) - if err != nil { - lg.Log("error", err, - "message", "unable to initialize stackdriver logger. Fallback to JSON logger.") - } + lg.Log("error", err, + "message", "unable to initialize stackdriver logger. Fallback to JSON logger.") return lg, func() error { return nil }, nil } return lg, cl, err From 9939c30a404dce9274885307fb8ae717962175c5 Mon Sep 17 00:00:00 2001 From: Oleksii Khliupin Date: Tue, 5 Feb 2019 15:42:42 -0500 Subject: [PATCH 5/5] Docs for logID --- server/kit/log.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/kit/log.go b/server/kit/log.go index 5368ae92e..813714739 100644 --- a/server/kit/log.go +++ b/server/kit/log.go @@ -20,6 +20,10 @@ import ( // When using the Stackdriver logger, any go-kit/log/levels will be translated to // Stackdriver severity levels. // logID identifies, for Stackdriver, the resource name of the log to which this log entry belongs. +// LogID is used to create logName field of LogEntry (https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry). +// The purposes to have different logName are: +// - to be able to delete log records from Stackdriver. +// - filtering func NewLogger(ctx context.Context, logID string) (log.Logger, func() error, error) { projectID, serviceID, svcVersion := getGAEInfo() lg, cl, err := newStackdriverLogger(ctx, logID, projectID, serviceID, svcVersion)