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/handlerandgithub.com/gorilla/muxpackages using thego getcommand, as follows:
$ go get github.com/gorilla/handlers
$ go get github.com/gorilla/mux- Create http-server-request-logging.goand 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.goHow 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/fooThis 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 wrappedGetRequestHandlerwith 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.login 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 wrappedGetRequestHandlerwith 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/postin a file named/hello/{name}in Apache Common Log Format.
- Using router.Handle("/hello/{name}", handlers.CombinedLoggingHandler(logFile, PathVariableHandler)).Methods("GET"), we wrappedGetRequestHandlerwith 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.login Apache Combined Log Format.
 
                                             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
     
         
                 
                 
                 
                 
                 
                 
                 
                 
                 
        