{"id":13615248,"url":"https://github.com/MadAppGang/httplog","last_synced_at":"2025-04-13T21:30:39.274Z","repository":{"id":56854906,"uuid":"524270841","full_name":"MadAppGang/httplog","owner":"MadAppGang","description":"Golang HTTP logger middleware with color console output and structured logs","archived":false,"fork":false,"pushed_at":"2023-03-01T04:54:01.000Z","size":2974,"stargazers_count":130,"open_issues_count":6,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-10T10:15:32.747Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/MadAppGang.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":"2022-08-13T01:42:51.000Z","updated_at":"2025-03-15T23:21:30.000Z","dependencies_parsed_at":"2024-06-18T19:46:09.968Z","dependency_job_id":"f4cf8fee-1a5d-4286-b495-1fa798603dfa","html_url":"https://github.com/MadAppGang/httplog","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadAppGang%2Fhttplog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadAppGang%2Fhttplog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadAppGang%2Fhttplog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadAppGang%2Fhttplog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MadAppGang","download_url":"https://codeload.github.com/MadAppGang/httplog/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248785891,"owners_count":21161369,"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":[],"created_at":"2024-08-01T20:01:11.032Z","updated_at":"2025-04-13T21:30:37.499Z","avatar_url":"https://github.com/MadAppGang.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Beautiful logger for http\n\nProudly created and supported by [MadAppGang](https://madappgang.com) company.\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/MadAppGang/httplog.svg)](https://pkg.go.dev/github.com/MadAppGang/httplog)\n[![Go Report Card](https://goreportcard.com/badge/github.com/MadAppGang/httplog)](https://goreportcard.com/report/github.com/MadAppGang/httplog)\n[![codecov](https://codecov.io/gh/MadAppGang/httplog/branch/main/graph/badge.svg?token=BJT0WRNJS1)](https://codecov.io/gh/MadAppGang/httplog)\n\n## Why?\n\nEvery single web framework has a build-in logger already, why do we need on more?\nThe question is simple and the answer is not.\n\nThe best logger is structured logger, like [Uber Zap](https://github.com/uber-go/zap). Structure logs are essentials today to help collect and analyze logs with monitoring tools like ElasticSearch or DataDog.\n\nBut what about humans? Obviously you can go to your monitoring tool and parse your structured logs. But what about seeing human readable logs in place just in console? Although you can read JSON, it is extremely hard to find most critical information in the large JSON data flow.\n\nHttplog package brings good for humans and log collection systems, you can use tools like zap to create structured logs and see colored beautiful human-friendly output in console in place. Win-win for human and machines 🤖❤️👩🏽‍💻\n\nNice and clean output is critical for any web framework. Than is why some people use go web frameworks just to get beautiful logs.\n\nThis library brings you fantastic http logs to any web framework, even if you use native `net/http` for that.\n\nBut it's better to see once, here the default output you will get with couple of lines of code:\n\n![logs screenshot](docs/logs_screenshot.png)\n\nAnd actual code looks like this:\n\n```go\n  func main() {\n    // setup routes\n    http.Handle(\"/happy\", httplog.Logger(happyHandler))\n    http.Handle(\"/not_found\", httplog.Logger(http.NotFoundHandler()))\n\n    //run server\n    _ = http.ListenAndServe(\":3333\", nil)\n  }\n```\n\n\nAll you need is wrap you handler with `httplog.Logger` and the magic happens.\n\nAnd this is how the structured logs looks in AWS CloudWatch. As you can see, the color output looks not as good here as in console. But JSON structured logs are awesome 😍\n\n![structured logs](docs/structured_logs.com.png)\n\nHere is a main features:\n\n- framework agnostic (could be easily integrated with any web framework), you can find `examples` for:\n  - [alice](https://github.com/MadAppGang/httplog/blob/main/examples/alice/main.go)\n  - [chi](https://github.com/MadAppGang/httplog/blob/main/examples/chi/main.go)\n  - [echo](https://github.com/MadAppGang/httplog/blob/main/examples/echo/main.go)\n  - [gin](https://github.com/MadAppGang/httplog/blob/main/examples/gin/main.go)\n  - [goji](https://github.com/MadAppGang/httplog/blob/main/examples/goji/main.go)\n  - [gorilla mux](https://github.com/MadAppGang/httplog/blob/main/examples/gorilla/main.go)\n  - [httprouter](https://github.com/MadAppGang/httplog/blob/main/examples/httprouter/main.go)\n  - [mojito](https://github.com/MadAppGang/httplog/blob/main/examples/mojito/main.go)\n  - [negroni](https://github.com/MadAppGang/httplog/blob/main/examples/negroni/main.go)\n  - [native net/http](https://github.com/MadAppGang/httplog/blob/main/examples/nethttp/main.go)\n  - not found yours? let us know and we will add it\n- response code using special wrapper\n- response length using special wrapper\n- can copy response body\n- get real user IP for Google App Engine\n- get real user IP for CloudFront\n- get real user IP for other reverse proxy which implements [RFC7239](https://www.rfc-editor.org/rfc/rfc7239.html)\n- customize output format\n- has the list of routes to ignore\n- build in structure logger integration\n- callback function to modify response before write back (add headers or do something)\n\nThis framework is highly inspired by [Gin logger](https://github.com/gin-gonic/gin/blob/master/logger.go) library, but has not Gin dependencies at all and has some improvements.\nHttplog has only one dependency at all: `github.com/mattn/go-isatty`. So it's will not affect your codebase size.\n\n## Custom format\n\nYou can modify formatter as you want. Now there are two formatter available:\n\n- `DefaultLogFormatter`\n- `ShortLogFormatter`\n- `HeadersLogFormatter`\n- `DefaultLogFormatterWithHeaders`\n- `BodyLogFormatter`\n- `DefaultLogFormatterWithHeadersAndBody`\n- `RequestHeaderLogFormatter`\n- `DefaultLogFormatterWithRequestHeader`\n- `RequestBodyLogFormatter`\n- `DefaultLogFormatterWithRequestHeadersAndBody`\n- `FullFormatterWithRequestAndResponseHeadersAndBody`\n\nAnd you can combine them using `ChainLogFormatter`.\n\nHere is an example of formatter in code:\n\n```go\n// Short log formatter\nshortLoggedHandler := httplog.LoggerWithFormatter(\n  httplog.ShortLogFormatter,\n  wrappedHandler,\n)\n```\n\nYou can define your own log format. Log formatter is a function with a set of precalculated parameters:\n\n```go\n// Custom log formatter\ncustomLoggedHandler := httplog.LoggerWithFormatter(\n  // formatter is a function, you can define your own\n  func(param httplog.LogFormatterParams) string {\n    statusColor := param.StatusCodeColor()\n    resetColor := param.ResetColor()\n    boldRedText := \"\\033[1;31m\"\n\n    return fmt.Sprintf(\"🥑[I am custom router!!!] %s %3d %s| size: %10d bytes | %s %#v %s 🔮👨🏻‍💻\\n\",\n      statusColor, param.StatusCode, resetColor,\n      param.BodySize,\n      boldRedText, param.Path, resetColor,\n    )\n  },\n  happyHandler,\n)\nhttp.Handle(\"/happy_custom\", customLoggedHandler)\n```\n\nFor more details and how to capture response body please look in the [example app](https://github.com/MadAppGang/httplog/blob/main/examples/custom_formatter/main.go).\n\nparams is a type of LogFormatterParams and the following params available for you:\n\n| param | description |\n| --- | --- |\n| Request | `http.Request` instance |\n| RouterName | when you create logger, you can specify router name |\n| Timestamp | TimeStamp shows the time after the server returns a response |\n| StatusCode | StatusCode is HTTP response code |\n| Latency | Latency is how much time the server cost to process a certain request |\n| ClientIP | ClientIP calculated real IP of requester, see Proxy for details |\n| Method | Method is the HTTP method given to the request |\n| Path | Path is a path the client requests |\n| BodySize | BodySize is the size of the Response Body |\n| Body | Body is a body content, if body is copied |\n\n## Integrate with structure logger\n\nGood and nice output is good, but as soon as we have so much data about every response it is a good idea to pass it to our application log structured collector.\n\nOne of the most popular solution is [Uber zap](https://github.com/uber-go/zap).\nYou can use any structured logger you want, use zap's integration example as a reference.\n\nAll you need is create custom log formatter function with your logger integration.\nThis repository has this formatter for zap created and you can use it importing `github.com/MadAppGang/httplog/zap`:\n\n```go\nlogger := httplog.LoggerWithConfig(\n  httplog.LoggerConfig{\n    Formatter:  lzap.DefaultZapLogger(zapLogger, zap.InfoLevel, \"\"),\n  },\n  http.HandlerFunc(handler),\n)\nhttp.Handle(\"/happy\", logger)\n```\n\nYou can find full-featured [example in zap integration folder](https://github.com/MadAppGang/httplog/blob/main/examples/zap/main.go).\n\n## Customize log output destination\n\nYou can use any output you need, your output must support `io.Writer` protocol.\nAfter that you need init logger:\n\n```go\nbuffer := new(bytes.Buffer)\nlogger := LoggerWithWriter(buffer, handler) //all output is written to buffer\n```\n\n## Care about secrets. Skipping path and masking headers\n\nSome destinations should not be logged. For that purpose logger config has `SkipPaths` property with array of strings. Each string is a Regexp for path you want to skip. You can write exact path to skip, which would be valid regexp, or you can use regexp power:\n\n```go\n\nlogger := LoggerWithConfig(LoggerConfig{\n  SkipPaths: []string{\n    \"/skipped\",\n    \"/payments/\\\\w+\",\n    \"/user/[0-9]+\",\n  },\n}, handler)\n\n\nThe other feature to safe your logs from leaking secrets is Header masking. For example you do not want to log Bearer token header, but it is  useful to see it is present and not empty.\n\nFor this purpose `LoggerConfig` has field `HideHeaderKeys` which works the same as `SkipPaths`. Just feed an array of case insensitive key names regexps like that:\n\n```go\n\nlogger := LoggerWithConfig(LoggerConfig{\n  HideHeaderKeys: []string{\n    \"Bearer\",\n    \"Secret-Key\",\n    \"Cookie\",\n  },\n}, handler)\n\n```\n\nIf regexp is failed to compile, the logger will skip and and it will write the message to the log output destination.\n\n## Use GoogleApp Engine or CloudFlare\n\nYou application is operating behind load balancers and reverse proxies. That is why origination IP address is changing on every hop.\nTo save the first sender's IP (real user remote IP) reverse proxies should save original IP in request headers.\nDefault headers are `X-Forwarded-For` and `X-Real-IP`.\n\nBut some clouds have custom headers, like Cloudflare and Google Apps Engine.\nIf you are using those clouds or have custom headers in you environment, you can handle that by using custom `Proxy` init parameters:\n\n```go\nhttplog.LoggerWithConfig(\n  httplog.LoggerConfig{\n    ProxyHandler: NewProxyWithType(httpdlog.ProxyGoogleAppEngine),\n  },\nhttp.HandlerFunc(h),\n```\n\nor if you have your custom headers:\n\n```go\nlogger := httplog.LoggerWithConfig(\n  httplog.LoggerConfig{\n    ProxyHandler: NewProxyWithTypeAndHeaders(\n      httpdlog.ProxyDefaultType,\n      []string{\"My-HEADER-NAME\", \"OTHER-HEADER-NAME\"}\n    ),\n  },\n  handler,\n)\n\n```\n\n## How to save request body and headers\n\nYou can capture response data as well. But please use it in dev environments only, as it use extra resources and produce a lot of output in terminal. Example of body output [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/body_formatter/main.go).\n\n![body output](docs/full_body_formatter.png)\n\nYou can use `DefaultLogFormatterWithHeaders` for headers output or `DefaultLogFormatterWithHeadersAndBody` to output response body. Don't forget to set `CaptureBody` in LoggerParams.\n\nYou can combine your custom Formatter and `HeadersLogFormatter` or/and `BodyLogFormatter` using `ChainLogFormatter`:\n\n```go\nvar myFormatter = httplog.ChainLogFormatter(\n  MyLogFormatter,\n  httplog.HeadersLogFormatter,\n  httplog.BodyLogFormatter,\n)\n```\n\n## Integration examples\n\nPlease go to examples folder and see how it's work:\n\n![Run demo](docs/demo_run.gif)\n\n### Native `net/http` package\n\nThis package is suing canonical golang approach, and it easy to implement it with all `net/http` package.\n\n```go\nhttp.Handle(\"/not_found\", httplog.Logger(http.NotFoundHandler()))\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/nethttp/main.go).\n\n### Alice middleware\n\nAlice is a fantastic lightweight framework to chain and manage middlewares. As Alice is using canonical approach, it is working with httplog out-of-the-box.\n\nYou don't need any wrappers and you can user logger directly:\n\n```golang\n\n.....\nchain := alice.New(httplog.Logger, nosurf.NewPure)\nmux.Handle(\"/happy\", chain.Then(happyHandler()))\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/alice/main.go).\n\n### Chi\n\nChi is a router which uses the standard approach as `Alice` package.\n\nYou don't need any wrappers and you can user logger directly:\n\n```go\n\nr := chi.NewRouter()\nr.Use(httplog.Logger)\nr.Get(\"/happy\", happyHandler)\n...\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/chi/main.go).\n\n```\n\n### Echo\n\nEcho middleware uses internal `echo.Context` to manage request/responser flow and middleware management.\n\nAs a result, `echo` creates it's own http.ResponseWriter wrapper to catch all written data.\nThat is why `httplog` could not handle it automatically.\n\nTo handle that there is a package `httplog/chilog` which has all the native echo middlewares to use:\n\n\n```go\n\te := echo.New()\n\n\t// Middleware\n\te.Use(echolog.LoggerWithName(\"ECHO NATIVE\"))\n\te.GET(\"/happy\", happyHandler)\n\te.POST(\"/happy\", happyHandler)\n\te.GET(\"/not_found\", echo.NotFoundHandler)\n\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/echo/main.go).\n\n### Gin\n\nGin has the most beautiful log output. That is why this package has build highly inspired by `Gin's` logger.\n\nIf you missing some features of Gin's native logger and want to use this one, it is still possible.\n\nGin middleware uses internal `gin.Context` to manage request/responser flow and middleware management. The same approach as `Echo`.\n\nThat is why we created `httplog`, to bring this fantastic logger to native golang world :-)\n\n`Gin` creates it's own http.ResponseWriter wrapper to catch all written data.\nThat is why `httplog` could not handle it automatically.\n\nTo handle that there is a package `httplog/ginlog` which has all the native gin middlewares to use:\n\n\n```go\n  r := gin.New()\n\tr.Use(ginlog.LoggerWithName(\"I AM GIN ROUTER\"))\n\tr.GET(\"/happy\", happyHandler)\n\tr.POST(\"/happy\", happyHandler)\n\tr.GET(\"/not_found\", gin.WrapF(http.NotFound))\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/gin/main.go).\n\n### Goji\n\nGoji is using canonical middleware approach, that is why it is working with httplog out-of-the-box.\n\nYou don't need wrappers or anything like that.\n\n```go\nmux := goji.NewMux()\nmux.Handle(pat.Get(\"/happy\"), httplog.Logger(happyHandler))\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/goji/main.go).\n\n### Gorilla\n\nGorilla mux is one of the most loved muxer/router.\nGorilla is using canonical middleware approach, that is why it is working with httplog out-of-the-box.\n\nYou don't need to create any wrappers:\n\n```go\n\nr := mux.NewRouter()\nr.HandleFunc(\"/happy\", happyHandler)\nr.Use(httplog.Logger)\n\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/gorilla/main.go).\n\n### HTTPRouter\n\nTo use HTPPRouter you need to create simple wrapper. As HTTPRouter using custom `httprouter.Handler` and additional argument with params in handler function.\n\n```go\nfunc LoggerMiddleware(h httprouter.Handle) httprouter.Handle {\n\tlogger := httplog.LoggerWithName(\"ME\")\n\treturn func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {\n\t\thandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\th(w, r, ps)\n\t\t})\n\t\tlogger(handler).ServeHTTP(w, r)\n\t}\n}\n\n//use as native middleware\nrouter := httprouter.New()\nrouter.GET(\"/happy\", LoggerMiddleware(happyHandler))\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/httprouter/main.go).\n\n### Mojito\nBecause Go-Mojito uses dynamic handler functions, which include support for net/http types, httplog works out-of-the-box:  \n\n```go\nmojito.WithMiddleware(httplog.Logger)\nmojito.GET(\"/happy\", happyHandler)\n```\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/mojito/main.go).\n\n### Negroni\n\nNegroni uses custom `negroni.Handler` as middleware. We need to create custom wrapper for that:\n\n```go\nvar negroniLoggerMiddleware negroni.Handler = negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {\n  logger := httplog.Logger(next)\n  logger.ServeHTTP(rw, r)\n})\n\n//use it as native middleware:\nn := negroni.New()\nn.Use(negroniLoggerMiddleware)\nn.UseHandler(mux)\n```\n\nFull example [could be found here](https://github.com/MadAppGang/httplog/blob/main/examples/negroni/main.go).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMadAppGang%2Fhttplog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMadAppGang%2Fhttplog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMadAppGang%2Fhttplog/lists"}