{"id":14987687,"url":"https://github.com/bose/go-gin-logrus","last_synced_at":"2025-08-02T10:04:44.966Z","repository":{"id":57484376,"uuid":"139775520","full_name":"Bose/go-gin-logrus","owner":"Bose","description":"Gin Web Framework for using Logrus as the Gin logger with Tracing middleware","archived":false,"fork":false,"pushed_at":"2020-06-16T19:01:09.000Z","size":90,"stargazers_count":41,"open_issues_count":2,"forks_count":9,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-12T00:16:41.246Z","etag":null,"topics":["gin","gin-gonic","gin-middleware","go","logrus","middleware","opentracing","trace"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Bose.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}},"created_at":"2018-07-05T00:10:28.000Z","updated_at":"2025-01-03T21:47:16.000Z","dependencies_parsed_at":"2022-08-26T13:23:13.086Z","dependency_job_id":null,"html_url":"https://github.com/Bose/go-gin-logrus","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fgo-gin-logrus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fgo-gin-logrus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fgo-gin-logrus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Bose%2Fgo-gin-logrus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Bose","download_url":"https://codeload.github.com/Bose/go-gin-logrus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248497818,"owners_count":21113984,"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","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":["gin","gin-gonic","gin-middleware","go","logrus","middleware","opentracing","trace"],"created_at":"2024-09-24T14:15:10.873Z","updated_at":"2025-04-12T00:16:48.363Z","avatar_url":"https://github.com/Bose.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-gin-logrus\n[![](https://godoc.org/github.com/Bose/go-gin-logrus?status.svg)](https://godoc.org/github.com/Bose/go-gin-logrus)\n[![Go Report Card](https://goreportcard.com/badge/github.com/Bose/go-gin-logrus)](https://goreportcard.com/report/github.com/Bose/go-gin-logrus)\n[![Release](https://img.shields.io/github/release/Bose/go-gin-logrus.svg?style=flat-square)](https://Bose/go-gin-logrus/releases)\n\nGin Web Framework Open Tracing middleware.\n\nThis middleware also support aggregate logging: the ability to aggregate all log entries into just one write.  This aggregation is helpful when your logs are being sent to Kibana and you only want to index one log per request.\n\n## Installation\n\n`$ go get github.com/Bose/go-gin-logrus`\n\nIf you want to use it with opentracing you could consider installing:\n\n`$ go get github.com/Bose/go-gin-opentracing`\n\n## Dependencies - for local development\nIf you want to see your traces on your local system, you'll need to run a tracing backend like Jaeger.   You'll find info about how-to in the [Jaeger Tracing github repo docs](https://github.com/jaegertracing/documentation/blob/master/content/docs/getting-started.md)\nBasically, you can run the Jaeger opentracing backend under docker via:\n\n```bash \ndocker run -d -e \\\n  COLLECTOR_ZIPKIN_HTTP_PORT=9411 \\\n  -p 5775:5775/udp \\\n  -p 6831:6831/udp \\\n  -p 6832:6832/udp \\\n  -p 5778:5778 \\\n  -p 16686:16686 \\\n  -p 14268:14268 \\\n  -p 9411:9411 \\\n  jaegertracing/all-in-one:latest\n  ```\n## Usage\n```\n# example aggregated log entry for a request with UseBanner == true\n{\n  \"new-header-index-name\": \"this is how you set new header level data\",\n  \"request-summary-info\": {\n    \"comment\": \"\",\n    \"ip\": \"::1\",\n    \"latency\": \"     98.217µs\",\n    \"method\": \"GET\",\n    \"path\": \"/\",\n    \"requestID\": \"4b4fb22ef51cc540:4b4fb22ef51cc540:0:1\",\n    \"status\": 200,\n    \"time\": \"2019-02-06T13:24:06Z\",\n    \"user-agent\": \"curl/7.54.0\"\n  },\n  \"entries\": [\n    {\n      \"level\": \"info\",\n      \"msg\": \"this will be aggregated into one write with the access log and will show up when the request is completed\",\n      \"time\": \"2019-02-06T08:24:06-05:00\"\n    },\n    {\n      \"comment\": \"this is an aggregated log entry with initial comment field\",\n      \"level\": \"debug\",\n      \"msg\": \"aggregated entry with new comment field\",\n      \"time\": \"2019-02-06T08:24:06-05:00\"\n    },\n    {\n      \"level\": \"error\",\n      \"msg\": \"aggregated error entry with new-comment field\",\n      \"new-comment\": \"this is an aggregated log entry with reset comment field\",\n      \"time\": \"2019-02-06T08:24:06-05:00\"\n    }\n  ],\n  \"banner\": \"[GIN] --------------------------------------------------------------- GinLogrusWithTracing ----------------------------------------------------------------\"\n}\n\n```\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"time\"\n\n\t\"github.com/opentracing/opentracing-go/ext\"\n\n\tginlogrus \"github.com/Bose/go-gin-logrus\"\n\tginopentracing \"github.com/Bose/go-gin-opentracing\"\n\t\"github.com/gin-gonic/gin\"\n\topentracing \"github.com/opentracing/opentracing-go\"\n\t\"github.com/sirupsen/logrus\"\n)\n\nfunc main() {\n\t// use the JSON formatter\n\tlogrus.SetFormatter(\u0026logrus.JSONFormatter{})\n\n\tr := gin.New() // don't use the Default(), since it comes with a logger\n\n\t// setup tracing...\n\thostName, err := os.Hostname()\n\tif err != nil {\n\t\thostName = \"unknown\"\n\t}\n\n\ttracer, reporter, closer, err := ginopentracing.InitTracing(\n\t\tfmt.Sprintf(\"go-gin-logrus-example::%s\", hostName), // service name for the traces\n\t\t\"localhost:5775\",                        // where to send the spans\n\t\tginopentracing.WithEnableInfoLog(false)) // WithEnableLogInfo(false) will not log info on every span sent... if set to true it will log and they won't be aggregated\n\tif err != nil {\n\t\tpanic(\"unable to init tracing\")\n\t}\n\tdefer closer.Close()\n\tdefer reporter.Close()\n\topentracing.SetGlobalTracer(tracer)\n\n\tp := ginopentracing.OpenTracer([]byte(\"api-request-\"))\n\tr.Use(p)\n\n\tr.Use(gin.Recovery()) // add Recovery middleware\n\tuseBanner := true\n\tuseUTC := true\n\tr.Use(ginlogrus.WithTracing(logrus.StandardLogger(),\n\t\tuseBanner,\n\t\ttime.RFC3339,\n\t\tuseUTC,\n\t\t\"requestID\",\n\t\t[]byte(\"uber-trace-id\"), // where jaeger might have put the trace id\n\t\t[]byte(\"RequestID\"),     // where the trace ID might already be populated in the headers\n\t\tginlogrus.WithAggregateLogging(true)))\n\n\tr.GET(\"/\", func(c *gin.Context) {\n\t\tginlogrus.SetCtxLoggerHeader(c, \"new-header-index-name\", \"this is how you set new header level data\")\n\n\t\tlogger := ginlogrus.GetCtxLogger(c) // will get a logger with the aggregate Logger set if it's enabled - handy if you've already set fields for the request\n\t\tlogger.Info(\"this will be aggregated into one write with the access log and will show up when the request is completed\")\n\n\t\t// add some new fields to the existing logger\n\t\tlogger = ginlogrus.SetCtxLogger(c, logger.WithFields(logrus.Fields{\"comment\": \"this is an aggregated log entry with initial comment field\"}))\n\t\tlogger.Debug(\"aggregated entry with new comment field\")\n\n\t\t// replace existing logger fields with new ones (notice it's logrus.WithFields())\n\t\tlogger = ginlogrus.SetCtxLogger(c, logrus.WithFields(logrus.Fields{\"new-comment\": \"this is an aggregated log entry with reset comment field\"}))\n\t\tlogger.Error(\"aggregated error entry with new-comment field\")\n\n\t\tlogrus.Info(\"this will NOT be aggregated and will be logged immediately\")\n\t\tspan := newSpanFromContext(c, \"sleep-span\")\n\t\tdefer span.Finish() // this will get logged because tracing was setup with ginopentracing.WithEnableInfoLog(true)\n\n\t\tgo func() {\n\t\t\t// need a NewBuffer for aggregate logging of this goroutine (since the req will be done long before this thing finishes)\n\t\t\t// it will inherit header info from the existing request\n\t\t\tbuff := ginlogrus.NewBuffer(logger)\n\t\t\ttime.Sleep(1 * time.Second)\n\t\t\tlogger.Info(\"Hi from a goroutine completing after the request\")\n\t\t\tfmt.Printf(buff.String())\n\t\t}()\n\t\tc.JSON(200, \"Hello world!\")\n\t})\n\n\tr.Run(\":29090\")\n}\n\nfunc newSpanFromContext(c *gin.Context, operationName string) opentracing.Span {\n\tparentSpan, _ := c.Get(\"tracing-context\")\n\toptions := []opentracing.StartSpanOption{\n\t\topentracing.Tag{Key: ext.SpanKindRPCServer.Key, Value: ext.SpanKindRPCServer.Value},\n\t\topentracing.Tag{Key: string(ext.HTTPMethod), Value: c.Request.Method},\n\t\topentracing.Tag{Key: string(ext.HTTPUrl), Value: c.Request.URL.Path},\n\t\topentracing.Tag{Key: \"current-goroutines\", Value: runtime.NumGoroutine()},\n\t}\n\n\tif parentSpan != nil {\n\t\toptions = append(options, opentracing.ChildOf(parentSpan.(opentracing.Span).Context()))\n\t}\n\n\treturn opentracing.StartSpan(operationName, options...)\n}\n\n\n```\n\nSee the [example.go file](https://github.com/Bose/go-gin-logrus/blob/master/example/example.go)\n\n## Reduced Logging Options\nThe Options.WithReducedLoggingFunc(c *gin.Context) allows users to specify a function for determining whether or not logs will be written. This function can be used with aggregate logging in situations where users want to maintain the details and fidelity of log messages but not necessarily log on every single request. The example below allows users to maintain aggregate logs at the DEBUG level but only write logs out on non-2xx response codes. \nReduced Logging Function:\n``` go\n// This function will determine whether to write a log message or not.\n// When the request is not a 2xx the function will return true indicating that a log message should be written.\nfunc ProductionLogging(c *gin.Context) bool {\n\tstatusCode := c.Writer.Status()\n\tif statusCode \u003c http.StatusOK || statusCode \u003e= http.StatusMultipleChoices {\n\t\treturn true\n\t}\n\treturn false\n}\n```\n\n``` go\n\tr.Use(ginlogrus.WithTracing(logrus.StandardLogger(),\n\t\tuseBanner,\n\t\ttime.RFC3339,\n\t\tuseUTC,\n\t\t\"requestID\",\n\t\t[]byte(\"uber-trace-id\"), // where jaeger might have put the trace id\n\t\t[]byte(\"RequestID\"),     // where the trace ID might already be populated in the headers\n\t\tginlogrus.WithAggregateLogging(true),\n\t\tginlogrus.WithReducedLoggingFunc(ProductionLogging)))\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbose%2Fgo-gin-logrus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbose%2Fgo-gin-logrus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbose%2Fgo-gin-logrus/lists"}