2017-11-25 12:36:03 +00:00
|
|
|
package collector
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/json"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/mitchellh/hashstructure"
|
2022-11-21 17:36:05 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
2023-02-03 14:24:05 +00:00
|
|
|
"github.com/traefik/traefik/v3/pkg/config/static"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/redactor"
|
|
|
|
"github.com/traefik/traefik/v3/pkg/version"
|
2017-11-25 12:36:03 +00:00
|
|
|
)
|
|
|
|
|
2022-05-03 13:54:08 +00:00
|
|
|
// collectorURL URL where the stats are sent.
|
2019-03-14 18:32:03 +00:00
|
|
|
const collectorURL = "https://collect.traefik.io/9vxmmkcdmalbdi635d4jgc5p5rx0h7h8"
|
2017-11-25 12:36:03 +00:00
|
|
|
|
2020-05-11 10:06:07 +00:00
|
|
|
// Collected data.
|
2023-02-23 14:06:05 +00:00
|
|
|
//
|
|
|
|
//nolint:musttag // cannot be changed for historical reasons.
|
2017-11-25 12:36:03 +00:00
|
|
|
type data struct {
|
|
|
|
Version string
|
|
|
|
Codename string
|
|
|
|
BuildDate string
|
|
|
|
Configuration string
|
|
|
|
Hash string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Collect anonymous data.
|
2018-11-27 16:42:04 +00:00
|
|
|
func Collect(staticConfiguration *static.Configuration) error {
|
2022-05-03 13:54:08 +00:00
|
|
|
buf, err := createBody(staticConfiguration)
|
2017-11-25 12:36:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-05-03 13:54:08 +00:00
|
|
|
resp, err := makeHTTPClient().Post(collectorURL, "application/json; charset=utf-8", buf)
|
|
|
|
if resp != nil {
|
|
|
|
_ = resp.Body.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func createBody(staticConfiguration *static.Configuration) (*bytes.Buffer, error) {
|
|
|
|
anonConfig, err := redactor.Anonymize(staticConfiguration)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-11-21 17:36:05 +00:00
|
|
|
log.Debug().Msgf("Anonymous stats sent to %s: %s", collectorURL, anonConfig)
|
2017-11-25 12:36:03 +00:00
|
|
|
|
2018-11-27 16:42:04 +00:00
|
|
|
hashConf, err := hashstructure.Hash(staticConfiguration, nil)
|
2017-11-25 12:36:03 +00:00
|
|
|
if err != nil {
|
2022-05-03 13:54:08 +00:00
|
|
|
return nil, err
|
2017-11-25 12:36:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data := &data{
|
|
|
|
Version: version.Version,
|
|
|
|
Codename: version.Codename,
|
|
|
|
BuildDate: version.BuildDate,
|
|
|
|
Hash: strconv.FormatUint(hashConf, 10),
|
|
|
|
Configuration: base64.StdEncoding.EncodeToString([]byte(anonConfig)),
|
|
|
|
}
|
|
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
err = json.NewEncoder(buf).Encode(data)
|
|
|
|
if err != nil {
|
2022-05-03 13:54:08 +00:00
|
|
|
return nil, err
|
2017-11-25 12:36:03 +00:00
|
|
|
}
|
|
|
|
|
2022-05-03 13:54:08 +00:00
|
|
|
return buf, err
|
2017-11-25 12:36:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func makeHTTPClient() *http.Client {
|
|
|
|
dialer := &net.Dialer{
|
2019-03-18 10:30:07 +00:00
|
|
|
Timeout: 30 * time.Second,
|
2017-11-25 12:36:03 +00:00
|
|
|
KeepAlive: 30 * time.Second,
|
|
|
|
DualStack: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
transport := &http.Transport{
|
|
|
|
Proxy: http.ProxyFromEnvironment,
|
|
|
|
DialContext: dialer.DialContext,
|
|
|
|
IdleConnTimeout: 90 * time.Second,
|
|
|
|
TLSHandshakeTimeout: 10 * time.Second,
|
|
|
|
ExpectContinueTimeout: 1 * time.Second,
|
|
|
|
}
|
|
|
|
|
|
|
|
return &http.Client{Transport: transport}
|
|
|
|
}
|