Go logger with Kubernetes Stackdriver format compatibility

Originally published on my blog

I’m so proud to announce that a Go Logger package that our backend team at Teltech was working on is now open-source! It is our library for structured logging mechanism for Go projects running via Kubernetes with Stackdriver format compatibility.

For those who’d like to get started with Kubernetes, here are two free courses:
 1.
Scalable Microservices with Kubernetes by Google on Udacity. Kelsey Hightower is one of the instructors here!
 2. Introduction to Kubernetes by edX
For the curious, here’s an overview of logging in Kubernetes.

Installation

go get -u github.com/teltech/logger

Usage

package main

import (
"github.com/teltech/logger"
)

// There should be a LOG_LEVEL environment variable set, which is read by the library
// If no value is set, the default LOG_LEVEL will be INFO

func main() {
// Stackdriver requires a project name and version to be set. Use your environment for these values.
// SERVICE should be your GCP project-id, e.g. robokiller-146813
// VERSION is an arbitrary value
log := logger.New()

// You can also initialize the logger with a context; the values will persist throughout the scope of the logger instance
log = logger.New().With(logger.Fields{
"user": "+1234567890",
"action": "create-account",
})

param := "something useful here"

// A metric is an INFO log entry without a payload
log.Metric("CUSTOM_METRIC_ENTRY")

// Log a DEBUG message, only visible in when LOG_LEVEL is set to DEBUG
log.With(logger.Fields{"key": "val", "something": true}).Debug("debug message goes here")
log.With(logger.Fields{"key": "val"}).Debugf("debug message with %s", param)

// Log an INFO message
log.With(logger.Fields{"key": "val", "names": []string{"Mauricio", "Manuel"}}).Info("info message goes here")
log.With(logger.Fields{"key": "val"}).Infof("info message with %s", param)

// Log a WARN message
log.With(logger.Fields{"key": "val"}).Warn("warn message goes here")
log.With(logger.Fields{"key": "val"}).Warnf("warn message with %s", param)

// Error() prints the stacktrace as part of the payload for each entry and sends the
// data to Stackdriver Error Reporting service
log.With(logger.Fields{"key": "val"}).Error("error message goes here")
log.With(logger.Fields{"key": "val"}).Errorf("error message with %s", param)
}

Output

The errors require a specific JSON format for them to be ingested and processed by Google Cloud Platform Stackdriver Logging and Error Reporting. See this post for more info. The resulting output has the following format, optional fields are, well, optional:

{
"severity": "ERROR",
"eventTime": "2017-04-26T02:29:33-04:00",
"message": "An error just happened!",
"serviceContext": {
"service": "robokiller-ivr",
"version": "1.0"
},
"context": {
"data": {
"clientIP": "127.0.0.1"
"userAgent": "Mosaic 1.0"
},
"reportLocation": {
"filePath": "\/Users\/mc\/Documents\/src\/github.com\/macuenca\/apex\/mauricio.go",
"functionName": "unknown",
"lineNumber": 15
}
},
"stacktrace": "goroutine 1 [running]:main.main()\n\t\/github.com\/macuenca\/mauricio.go:15 +0x1a9\n"
}

Your Google Console StackDriver Error Reporting may then look something like this:

License

This package is licensed under the BSD 3-clause license.

Opportunities

If you like this project and would like to work on something similar, go check out our Careers page — we’re always looking for talented new people 🙌

Conclusion

This package has been very helpful to us, so we hope it helps someone else as well. If you have any remarks on the project, please submit a bug or PR 💪