Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tracing an HTTP request in Go in a one structured log line

I have learned you can "decorate" the HTTP transport so that you can details of the request, however I can't quite figure out how you log the URL in the same line.

https://play.golang.org/p/g-ypQN9ceGa

results in

  INFO[0000] Client request            dns_start_ms=0 first_byte_ms=590 response_code=200 total_ms=590 url=
  INFO[0000] 200

I'm perpetually confused if I should be using https://golang.org/pkg/context/#WithValue to pass around the context in a struct, especially in light where https://blog.golang.org/context-and-structs concludes with pass context.Context in as an argument.

like image 497
hendry Avatar asked Apr 18 '21 01:04

hendry


People also ask

What is http tracing in go?

In Go 1.7 we introduced HTTP tracing, a facility to gather fine-grained information throughout the lifecycle of an HTTP client request. Support for HTTP tracing is provided by the net/http/httptrace package. The collected information can be used for debugging latency issues, service monitoring, writing adaptive systems, and more.

How to make HTTP requests with go?

The first step in making an HTTP request with Go is to import the net/http package from the standard library. This package provides us with all the utilities we need to make HTTP requests with ease. We can import the net/http package and other packages we will need by adding the following lines of code to a main.go file that we create:

How do I enable http tracing with HTTP hooks?

The httptrace package provides a number of hooks to gather information during an HTTP round trip about a variety of events. These events include: You can enable HTTP tracing by putting an *httptrace.ClientTrace containing hook functions into a request’s context.Context .

What is the scope of the tracing?

The tracing is scoped to the request’s context and users should put a *httptrace.ClientTrace to the request context before they start a request.


Video Answer


2 Answers

Go through the behaviour of how the request is constructed in request.go from net/http. You see that the RequestURI field is never set there. Quoting from same reference,

Usually the URL field should be used instead.
It is an error to set this field in an HTTP client request

So, I would suggest you to use request.URL instead.
It is a parsed from the request uri. It should have the data you need.

You can construct the output as following:

f := log.Fields{
    "url": fmt.Sprintf("%s %s%s", r.Method, r.URL.Host, r.URL.Path),
}

Also, in my experience, it is far more easier to use context.WithValue and pass the context as an argument.

like image 168
advay rajhansa Avatar answered Oct 24 '22 12:10

advay rajhansa


Replace r.RequestURI by r.URL.String() in your code to log the full, valid URL (https://golang.org/pkg/net/url/#URL.String). RequestURI is empty on the client side (https://golang.org/pkg/net/http/#Request), as the output from your code is showing.

I don't see how context.Context relates to your question, but I believe https://blog.golang.org/context-and-structs is considered "best practice".

like image 40
Lars Christian Jensen Avatar answered Oct 24 '22 14:10

Lars Christian Jensen