Skip to content

Commit

Permalink
Add resource information to logger of GKE, GCE and AWS EC2 (#180)
Browse files Browse the repository at this point in the history
* Add resource information to logger of GKE, GCE and AWS EC2

* Remove env var. Add return error

* Handling error of stackdriver logger creation

* Handling error of stackdriver logger creation

* Docs for logID

* LogID Doc and use default values if is not provided

* Update error message

* Update doc
  • Loading branch information
gaplyk authored and jprobinson committed Feb 5, 2019
1 parent 30c33e4 commit a140a3d
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 26 deletions.
2 changes: 1 addition & 1 deletion server/kit/kitserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func NewServer(svc Service) *Server {

ctx := context.Background()

lg, logClose, err := NewLogger(ctx)
lg, logClose, err := NewLogger(ctx, "")
if err != nil {
stdlog.Fatalf("unable to start up logger: %s", err)
}
Expand Down
31 changes: 20 additions & 11 deletions server/kit/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,31 @@ 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() {
return log.NewJSONLogger(log.NewSyncWriter(os.Stdout)), func() error { return nil }, nil
}

// The logID field is used when the server is deployed in a Stackdriver enabled environment.
// If an empty string is provided, "gae_log" will be used in App Engine and "stdout" elsewhere.
// For more information about to use of logID see the documentation here: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#FIELDS.log_name
func NewLogger(ctx context.Context, logID string) (log.Logger, func() error, error) {
projectID, serviceID, svcVersion := getGAEInfo()
return newAppEngineLogger(ctx, projectID, serviceID, svcVersion)
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 err != nil {
// running locally or in a non-GAE environment? use JSON
lg := log.NewJSONLogger(log.NewSyncWriter(os.Stdout))
lg.Log("error", err,
"message", "unable to initialize Stackdriver logger. falling back to stdout JSON logging.")
return lg, func() error { return nil }, nil
}
return lg, cl, err
}

// Logger will return a kit/log.Logger that has been injected into the context by the kit
Expand Down
48 changes: 34 additions & 14 deletions server/kit/gae_log.go → server/kit/sd_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -27,34 +28,53 @@ 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 isGAE() {
resource.Type = "gae_app"
if logID == "" {
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
if logID == "" {
logID = "stdout"
}
} else {
return nil, nil, errors.New("unable to find monitored resource")
}

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 != "" {
Expand Down Expand Up @@ -87,7 +107,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]
}

Expand Down

0 comments on commit a140a3d

Please sign in to comment.