feat(oohelperd): log messages at info level (#896)
We're using a request-specific logger where we also print the ID of the request. This design helps to observe logs produced by concurrent requests. Part of https://github.com/ooni/probe/issues/2183 While there, fix https://github.com/ooni/probe/issues/2241
This commit is contained in:
parent
8ca7645026
commit
4241ee4bc1
|
@ -9,6 +9,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/measurexlite"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
"github.com/ooni/probe-cli/v3/internal/tracex"
|
"github.com/ooni/probe-cli/v3/internal/tracex"
|
||||||
|
@ -26,8 +27,11 @@ type dnsConfig struct {
|
||||||
// Domain is the MANDATORY domain to resolve.
|
// Domain is the MANDATORY domain to resolve.
|
||||||
Domain string
|
Domain string
|
||||||
|
|
||||||
|
// Logger is the MANDATORY logger to use.
|
||||||
|
Logger model.Logger
|
||||||
|
|
||||||
// NewResolver is the MANDATORY factory to create a new resolver.
|
// NewResolver is the MANDATORY factory to create a new resolver.
|
||||||
NewResolver func() model.Resolver
|
NewResolver func(model.Logger) model.Resolver
|
||||||
|
|
||||||
// Out is the channel where we publish the results.
|
// Out is the channel where we publish the results.
|
||||||
Out chan ctrlDNSResult
|
Out chan ctrlDNSResult
|
||||||
|
@ -42,9 +46,11 @@ func dnsDo(ctx context.Context, config *dnsConfig) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
defer config.Wg.Done()
|
defer config.Wg.Done()
|
||||||
reso := config.NewResolver()
|
reso := config.NewResolver(config.Logger)
|
||||||
defer reso.CloseIdleConnections()
|
defer reso.CloseIdleConnections()
|
||||||
|
ol := measurexlite.NewOperationLogger(config.Logger, "DNSLookup %s", config.Domain)
|
||||||
addrs, err := reso.LookupHost(ctx, config.Domain)
|
addrs, err := reso.LookupHost(ctx, config.Domain)
|
||||||
|
ol.Stop(err)
|
||||||
if addrs == nil {
|
if addrs == nil {
|
||||||
addrs = []string{} // fix: the old test helper did that
|
addrs = []string{} // fix: the old test helper did that
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,8 @@ func TestDNSDo(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
config := &dnsConfig{
|
config := &dnsConfig{
|
||||||
Domain: "antani.ooni.org",
|
Domain: "antani.ooni.org",
|
||||||
NewResolver: func() model.Resolver {
|
Logger: model.DiscardLogger,
|
||||||
|
NewResolver: func(model.Logger) model.Resolver {
|
||||||
return &mocks.Resolver{
|
return &mocks.Resolver{
|
||||||
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
|
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
|
||||||
return nil, netxlite.ErrOODNSNoSuchHost
|
return nil, netxlite.ErrOODNSNoSuchHost
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/atomicx"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
"github.com/ooni/probe-cli/v3/internal/runtimex"
|
"github.com/ooni/probe-cli/v3/internal/runtimex"
|
||||||
|
@ -18,20 +19,26 @@ import (
|
||||||
|
|
||||||
// handler implements the Web Connectivity test helper HTTP API.
|
// handler implements the Web Connectivity test helper HTTP API.
|
||||||
type handler struct {
|
type handler struct {
|
||||||
|
// BaseLogger is the MANDATORY logger to use.
|
||||||
|
BaseLogger model.Logger
|
||||||
|
|
||||||
|
// Indexer is the MANDATORY atomic integer used to assign an index to requests.
|
||||||
|
Indexer *atomicx.Int64
|
||||||
|
|
||||||
// MaxAcceptableBody is the MANDATORY maximum acceptable response body.
|
// MaxAcceptableBody is the MANDATORY maximum acceptable response body.
|
||||||
MaxAcceptableBody int64
|
MaxAcceptableBody int64
|
||||||
|
|
||||||
// NewClient is the MANDATORY factory to create a new HTTPClient.
|
// NewClient is the MANDATORY factory to create a new HTTPClient.
|
||||||
NewClient func() model.HTTPClient
|
NewClient func(model.Logger) model.HTTPClient
|
||||||
|
|
||||||
// NewDialer is the MANDATORY factory to create a new Dialer.
|
// NewDialer is the MANDATORY factory to create a new Dialer.
|
||||||
NewDialer func() model.Dialer
|
NewDialer func(model.Logger) model.Dialer
|
||||||
|
|
||||||
// NewResolver is the MANDATORY factory for creating a new resolver.
|
// NewResolver is the MANDATORY factory for creating a new resolver.
|
||||||
NewResolver func() model.Resolver
|
NewResolver func(model.Logger) model.Resolver
|
||||||
|
|
||||||
// NewTLSHandshaker is the MANDATORY factory for creating a new TLS handshaker.
|
// NewTLSHandshaker is the MANDATORY factory for creating a new TLS handshaker.
|
||||||
NewTLSHandshaker func() model.TLSHandshaker
|
NewTLSHandshaker func(model.Logger) model.TLSHandshaker
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ http.Handler = &handler{}
|
var _ http.Handler = &handler{}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/atomicx"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
||||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
|
@ -53,17 +54,19 @@ const requestWithoutDomainName = `{
|
||||||
|
|
||||||
func TestHandlerWorkingAsIntended(t *testing.T) {
|
func TestHandlerWorkingAsIntended(t *testing.T) {
|
||||||
handler := &handler{
|
handler := &handler{
|
||||||
|
BaseLogger: model.DiscardLogger,
|
||||||
|
Indexer: &atomicx.Int64{},
|
||||||
MaxAcceptableBody: 1 << 24,
|
MaxAcceptableBody: 1 << 24,
|
||||||
NewClient: func() model.HTTPClient {
|
NewClient: func(model.Logger) model.HTTPClient {
|
||||||
return http.DefaultClient
|
return http.DefaultClient
|
||||||
},
|
},
|
||||||
NewDialer: func() model.Dialer {
|
NewDialer: func(model.Logger) model.Dialer {
|
||||||
return netxlite.NewDialerWithStdlibResolver(model.DiscardLogger)
|
return netxlite.NewDialerWithStdlibResolver(model.DiscardLogger)
|
||||||
},
|
},
|
||||||
NewResolver: func() model.Resolver {
|
NewResolver: func(model.Logger) model.Resolver {
|
||||||
return netxlite.NewUnwrappedStdlibResolver()
|
return netxlite.NewUnwrappedStdlibResolver()
|
||||||
},
|
},
|
||||||
NewTLSHandshaker: func() model.TLSHandshaker {
|
NewTLSHandshaker: func(model.Logger) model.TLSHandshaker {
|
||||||
return netxlite.NewTLSHandshakerStdlib(model.DiscardLogger)
|
return netxlite.NewTLSHandshakerStdlib(model.DiscardLogger)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,14 @@ type httpConfig struct {
|
||||||
// Headers is OPTIONAL and contains the request headers we should set.
|
// Headers is OPTIONAL and contains the request headers we should set.
|
||||||
Headers map[string][]string
|
Headers map[string][]string
|
||||||
|
|
||||||
|
// Logger is the MANDATORY logger to use.
|
||||||
|
Logger model.Logger
|
||||||
|
|
||||||
// MaxAcceptableBody is MANDATORY and specifies the maximum acceptable body size.
|
// MaxAcceptableBody is MANDATORY and specifies the maximum acceptable body size.
|
||||||
MaxAcceptableBody int64
|
MaxAcceptableBody int64
|
||||||
|
|
||||||
// NewClient is the MANDATORY factory to create a new client.
|
// NewClient is the MANDATORY factory to create a new client.
|
||||||
NewClient func() model.HTTPClient
|
NewClient func(model.Logger) model.HTTPClient
|
||||||
|
|
||||||
// Out is the MANDATORY channel where we'll post results.
|
// Out is the MANDATORY channel where we'll post results.
|
||||||
Out chan ctrlHTTPResponse
|
Out chan ctrlHTTPResponse
|
||||||
|
@ -48,6 +51,7 @@ type httpConfig struct {
|
||||||
|
|
||||||
// httpDo performs the HTTP check.
|
// httpDo performs the HTTP check.
|
||||||
func httpDo(ctx context.Context, config *httpConfig) {
|
func httpDo(ctx context.Context, config *httpConfig) {
|
||||||
|
ol := measurexlite.NewOperationLogger(config.Logger, "GET %s", config.URL)
|
||||||
const timeout = 15 * time.Second
|
const timeout = 15 * time.Second
|
||||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -62,6 +66,7 @@ func httpDo(ctx context.Context, config *httpConfig) {
|
||||||
Headers: map[string]string{},
|
Headers: map[string]string{},
|
||||||
StatusCode: -1,
|
StatusCode: -1,
|
||||||
}
|
}
|
||||||
|
ol.Stop(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// The original test helper failed with extra headers while here
|
// The original test helper failed with extra headers while here
|
||||||
|
@ -74,7 +79,7 @@ func httpDo(ctx context.Context, config *httpConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clnt := config.NewClient()
|
clnt := config.NewClient(config.Logger)
|
||||||
defer clnt.CloseIdleConnections()
|
defer clnt.CloseIdleConnections()
|
||||||
resp, err := clnt.Do(req)
|
resp, err := clnt.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -86,6 +91,7 @@ func httpDo(ctx context.Context, config *httpConfig) {
|
||||||
Headers: map[string]string{},
|
Headers: map[string]string{},
|
||||||
StatusCode: -1,
|
StatusCode: -1,
|
||||||
}
|
}
|
||||||
|
ol.Stop(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
@ -95,6 +101,7 @@ func httpDo(ctx context.Context, config *httpConfig) {
|
||||||
}
|
}
|
||||||
reader := &io.LimitedReader{R: resp.Body, N: config.MaxAcceptableBody}
|
reader := &io.LimitedReader{R: resp.Body, N: config.MaxAcceptableBody}
|
||||||
data, err := netxlite.ReadAllContext(ctx, reader)
|
data, err := netxlite.ReadAllContext(ctx, reader)
|
||||||
|
ol.Stop(err)
|
||||||
config.Out <- ctrlHTTPResponse{
|
config.Out <- ctrlHTTPResponse{
|
||||||
BodyLength: int64(len(data)),
|
BodyLength: int64(len(data)),
|
||||||
Failure: httpMapFailure(err),
|
Failure: httpMapFailure(err),
|
||||||
|
|
|
@ -20,8 +20,9 @@ func TestHTTPDoWithInvalidURL(t *testing.T) {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go httpDo(ctx, &httpConfig{
|
go httpDo(ctx, &httpConfig{
|
||||||
Headers: nil,
|
Headers: nil,
|
||||||
|
Logger: model.DiscardLogger,
|
||||||
MaxAcceptableBody: 1 << 24,
|
MaxAcceptableBody: 1 << 24,
|
||||||
NewClient: func() model.HTTPClient {
|
NewClient: func(model.Logger) model.HTTPClient {
|
||||||
return http.DefaultClient
|
return http.DefaultClient
|
||||||
},
|
},
|
||||||
Out: httpch,
|
Out: httpch,
|
||||||
|
@ -44,8 +45,9 @@ func TestHTTPDoWithHTTPTransportFailure(t *testing.T) {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go httpDo(ctx, &httpConfig{
|
go httpDo(ctx, &httpConfig{
|
||||||
Headers: nil,
|
Headers: nil,
|
||||||
|
Logger: model.DiscardLogger,
|
||||||
MaxAcceptableBody: 1 << 24,
|
MaxAcceptableBody: 1 << 24,
|
||||||
NewClient: func() model.HTTPClient {
|
NewClient: func(model.Logger) model.HTTPClient {
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Transport: &mocks.HTTPTransport{
|
Transport: &mocks.HTTPTransport{
|
||||||
MockRoundTrip: func(req *http.Request) (*http.Response, error) {
|
MockRoundTrip: func(req *http.Request) (*http.Response, error) {
|
||||||
|
|
41
internal/cmd/oohelperd/logging.go
Normal file
41
internal/cmd/oohelperd/logging.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/ooni/probe-cli/v3/internal/model"
|
||||||
|
|
||||||
|
// indexLogger is a logger with an index.
|
||||||
|
type indexLogger struct {
|
||||||
|
indexstr string
|
||||||
|
logger model.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ model.Logger = &indexLogger{}
|
||||||
|
|
||||||
|
// Debug implements DebugLogger.Debug
|
||||||
|
func (p *indexLogger) Debug(msg string) {
|
||||||
|
p.logger.Debug(p.indexstr + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf implements DebugLogger.Debugf
|
||||||
|
func (p *indexLogger) Debugf(format string, v ...interface{}) {
|
||||||
|
p.logger.Debugf(p.indexstr+format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info implements InfoLogger.Info
|
||||||
|
func (p *indexLogger) Info(msg string) {
|
||||||
|
p.logger.Info(p.indexstr + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infov implements InfoLogger.Infov
|
||||||
|
func (p *indexLogger) Infof(format string, v ...interface{}) {
|
||||||
|
p.logger.Infof(p.indexstr+format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn implements Logger.Warn
|
||||||
|
func (p *indexLogger) Warn(msg string) {
|
||||||
|
p.logger.Warn(p.indexstr + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf implements Logger.Warnf
|
||||||
|
func (p *indexLogger) Warnf(format string, v ...interface{}) {
|
||||||
|
p.logger.Warnf(p.indexstr+format, v...)
|
||||||
|
}
|
105
internal/cmd/oohelperd/logging_test.go
Normal file
105
internal/cmd/oohelperd/logging_test.go
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIndexLogger(t *testing.T) {
|
||||||
|
t.Run("Debug", func(t *testing.T) {
|
||||||
|
expected := "<0>antani"
|
||||||
|
base := &mocks.Logger{
|
||||||
|
MockDebug: func(message string) {
|
||||||
|
if message != expected {
|
||||||
|
t.Fatal("unexpected message")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
logger := &indexLogger{
|
||||||
|
indexstr: "<0>",
|
||||||
|
logger: base,
|
||||||
|
}
|
||||||
|
logger.Debug("antani")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Info", func(t *testing.T) {
|
||||||
|
expected := "<0>antani"
|
||||||
|
base := &mocks.Logger{
|
||||||
|
MockInfo: func(message string) {
|
||||||
|
if message != expected {
|
||||||
|
t.Fatal("unexpected message")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
logger := &indexLogger{
|
||||||
|
indexstr: "<0>",
|
||||||
|
logger: base,
|
||||||
|
}
|
||||||
|
logger.Info("antani")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Warn", func(t *testing.T) {
|
||||||
|
expected := "<0>antani"
|
||||||
|
base := &mocks.Logger{
|
||||||
|
MockWarn: func(message string) {
|
||||||
|
if message != expected {
|
||||||
|
t.Fatal("unexpected message")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
logger := &indexLogger{
|
||||||
|
indexstr: "<0>",
|
||||||
|
logger: base,
|
||||||
|
}
|
||||||
|
logger.Warn("antani")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Debugf", func(t *testing.T) {
|
||||||
|
expected := "<0>antani%d"
|
||||||
|
base := &mocks.Logger{
|
||||||
|
MockDebugf: func(format string, v ...any) {
|
||||||
|
if format != expected {
|
||||||
|
t.Fatal("unexpected message")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
logger := &indexLogger{
|
||||||
|
indexstr: "<0>",
|
||||||
|
logger: base,
|
||||||
|
}
|
||||||
|
logger.Debugf("antani%d", 11)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Infof", func(t *testing.T) {
|
||||||
|
expected := "<0>antani%d"
|
||||||
|
base := &mocks.Logger{
|
||||||
|
MockInfof: func(format string, v ...any) {
|
||||||
|
if format != expected {
|
||||||
|
t.Fatal("unexpected message")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
logger := &indexLogger{
|
||||||
|
indexstr: "<0>",
|
||||||
|
logger: base,
|
||||||
|
}
|
||||||
|
logger.Infof("antani%d", 11)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Warnf", func(t *testing.T) {
|
||||||
|
expected := "<0>antani%d"
|
||||||
|
base := &mocks.Logger{
|
||||||
|
MockWarnf: func(format string, v ...any) {
|
||||||
|
if format != expected {
|
||||||
|
t.Fatal("unexpected message")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
logger := &indexLogger{
|
||||||
|
indexstr: "<0>",
|
||||||
|
logger: base,
|
||||||
|
}
|
||||||
|
logger.Warnf("antani%d", 11)
|
||||||
|
})
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
|
"github.com/ooni/probe-cli/v3/internal/atomicx"
|
||||||
"github.com/ooni/probe-cli/v3/internal/model"
|
"github.com/ooni/probe-cli/v3/internal/model"
|
||||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||||
"github.com/ooni/probe-cli/v3/internal/runtimex"
|
"github.com/ooni/probe-cli/v3/internal/runtimex"
|
||||||
|
@ -29,11 +30,11 @@ func init() {
|
||||||
srvCtx, srvCancel = context.WithCancel(context.Background())
|
srvCtx, srvCancel = context.WithCancel(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
func newResolver() model.Resolver {
|
func newResolver(logger model.Logger) model.Resolver {
|
||||||
// Implementation note: pin to a specific resolver so we don't depend upon the
|
// Implementation note: pin to a specific resolver so we don't depend upon the
|
||||||
// default resolver configured by the box. Also, use an encrypted transport thus
|
// default resolver configured by the box. Also, use an encrypted transport thus
|
||||||
// we're less vulnerable to any policy implemented by the box's provider.
|
// we're less vulnerable to any policy implemented by the box's provider.
|
||||||
resolver := netxlite.NewParallelDNSOverHTTPSResolver(log.Log, "https://8.8.8.8/dns-query")
|
resolver := netxlite.NewParallelDNSOverHTTPSResolver(logger, "https://dns.google/dns-query")
|
||||||
return resolver
|
return resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,16 +55,18 @@ func main() {
|
||||||
defer srvCancel()
|
defer srvCancel()
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle("/", &handler{
|
mux.Handle("/", &handler{
|
||||||
|
BaseLogger: log.Log,
|
||||||
|
Indexer: &atomicx.Int64{},
|
||||||
MaxAcceptableBody: maxAcceptableBody,
|
MaxAcceptableBody: maxAcceptableBody,
|
||||||
NewClient: func() model.HTTPClient {
|
NewClient: func(logger model.Logger) model.HTTPClient {
|
||||||
return netxlite.NewHTTPClientWithResolver(log.Log, newResolver())
|
return netxlite.NewHTTPClientWithResolver(logger, newResolver(logger))
|
||||||
},
|
},
|
||||||
NewDialer: func() model.Dialer {
|
NewDialer: func(logger model.Logger) model.Dialer {
|
||||||
return netxlite.NewDialerWithResolver(log.Log, newResolver())
|
return netxlite.NewDialerWithResolver(logger, newResolver(logger))
|
||||||
},
|
},
|
||||||
NewResolver: newResolver,
|
NewResolver: newResolver,
|
||||||
NewTLSHandshaker: func() model.TLSHandshaker {
|
NewTLSHandshaker: func(logger model.Logger) model.TLSHandshaker {
|
||||||
return netxlite.NewTLSHandshakerStdlib(log.Log)
|
return netxlite.NewTLSHandshakerStdlib(logger)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
srv := &http.Server{Addr: *endpoint, Handler: mux}
|
srv := &http.Server{Addr: *endpoint, Handler: mux}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -24,9 +25,16 @@ type (
|
||||||
// measure performs the measurement described by the request and
|
// measure performs the measurement described by the request and
|
||||||
// returns the corresponding response or an error.
|
// returns the corresponding response or an error.
|
||||||
func measure(ctx context.Context, config *handler, creq *ctrlRequest) (*ctrlResponse, error) {
|
func measure(ctx context.Context, config *handler, creq *ctrlRequest) (*ctrlResponse, error) {
|
||||||
|
// create indexed logger
|
||||||
|
logger := &indexLogger{
|
||||||
|
indexstr: fmt.Sprintf("<#%d> ", config.Indexer.Add(1)),
|
||||||
|
logger: config.BaseLogger,
|
||||||
|
}
|
||||||
|
|
||||||
// parse input for correctness
|
// parse input for correctness
|
||||||
URL, err := url.Parse(creq.HTTPRequest)
|
URL, err := url.Parse(creq.HTTPRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Warnf("cannot parse URL: %s", err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
|
@ -37,6 +45,7 @@ func measure(ctx context.Context, config *handler, creq *ctrlRequest) (*ctrlResp
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go dnsDo(ctx, &dnsConfig{
|
go dnsDo(ctx, &dnsConfig{
|
||||||
Domain: URL.Hostname(),
|
Domain: URL.Hostname(),
|
||||||
|
Logger: logger,
|
||||||
NewResolver: config.NewResolver,
|
NewResolver: config.NewResolver,
|
||||||
Out: dnsch,
|
Out: dnsch,
|
||||||
Wg: wg,
|
Wg: wg,
|
||||||
|
@ -78,6 +87,7 @@ func measure(ctx context.Context, config *handler, creq *ctrlRequest) (*ctrlResp
|
||||||
Address: endpoint.Addr,
|
Address: endpoint.Addr,
|
||||||
EnableTLS: endpoint.TLS,
|
EnableTLS: endpoint.TLS,
|
||||||
Endpoint: endpoint.Epnt,
|
Endpoint: endpoint.Epnt,
|
||||||
|
Logger: logger,
|
||||||
NewDialer: config.NewDialer,
|
NewDialer: config.NewDialer,
|
||||||
NewTSLHandshaker: config.NewTLSHandshaker,
|
NewTSLHandshaker: config.NewTLSHandshaker,
|
||||||
URLHostname: URL.Hostname(),
|
URLHostname: URL.Hostname(),
|
||||||
|
@ -91,6 +101,7 @@ func measure(ctx context.Context, config *handler, creq *ctrlRequest) (*ctrlResp
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go httpDo(ctx, &httpConfig{
|
go httpDo(ctx, &httpConfig{
|
||||||
Headers: creq.HTTPRequestHeaders,
|
Headers: creq.HTTPRequestHeaders,
|
||||||
|
Logger: logger,
|
||||||
MaxAcceptableBody: config.MaxAcceptableBody,
|
MaxAcceptableBody: config.MaxAcceptableBody,
|
||||||
NewClient: config.NewClient,
|
NewClient: config.NewClient,
|
||||||
Out: httpch,
|
Out: httpch,
|
||||||
|
|
|
@ -47,11 +47,14 @@ type tcpConfig struct {
|
||||||
// Endpoint is the MANDATORY endpoint to connect to.
|
// Endpoint is the MANDATORY endpoint to connect to.
|
||||||
Endpoint string
|
Endpoint string
|
||||||
|
|
||||||
|
// Logger is the MANDATORY logger to use.
|
||||||
|
Logger model.Logger
|
||||||
|
|
||||||
// NewDialer is the MANDATORY factory for creating a new dialer.
|
// NewDialer is the MANDATORY factory for creating a new dialer.
|
||||||
NewDialer func() model.Dialer
|
NewDialer func(model.Logger) model.Dialer
|
||||||
|
|
||||||
// NewTSLHandshaker is the MANDATORY factory for creating a new handshaker.
|
// NewTSLHandshaker is the MANDATORY factory for creating a new handshaker.
|
||||||
NewTSLHandshaker func() model.TLSHandshaker
|
NewTSLHandshaker func(model.Logger) model.TLSHandshaker
|
||||||
|
|
||||||
// Out is the MANDATORY where we'll post the TCP measurement results.
|
// Out is the MANDATORY where we'll post the TCP measurement results.
|
||||||
Out chan *tcpResultPair
|
Out chan *tcpResultPair
|
||||||
|
@ -78,13 +81,21 @@ func tcpDo(ctx context.Context, config *tcpConfig) {
|
||||||
defer func() {
|
defer func() {
|
||||||
config.Out <- out
|
config.Out <- out
|
||||||
}()
|
}()
|
||||||
dialer := config.NewDialer()
|
ol := measurexlite.NewOperationLogger(
|
||||||
|
config.Logger,
|
||||||
|
"TCPConnect %s EnableTLS=%v SNI=%s",
|
||||||
|
config.Endpoint,
|
||||||
|
config.EnableTLS,
|
||||||
|
config.URLHostname,
|
||||||
|
)
|
||||||
|
dialer := config.NewDialer(config.Logger)
|
||||||
defer dialer.CloseIdleConnections()
|
defer dialer.CloseIdleConnections()
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", config.Endpoint)
|
conn, err := dialer.DialContext(ctx, "tcp", config.Endpoint)
|
||||||
out.TCP.Failure = tcpMapFailure(newfailure(err))
|
out.TCP.Failure = tcpMapFailure(newfailure(err))
|
||||||
out.TCP.Status = err == nil
|
out.TCP.Status = err == nil
|
||||||
defer measurexlite.MaybeClose(conn)
|
defer measurexlite.MaybeClose(conn)
|
||||||
if err != nil || !config.EnableTLS {
|
if err != nil || !config.EnableTLS {
|
||||||
|
ol.Stop(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
|
@ -92,8 +103,9 @@ func tcpDo(ctx context.Context, config *tcpConfig) {
|
||||||
RootCAs: netxlite.NewDefaultCertPool(),
|
RootCAs: netxlite.NewDefaultCertPool(),
|
||||||
ServerName: config.URLHostname,
|
ServerName: config.URLHostname,
|
||||||
}
|
}
|
||||||
thx := config.NewTSLHandshaker()
|
thx := config.NewTSLHandshaker(config.Logger)
|
||||||
tlsConn, _, err := thx.Handshake(ctx, conn, tlsConfig)
|
tlsConn, _, err := thx.Handshake(ctx, conn, tlsConfig)
|
||||||
|
ol.Stop(err)
|
||||||
out.TLS = &ctrlTLSResult{
|
out.TLS = &ctrlTLSResult{
|
||||||
ServerName: config.URLHostname,
|
ServerName: config.URLHostname,
|
||||||
Status: err == nil,
|
Status: err == nil,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user