пятница, 7 февраля 2020 г.

Трассировка HTTP запросов в Golang

Начиная с версии 1.7 в Go появилась трассировка HTTP, средство для сбора детальной информации в течение всего жизненного цикла запроса клиента HTTP. Поддержка трассировки HTTP обеспечивается
пакетом net/http/httptrace. Собранная информация может использоваться для устранения проблем с задержкой, мониторинга служб, написания адаптивных систем и многого другого.

HTTP события

В пакете httptrace есть несколько хуков для сбора информации о различных событиях во время выполнения HTTP-запроса. Эти события включают в себя:

  • Создание соединения
  • Повторное использование соединения
  • DNS-поиск
  • Запись запроса в сеть (на провод)
  • Чтение ответа

Отслеживание событий

Вы можете включить HTTP-трассировку, поместив *httptrace.ClientTrace, содержащий функции ловушек (hook functions), в context.Context запроса. Различные реализации http.RoundTripper сообщают о внутренних событиях, ища контекст *httptrace.ClientTrace и вызывая соответствующие функции ловушек.

Трассировка ограничена контекстом запроса, и пользователи должны поместить *httptrace.ClientTrace в контекст запроса, прежде чем они начнут запрос.

req, _ := http.NewRequest("GET", "http://example.com", nil)
trace := &httptrace.ClientTrace{
    DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
        fmt.Printf("DNS Info: %+v\n", dnsInfo)
    },
    GotConn: func(connInfo httptrace.GotConnInfo) {
        fmt.Printf("Got Conn: %+v\n", connInfo)
    },
}
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
if _, err := http.DefaultTransport.RoundTrip(req); err != nil {
    log.Fatal(err)
}

Во время передачи туда и обратно http.DefaultTransport будет вызывать каждый хук, когда происходит событие. Программа выше напечатает информацию DNS, как только поиск DNS будет завершен. Он также будет печатать информацию о соединении, когда соединение установлено с хостом запроса.

Трассировка с http.Client

Механизм трассировки предназначен для отслеживания событий в жизненном цикле одного http.Transport.RoundTrip. Тем не менее, клиент может совершить несколько обращений для выполнения HTTP-запроса. Например, в случае перенаправления URL-адреса зарегистрированные хуки будут вызываться столько раз, сколько клиент выполняет перенаправления HTTP, делая несколько запросов. Пользователи несут ответственность за распознавание таких событий на уровне http.Client. Программа ниже идентифицирует текущий запрос, используя оболочку http.RoundTripper.

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httptrace"
)

// transport это http.RoundTripper 
// который отслеживает выполняемый запрос
// и реализуек хуки для сообщения HTTP событий отслеживания
type transport struct {
    current *http.Request
}

// RoundTrip оборачивает http.DefaultTransport.RoundTrip
// чтобы отслеживать текущий запрос.
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
    t.current = req
    return http.DefaultTransport.RoundTrip(req)
}

// GotConn печатает информацию о том 
// было ли соединение использовано ранее для текущего запроса
func (t *transport) GotConn(info httptrace.GotConnInfo) {
    fmt.Printf("Connection reused for %v? %v\n", t.current.URL, info.Reused)
}

func main() {
    t := &transport{}

    req, _ := http.NewRequest("GET", "https://google.com", nil)
    trace := &httptrace.ClientTrace{
        GotConn: t.GotConn,
    }
    req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))

    client := &http.Client{Transport: t}
    if _, err := client.Do(req); err != nil {
        log.Fatal(err)
    }
}

Программа выполнит перенаправление google.com на www.google.com и выведет:

Connection reused for https://google.com? false
Connection reused for https://www.google.com/? false

Transport в пакете net/http поддерживает трассировку запросов HTTP/1 и HTTP/2.

Если вы являетесь автором пользовательской реализации http.RoundTripper, вы можете поддержать трассировку, проверив контекст запроса для *httptest.ClientTrace и вызвав соответствующие хуки по мере возникновения событий.

Вывод

HTTP-трассировка является ценным дополнением к Go для тех, кто интересуется отладкой задержки HTTP-запросов и инструментами записи для сетевой отладки для исходящего трафика.


Читайте также:


Комментариев нет:

Отправить комментарий