{"id":18451812,"url":"https://github.com/remko/cloudrun-slog","last_synced_at":"2025-10-08T04:08:23.582Z","repository":{"id":188287203,"uuid":"678333863","full_name":"remko/cloudrun-slog","owner":"remko","description":"Example Cloud Run Go app with lightweight structured logging using `slog`","archived":false,"fork":false,"pushed_at":"2025-03-20T15:28:43.000Z","size":255,"stargazers_count":37,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-04T23:51:16.383Z","etag":null,"topics":["cloudrun","go","google","google-cloud-run","slog"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/remko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-14T10:04:29.000Z","updated_at":"2025-03-24T14:03:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"a63ce2df-50d2-441f-8ff6-49f44f989fd6","html_url":"https://github.com/remko/cloudrun-slog","commit_stats":null,"previous_names":["remko/cloudrun-slog"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/remko/cloudrun-slog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fcloudrun-slog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fcloudrun-slog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fcloudrun-slog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fcloudrun-slog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/remko","download_url":"https://codeload.github.com/remko/cloudrun-slog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fcloudrun-slog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273528173,"owners_count":25121750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudrun","go","google","google-cloud-run","slog"],"created_at":"2024-11-06T07:29:39.360Z","updated_at":"2025-10-08T04:08:18.538Z","avatar_url":"https://github.com/remko.png","language":"Go","readme":"# Example Cloud Run Go app with lightweight structured logging using `slog`\n\nThis is a small example of a Go web app for [Cloud Run](https://cloud.google.com/run) that uses\nGo 1.21's standard library [`slog`](https://pkg.go.dev/log/slog) package for structured logging to Cloud Logging.\n\nContrary to the [documented 'standard' approach for\nlogging](https://cloud.google.com/logging/docs/setup/go), this doesn't\nuse any third-party logging package for logging. Instead, it relies on\nCloud Run's support for ingesting structured logs by [simply printing\nJSON to standard\nerror](https://cloud.google.com/run/docs/logging#using-json).\n\n## Outputting structured JSON for Cloud Logging\n\nMost of the heavy lifting of logging can be done with the standard [`JSONHandler`](https://pkg.go.dev/golang.org/x/exp/slog#JSONHandler).\nCloud Logging uses [different naming for some attributes](https://cloud.google.com/logging/docs/agent/logging/configuration#special-fields), so these need to be renamed (which can be done using `HandlerOptions`).\n\nCloud Logging also supports a `CRITICAL` log level that isn’t part of the standard library, and support for this can be added in the\nsame place:\n\n```go\nh := slog.NewJSONHandler(os.Stderr, \u0026slog.HandlerOptions{\n  AddSource: true,\n  Level:     slog.LevelDebug,\n  ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {\n    if groups != nil {\n      return a\n    }\n    if a.Key == slog.MessageKey {\n      a.Key = \"message\"\n    } else if a.Key == slog.SourceKey {\n      a.Key = \"logging.googleapis.com/sourceLocation\"\n    } else if a.Key == slog.LevelKey {\n      a.Key = \"severity\"\n      level := a.Value.Any().(slog.Level)\n      if level == LevelCritical {\n        a.Value = slog.StringValue(\"CRITICAL\")\n      }\n    }\n    return a\n  })\n})\n\nconst LevelCritical = slog.Level(12)\n```\n\nUsing the resulting handler on the default logger ensures that all log messages are output in JSON that is automatically ingested by Cloud Logging, including file/line support and extra structured properties.\n\n```go\nslog.SetDefault(slog.New(h))\n\n…\n\nslog.Info(\"my message\", \n  \"mycount\", 42, \n  \"mystring\", \"myvalue\"\n)\n```\n\nAccessing this handler gives the following result in the Cloud Logging Console:\n\n![Cloud Logging screenshot with structured log output](doc/log.png)\n\n## Correlating structured logs with the request log\n\nUsing the above handler, all log messages appear in the Cloud Run logs, but they are not correlated with the request log of Cloud Run. To add a parent-child relationship between the log messages and the Cloud Run request log, the trace needs to be captured from the request headers, and added as an extra field in the JSON output. \n\nCapturing the trace can be done by adding a piece of middleware that extracts the trace ID from the request header, and adds it to the request context:\n\n```go\nfunc WithCloudTraceContext(h http.Handler) http.Handler {\n  projectID, err := metadata.ProjectID()\n  if err != nil {\n    panic(err)\n  }\n  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n    var trace string\n    traceHeader := r.Header.Get(\"X-Cloud-Trace-Context\")\n    traceParts := strings.Split(traceHeader, \"/\")\n    if len(traceParts) \u003e 0 \u0026\u0026 len(traceParts[0]) \u003e 0 {\n      trace = fmt.Sprintf(\"projects/%s/traces/%s\", projectID, traceParts[0])\n    }\n    h.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), \"trace\", trace)))\n  })\n}\n\nmux := http.NewServeMux()\n…\nhttp.ListenAndServe(\":\"+port, WithCloudTraceContext(mux))\n```\n\nThe trace ID can then be added to the output by defining a custom handler that extracts the trace from the context, and adds the extra attribute before passing it on to the standard JSON handler:\n\n```go\nfunc NewCloudLoggingHandler() *CloudLoggingHandler {\n  return \u0026CloudLoggingHandler{handler: slog.NewJSONHandler(…)}\n}\n\nfunc (h *CloudLoggingHandler) Handle(ctx context.Context, rec slog.Record) error {\n  trace := ctx.Value(\"trace\")\n  if trace != nil \u0026\u0026 trace.(string) != \"\" {\n    rec = rec.Clone()\n    rec.Add(\"logging.googleapis.com/trace\", slog.StringValue(trace.(string)))\n  }\n  return h.handler.Handle(ctx, rec)\n}\n```\n\nAll logs belonging to a specific request can now be inspected by opening the dropdown\nof the request of interest:\n\n![Cloud Logging screenshot with correlated logs](doc/correlated.png)\n\n\n## Full example\n\nThe full working example above can be seen [here](https://github.com/remko/cloudrun-slog/blob/main/main.go). \n\n(Note that App Engine supports the same structured JSON output approach, so the same code can be used there)\n\n","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremko%2Fcloudrun-slog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremko%2Fcloudrun-slog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremko%2Fcloudrun-slog/lists"}