Logging HTTP requests
Logging HTTP requests is always useful when troubleshooting a web application, so it’s a good idea to log a request/response with a proper message and logging level. Go provides the log
package, which can help us to implement logging in an application. However, in this recipe we will be using Gorilla logging handlers to implement it because the library offers more features such as logging in Apache Combined Log Format and Apache Common Log Format, which are not yet supported by the Go log
package.
Getting Ready…
As we have already created an HTTP server and defined routes using Gorilla Mux in our previous recipe, we will update it to incorporate Gorilla logging handlers.
How to do it…
Let's implement logging using Gorilla handlers. Perform the following steps:
- Install the
github.com/gorilla/handler
andgithub.com/gorilla/mux
packages using thego get
command, as follows:
$ go get github.com/gorilla/handlers
$ go get github.com/gorilla/mux
- Create
http-server-request-logging.go
and copy the following content:
package main import ( "net/http" "os" "github.com/gorilla/handlers" "github.com/gorilla/mux" ) const ( CONN_HOST = "localhost" CONN_PORT = "8080" ) var GetRequestHandler = http.HandlerFunc ( func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World!")) } ) var PostRequestHandler = http.HandlerFunc ( func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("It's a Post Request!")) } ) var PathVariableHandler = http.HandlerFunc ( func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) name := vars["name"] w.Write([]byte("Hi " + name)) } ) func main() { router := mux.NewRouter() router.Handle("/", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(GetRequestHandler))).Methods("GET") logFile, err := os.OpenFile("server.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatal("error starting http server : ", err) return } router.Handle("/post", handlers.LoggingHandler(logFile, PostRequestHandler)).Methods("POST") router.Handle("/hello/{name}", handlers.CombinedLoggingHandler(logFile, PathVariableHandler)).Methods("GET") http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router) }
- Run the program, using the following command:
$ go run http-server-request-logging.go
How it works…
Once we run the program, the HTTP server will start locally listening on port 8080
.
Execute a GET
request from the command line, as follows:
$ curl -X GET -i http://localhost:8080/
This will log the request details in the server log in the Apache Common Log Format, as shown in the following screenshot:

We could also execute http://localhost:8080/hello/foo
from the command line, as follows:
$ curl -X GET -i http://localhost:8080/hello/foo
This will log the request details in the server.log
in the Apache Combined Log Format, as shown in the following screenshot:

Let's understand what we have done in this recipe:
- Firstly, we imported two additional packages, one is
os
, which we use to open a file. The other one isgithub.com/gorilla/handlers
, which we use to import logging handlers for logging HTTP requests, as follows:
import ( "net/http" "os" "github.com/gorilla/handlers" "github.com/gorilla/mux" )
- Next, we modified the
main()
method. Usingrouter.Handle("/", handlers.LoggingHandler(os.Stdout,
http.HandlerFunc(GetRequestHandler))).Methods("GET")
, we wrappedGetRequestHandler
with a Gorilla logging handler, and passed a standard output stream as a writer to it, which means we are simply asking to log every request with the URL path/
on the console in Apache Common Log Format. - Next, we create a new file named
server.log
in write-only mode, or we open it, if it already exists. If there is any error, then log it and exit with a status code of 1, as follows:
logFile, err := os.OpenFile("server.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatal("error starting http server : ", err) return }
- Using
router.Handle("/post", handlers.LoggingHandler(logFile, PostRequestHandler)).Methods("POST")
, we wrappedGetRequestHandler
with a Gorilla logging handler and passed the file as a writer to it, which means we are simply asking to log every request with the URL path/post
in a file named/hello/{name}
in Apache Common Log Format. - Using
router.Handle("/hello/{name}", handlers.CombinedLoggingHandler(logFile, PathVariableHandler)).Methods("GET")
, we wrappedGetRequestHandler
with a Gorilla logging handler and passed the file as a writer to it, which means we are simply asking to log every request with the URL path/hello/{name}
in a file namedserver.log
in Apache Combined Log Format.