logpolicy: log on dials, add knob to force HTTP/1 for log uploads
import (
"bytes"
"context"
+ "crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
+ "net"
+ "net/http"
"os"
"path/filepath"
"runtime"
+ "strconv"
+ "time"
"github.com/klauspost/compress/zstd"
"golang.org/x/crypto/ssh/terminal"
@@ -182,6 +187,7 @@ func New(collection string) *Policy {
}
return w
},
+ HTTPC: &http.Client{Transport: newLogtailTransport()},
}
filchBuf, filchErr := filch.New(filepath.Join(dir, version.CmdName()), filch.Options{})
@@ -220,3 +226,48 @@ func (p *Policy) Shutdown(ctx context.Context) error {
}
return nil
}
+
+// newLogtailTransport returns the HTTP Transport we use for uploading logs.
+func newLogtailTransport() *http.Transport {
+ // Start with a copy of http.DefaultTransport and tweak it a bit.
+ tr := http.DefaultTransport.(*http.Transport).Clone()
+
+ // We do our own zstd compression on uploads, and responses never contain any payload,
+ // so don't send "Accept-Encoding: gzip" to save a few bytes on the wire, since there
+ // will never be any body to decompress:
+ tr.DisableCompression = true
+
+ // Log whenever we dial:
+ tr.DialContext = func(ctx context.Context, netw, addr string) (net.Conn, error) {
+ nd := &net.Dialer{
+ Timeout: 30 * time.Second,
+ KeepAlive: 30 * time.Second,
+ DualStack: true,
+ }
+ t0 := time.Now()
+ c, err := nd.DialContext(ctx, netw, addr)
+ d := time.Since(t0).Round(time.Millisecond)
+ if err != nil {
+ log.Printf("logtail: dial %q failed: %v (in %v)", addr, err, d)
+ } else {
+ log.Printf("logtail: dialed %q in %v", addr, d)
+ }
+ return c, err
+ }
+
+ // We're contacting exactly 1 hostname, so the default's 100
+ // max idle conns is very high for our needs. Even 2 is
+ // probably double what we need:
+ tr.MaxIdleConns = 2
+
+ // Provide knob to force HTTP/1 for log uploads.
+ // TODO(bradfitz): remove this debug knob once we've decided
+ // to upload via HTTP/1 or HTTP/2 (probably HTTP/1). Or we might just enforce
+ // it server-side.
+ if h1, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_FORCE_H1_LOGS")); h1 {
+ tr.TLSClientConfig = nil // DefaultTransport's was already initialized w/ h2
+ tr.ForceAttemptHTTP2 = false
+ tr.TLSNextProto = map[string]func(authority string, c *tls.Conn) http.RoundTripper{}
+ }
+ return tr
+}
