{"id":3808,"date":"2017-11-08T10:28:04","date_gmt":"2017-11-08T10:28:04","guid":{"rendered":"http:\/\/www.nikola-breznjak.com\/blog\/?p=3808"},"modified":"2017-11-08T14:50:51","modified_gmt":"2017-11-08T14:50:51","slug":"go-logger-kubernetes-stackdriver-format-compatibility","status":"publish","type":"post","link":"https:\/\/nikola-breznjak.com\/blog\/go\/go-logger-kubernetes-stackdriver-format-compatibility\/","title":{"rendered":"Go logger with Kubernetes Stackdriver format compatibility"},"content":{"rendered":"<p>I&#8217;m so proud to announce that a Go <a href=\"https:\/\/github.com\/teltech\/logger\">Logger<\/a> package that our backend team at <a href=\"http:\/\/teltech.co\/\">TelTech<\/a> was working on is now open-source! It is our library for structured logging mechanism for Go projects running via Kubernetes with <a href=\"https:\/\/cloud.google.com\/error-reporting\/docs\/formatting-error-messages\">Stackdriver format<\/a> compatibility.<\/p>\n<blockquote><p>\n  For those who&#8217;d like to get started with Kubernetes, here are two free courses:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.udacity.com\/course\/scalable-microservices-with-kubernetes--ud615\">Scalable Microservices with Kubernetes by Google<\/a> on Udacity. <a href=\"https:\/\/twitter.com\/kelseyhightower\">Kelsey Hightower<\/a> is one of the instructors here!<\/li>\n<li><a href=\"https:\/\/www.edx.org\/course\/introduction-kubernetes-linuxfoundationx-lfs158x\">Introduction to Kubernetes<\/a> by edX<\/li>\n<\/ul>\n<p>  For the curious, here&#8217;s an <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/cluster-administration\/logging\">overview of logging in Kubernetes<\/a>.\n<\/p><\/blockquote>\n<h2>Installation<\/h2>\n<p><code>go get -u github.com\/teltech\/logger<\/code><\/p>\n<h2>Usage<\/h2>\n<pre><code>package main\n\nimport (\n    \"github.com\/teltech\/logger\"\n)\n\n\/\/ There should be a LOG_LEVEL environment variable set, which is read by the library\n\/\/ If no value is set, the default LOG_LEVEL will be INFO\n\nfunc main() {\n    \/\/ Stackdriver requires a project name and version to be set. Use your environment for these values.\n    \/\/ SERVICE should be your GCP project-id, e.g. robokiller-146813\n    \/\/ VERSION is an arbitrary value\n    log := logger.New()\n\n    \/\/ You can also initialize the logger with a context; the values will persist throughout the scope of the logger instance\n    log = logger.New().With(logger.Fields{\n        \"user\":   \"+1234567890\",\n        \"action\": \"create-account\",\n    })\n\n    param := \"something useful here\"\n\n    \/\/ A metric is an INFO log entry without a payload\n    log.Metric(\"CUSTOM_METRIC_ENTRY\")\n\n    \/\/ Log a DEBUG message, only visible in when LOG_LEVEL is set to DEBUG\n    log.With(logger.Fields{\"key\": \"val\", \"something\": true}).Debug(\"debug message goes here\")\n    log.With(logger.Fields{\"key\": \"val\"}).Debugf(\"debug message with %s\", param)\n\n    \/\/ Log an INFO message\n    log.With(logger.Fields{\"key\": \"val\", \"names\": []string{\"Mauricio\", \"Manuel\"}}).Info(\"info message goes here\")\n    log.With(logger.Fields{\"key\": \"val\"}).Infof(\"info message with %s\", param)\n\n    \/\/ Log a WARN message\n    log.With(logger.Fields{\"key\": \"val\"}).Warn(\"warn message goes here\")\n    log.With(logger.Fields{\"key\": \"val\"}).Warnf(\"warn message with %s\", param)\n\n    \/\/ Error() prints the stacktrace as part of the payload for each entry and sends the\n    \/\/ data to Stackdriver Error Reporting service\n    log.With(logger.Fields{\"key\": \"val\"}).Error(\"error message goes here\")\n    log.With(logger.Fields{\"key\": \"val\"}).Errorf(\"error message with %s\", param)\n}\n<\/code><\/pre>\n<h2>Output<\/h2>\n<p>The errors require a specific JSON format for them to be ingested and processed by Google Cloud Platform Stackdriver Logging and Error Reporting. See <a href=\"https:\/\/cloud.google.com\/error-reporting\/docs\/formatting-error-messages\">this post<\/a> for more info. The resulting output has the following format, optional fields are, well, optional:<\/p>\n<pre><code> {\n  \"severity\": \"ERROR\",\n  \"eventTime\": \"2017-04-26T02:29:33-04:00\",\n  \"message\": \"An error just happened!\",\n  \"serviceContext\": {\n     \"service\": \"robokiller-ivr\",\n     \"version\": \"1.0\"\n  },\n  \"context\": {\n    \"data\": {\n      \"clientIP\": \"127.0.0.1\"\n      \"userAgent\": \"Mosaic 1.0\"\n    },\n    \"reportLocation\": {\n      \"filePath\": \"\\\/Users\\\/mc\\\/Documents\\\/src\\\/github.com\\\/macuenca\\\/apex\\\/mauricio.go\",\n      \"functionName\": \"unknown\",\n      \"lineNumber\": 15\n    }\n  },\n \"stacktrace\": \"goroutine 1 [running]:main.main()\\n\\t\\\/github.com\\\/macuenca\\\/mauricio.go:15 +0x1a9\\n\"\n}\n<\/code><\/pre>\n<p>Your Google Console StackDriver Error Reporting may then look something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/fC8Gk0w.png\" alt=\"\" \/><\/p>\n<h2>License<\/h2>\n<p>This package is licensed under the <a href=\"https:\/\/opensource.org\/licenses\/BSD-3-Clause\">BSD 3-clause<\/a> license.<\/p>\n<h2>Opportunities<\/h2>\n<p>If you like this project and would like to work on something similar, go check out <a href=\"http:\/\/teltech.co\/careers\">our Careers page<\/a> &#8211; we&#8217;re always looking for talented new people ?<\/p>\n<h2>Conclusion<\/h2>\n<p>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 ?<\/p>\n<blockquote class=\"twitter-tweet\" data-width=\"550\">\n<p lang=\"en\" dir=\"ltr\"><a href=\"https:\/\/twitter.com\/hashtag\/Go?src=hash&amp;ref_src=twsrc%5Etfw\">#Go<\/a> logger with <a href=\"https:\/\/twitter.com\/hashtag\/Kubernetes?src=hash&amp;ref_src=twsrc%5Etfw\">#Kubernetes<\/a> <a href=\"https:\/\/twitter.com\/hashtag\/Stackdriver?src=hash&amp;ref_src=twsrc%5Etfw\">#Stackdriver<\/a> format compatibility open-sourced by <a href=\"https:\/\/twitter.com\/teltech?ref_src=twsrc%5Etfw\">@teltech<\/a> <a href=\"https:\/\/t.co\/w1ev6PCf69\">https:\/\/t.co\/w1ev6PCf69<\/a><\/p>\n<p>&mdash; Nikola Bre\u017enjak (@HitmanHR) <a href=\"https:\/\/twitter.com\/HitmanHR\/status\/928209412598136832?ref_src=twsrc%5Etfw\">November 8, 2017<\/a><\/p><\/blockquote>\n<p><script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;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&hellip;<\/p>\n","protected":false},"author":1,"featured_media":3809,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55],"tags":[],"class_list":["post-3808","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-go"],"_links":{"self":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/3808","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/comments?post=3808"}],"version-history":[{"count":5,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/3808\/revisions"}],"predecessor-version":[{"id":3814,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/3808\/revisions\/3814"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media\/3809"}],"wp:attachment":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media?parent=3808"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/categories?post=3808"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/tags?post=3808"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}