mirror of
https://github.com/caddyserver/caddy.git
synced 2025-02-01 07:37:04 +08:00
Refactor diagnostics -> telemetry
This commit is contained in:
parent
7c868afd32
commit
52316952a5
4
caddy.go
4
caddy.go
|
@ -44,7 +44,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mholt/caddy/caddyfile"
|
"github.com/mholt/caddy/caddyfile"
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configurable application parameters
|
// Configurable application parameters
|
||||||
|
@ -617,7 +617,7 @@ func ValidateAndExecuteDirectives(cdyfile Input, inst *Instance, justValidate bo
|
||||||
return fmt.Errorf("error inspecting server blocks: %v", err)
|
return fmt.Errorf("error inspecting server blocks: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.Set("http_num_server_blocks", len(sblocks))
|
telemetry.Set("http_num_server_blocks", len(sblocks))
|
||||||
|
|
||||||
return executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate)
|
return executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"github.com/klauspost/cpuid"
|
"github.com/klauspost/cpuid"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddytls"
|
"github.com/mholt/caddy/caddytls"
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
"github.com/xenolf/lego/acme"
|
"github.com/xenolf/lego/acme"
|
||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
|
||||||
|
@ -52,7 +52,6 @@ func init() {
|
||||||
flag.StringVar(&caddytls.DefaultEmail, "email", "", "Default ACME CA account email address")
|
flag.StringVar(&caddytls.DefaultEmail, "email", "", "Default ACME CA account email address")
|
||||||
flag.DurationVar(&acme.HTTPClient.Timeout, "catimeout", acme.HTTPClient.Timeout, "Default ACME CA HTTP timeout")
|
flag.DurationVar(&acme.HTTPClient.Timeout, "catimeout", acme.HTTPClient.Timeout, "Default ACME CA HTTP timeout")
|
||||||
flag.StringVar(&logfile, "log", "", "Process log file")
|
flag.StringVar(&logfile, "log", "", "Process log file")
|
||||||
flag.BoolVar(&noDiag, "no-diagnostics", false, "Disable diagnostic reporting")
|
|
||||||
flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
|
flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
|
||||||
flag.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
|
flag.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
|
||||||
flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate")
|
flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate")
|
||||||
|
@ -89,9 +88,9 @@ func Run() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize diagnostics client
|
// initialize telemetry client
|
||||||
if !noDiag {
|
if enableTelemetry {
|
||||||
initDiagnostics()
|
initTelemetry()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for one-time actions
|
// Check for one-time actions
|
||||||
|
@ -150,13 +149,13 @@ func Run() {
|
||||||
// Execute instantiation events
|
// Execute instantiation events
|
||||||
caddy.EmitEvent(caddy.InstanceStartupEvent, instance)
|
caddy.EmitEvent(caddy.InstanceStartupEvent, instance)
|
||||||
|
|
||||||
// Begin diagnostics (these are no-ops if diagnostics disabled)
|
// Begin telemetry (these are no-ops if telemetry disabled)
|
||||||
diagnostics.Set("caddy_version", appVersion)
|
telemetry.Set("caddy_version", appVersion)
|
||||||
diagnostics.Set("num_listeners", len(instance.Servers()))
|
telemetry.Set("num_listeners", len(instance.Servers()))
|
||||||
diagnostics.Set("server_type", serverType)
|
telemetry.Set("server_type", serverType)
|
||||||
diagnostics.Set("os", runtime.GOOS)
|
telemetry.Set("os", runtime.GOOS)
|
||||||
diagnostics.Set("arch", runtime.GOARCH)
|
telemetry.Set("arch", runtime.GOARCH)
|
||||||
diagnostics.Set("cpu", struct {
|
telemetry.Set("cpu", struct {
|
||||||
BrandName string `json:"brand_name,omitempty"`
|
BrandName string `json:"brand_name,omitempty"`
|
||||||
NumLogical int `json:"num_logical,omitempty"`
|
NumLogical int `json:"num_logical,omitempty"`
|
||||||
AESNI bool `json:"aes_ni,omitempty"`
|
AESNI bool `json:"aes_ni,omitempty"`
|
||||||
|
@ -165,7 +164,7 @@ func Run() {
|
||||||
NumLogical: runtime.NumCPU(),
|
NumLogical: runtime.NumCPU(),
|
||||||
AESNI: cpuid.CPU.AesNi(),
|
AESNI: cpuid.CPU.AesNi(),
|
||||||
})
|
})
|
||||||
diagnostics.StartEmitting()
|
telemetry.StartEmitting()
|
||||||
|
|
||||||
// Twiddle your thumbs
|
// Twiddle your thumbs
|
||||||
instance.Wait()
|
instance.Wait()
|
||||||
|
@ -290,8 +289,8 @@ func setCPU(cpu string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initDiagnostics initializes the diagnostics engine.
|
// initTelemetry initializes the telemetry engine.
|
||||||
func initDiagnostics() {
|
func initTelemetry() {
|
||||||
uuidFilename := filepath.Join(caddy.AssetsPath(), "uuid")
|
uuidFilename := filepath.Join(caddy.AssetsPath(), "uuid")
|
||||||
|
|
||||||
newUUID := func() uuid.UUID {
|
newUUID := func() uuid.UUID {
|
||||||
|
@ -327,7 +326,7 @@ func initDiagnostics() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.Init(id)
|
telemetry.Init(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const appName = "Caddy"
|
const appName = "Caddy"
|
||||||
|
@ -342,7 +341,6 @@ var (
|
||||||
version bool
|
version bool
|
||||||
plugins bool
|
plugins bool
|
||||||
validate bool
|
validate bool
|
||||||
noDiag bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Build information obtained with the help of -ldflags
|
// Build information obtained with the help of -ldflags
|
||||||
|
@ -356,4 +354,6 @@ var (
|
||||||
gitCommit string // git rev-parse HEAD
|
gitCommit string // git rev-parse HEAD
|
||||||
gitShortStat string // git diff-index --shortstat
|
gitShortStat string // git diff-index --shortstat
|
||||||
gitFilesModified string // git diff-index --name-only HEAD
|
gitFilesModified string // git diff-index --name-only HEAD
|
||||||
|
|
||||||
|
enableTelemetry = true
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parse parses the input just enough to group tokens, in
|
// Parse parses the input just enough to group tokens, in
|
||||||
|
@ -371,7 +371,7 @@ func (p *parser) directive() error {
|
||||||
|
|
||||||
// The directive itself is appended as a relevant token
|
// The directive itself is appended as a relevant token
|
||||||
p.block.Tokens[dir] = append(p.block.Tokens[dir], p.tokens[p.cursor])
|
p.block.Tokens[dir] = append(p.block.Tokens[dir], p.tokens[p.cursor])
|
||||||
diagnostics.AppendUnique("directives", dir)
|
telemetry.AppendUnique("directives", dir)
|
||||||
|
|
||||||
for p.Next() {
|
for p.Next() {
|
||||||
if p.Val() == "{" {
|
if p.Val() == "{" {
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// tlsHandler is a http.Handler that will inject a value
|
// tlsHandler is a http.Handler that will inject a value
|
||||||
|
@ -103,12 +103,12 @@ func (h *tlsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if checked {
|
if checked {
|
||||||
r = r.WithContext(context.WithValue(r.Context(), MitmCtxKey, mitm))
|
r = r.WithContext(context.WithValue(r.Context(), MitmCtxKey, mitm))
|
||||||
if mitm {
|
if mitm {
|
||||||
go diagnostics.AppendUnique("http_mitm", "likely")
|
go telemetry.AppendUnique("http_mitm", "likely")
|
||||||
} else {
|
} else {
|
||||||
go diagnostics.AppendUnique("http_mitm", "unlikely")
|
go telemetry.AppendUnique("http_mitm", "unlikely")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
go diagnostics.AppendUnique("http_mitm", "unknown")
|
go telemetry.AppendUnique("http_mitm", "unknown")
|
||||||
}
|
}
|
||||||
|
|
||||||
if mitm && h.closeOnMITM {
|
if mitm && h.closeOnMITM {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/mholt/caddy/caddyfile"
|
"github.com/mholt/caddy/caddyfile"
|
||||||
"github.com/mholt/caddy/caddyhttp/staticfiles"
|
"github.com/mholt/caddy/caddyhttp/staticfiles"
|
||||||
"github.com/mholt/caddy/caddytls"
|
"github.com/mholt/caddy/caddytls"
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
const serverType = "http"
|
const serverType = "http"
|
||||||
|
@ -220,9 +220,9 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
|
||||||
|
|
||||||
var atLeastOneSiteLooksLikeProduction bool
|
var atLeastOneSiteLooksLikeProduction bool
|
||||||
for _, cfg := range h.siteConfigs {
|
for _, cfg := range h.siteConfigs {
|
||||||
// if we aren't sure yet whether it's a "production" server,
|
// see if all the addresses (both sites and
|
||||||
// continue to see if all the addresses (both sites and
|
// listeners) are loopback to help us determine
|
||||||
// listeners) are loopback
|
// if this is a "production" instance or not
|
||||||
if !atLeastOneSiteLooksLikeProduction {
|
if !atLeastOneSiteLooksLikeProduction {
|
||||||
if !caddy.IsLoopback(cfg.Addr.Host) &&
|
if !caddy.IsLoopback(cfg.Addr.Host) &&
|
||||||
!caddy.IsLoopback(cfg.ListenHost) &&
|
!caddy.IsLoopback(cfg.ListenHost) &&
|
||||||
|
@ -272,17 +272,17 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
|
||||||
servers = append(servers, s)
|
servers = append(servers, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This value is only a "good" guess. Quite often, development
|
// NOTE: This value is only a "good guess". Quite often, development
|
||||||
// environments will use internal DNS or a local hosts file to serve
|
// environments will use internal DNS or a local hosts file to serve
|
||||||
// real-looking domains in local development. We can't easily tell
|
// real-looking domains in local development. We can't easily tell
|
||||||
// which without doing a DNS lookup, so this guess is definitely naive,
|
// which without doing a DNS lookup, so this guess is definitely naive,
|
||||||
// and if we ever want a better guess, we will have to do DNS lookups.
|
// and if we ever want a better guess, we will have to do DNS lookups.
|
||||||
deploymentGuess := "dev"
|
deploymentGuess := "dev"
|
||||||
if looksLikeProductionCA && atLeastOneSiteLooksLikeProduction {
|
if looksLikeProductionCA && atLeastOneSiteLooksLikeProduction {
|
||||||
deploymentGuess = "production"
|
deploymentGuess = "prod"
|
||||||
}
|
}
|
||||||
diagnostics.Set("http_deployment_guess", deploymentGuess)
|
telemetry.Set("http_deployment_guess", deploymentGuess)
|
||||||
diagnostics.Set("http_num_sites", len(h.siteConfigs))
|
telemetry.Set("http_num_sites", len(h.siteConfigs))
|
||||||
|
|
||||||
return servers, nil
|
return servers, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import (
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddyhttp/staticfiles"
|
"github.com/mholt/caddy/caddyhttp/staticfiles"
|
||||||
"github.com/mholt/caddy/caddytls"
|
"github.com/mholt/caddy/caddytls"
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server is the HTTP server implementation.
|
// Server is the HTTP server implementation.
|
||||||
|
@ -347,8 +347,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// TODO: Somehow report UA string in conjunction with TLS handshake, if any (and just once per connection)
|
// TODO: Somehow report UA string in conjunction with TLS handshake, if any (and just once per connection)
|
||||||
go diagnostics.AppendUnique("http_user_agent", r.Header.Get("User-Agent"))
|
go telemetry.AppendUnique("http_user_agent", r.Header.Get("User-Agent"))
|
||||||
go diagnostics.Increment("http_request_count")
|
go telemetry.Increment("http_request_count")
|
||||||
|
|
||||||
// copy the original, unchanged URL into the context
|
// copy the original, unchanged URL into the context
|
||||||
// so it can be referenced by middlewares
|
// so it can be referenced by middlewares
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
"golang.org/x/crypto/ocsp"
|
"golang.org/x/crypto/ocsp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ func (cfg *Config) CacheManagedCertificate(domain string) (Certificate, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cert, err
|
return cert, err
|
||||||
}
|
}
|
||||||
diagnostics.Increment("tls_managed_cert_count")
|
telemetry.Increment("tls_managed_cert_count")
|
||||||
return cfg.cacheCertificate(cert), nil
|
return cfg.cacheCertificate(cert), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ func (cfg *Config) cacheUnmanagedCertificatePEMFile(certFile, keyFile string) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfg.cacheCertificate(cert)
|
cfg.cacheCertificate(cert)
|
||||||
diagnostics.Increment("tls_manual_cert_count")
|
telemetry.Increment("tls_manual_cert_count")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ func (cfg *Config) cacheUnmanagedCertificatePEMBytes(certBytes, keyBytes []byte)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfg.cacheCertificate(cert)
|
cfg.cacheCertificate(cert)
|
||||||
diagnostics.Increment("tls_manual_cert_count")
|
telemetry.Increment("tls_manual_cert_count")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
"github.com/xenolf/lego/acme"
|
"github.com/xenolf/lego/acme"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ Attempts:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
go diagnostics.Increment("tls_acme_certs_obtained")
|
go telemetry.Increment("tls_acme_certs_obtained")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ func (c *ACMEClient) Renew(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
caddy.EmitEvent(caddy.CertRenewEvent, name)
|
caddy.EmitEvent(caddy.CertRenewEvent, name)
|
||||||
go diagnostics.Increment("tls_acme_certs_renewed")
|
go telemetry.Increment("tls_acme_certs_renewed")
|
||||||
|
|
||||||
return saveCertResource(c.storage, newCertMeta)
|
return saveCertResource(c.storage, newCertMeta)
|
||||||
}
|
}
|
||||||
|
@ -367,7 +367,7 @@ func (c *ACMEClient) Revoke(name string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go diagnostics.Increment("tls_acme_certs_revoked")
|
go telemetry.Increment("tls_acme_certs_revoked")
|
||||||
|
|
||||||
err = c.storage.DeleteSite(name)
|
err = c.storage.DeleteSite(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// configGroup is a type that keys configs by their hostname
|
// configGroup is a type that keys configs by their hostname
|
||||||
|
@ -102,7 +102,7 @@ func (cg configGroup) GetConfigForClient(clientHello *tls.ClientHelloInfo) (*tls
|
||||||
func (cfg *Config) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
func (cfg *Config) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
// TODO: We need to collect this in a heavily de-duplicating way
|
// TODO: We need to collect this in a heavily de-duplicating way
|
||||||
// It would also be nice to associate a handshake with the UA string (but that is only for HTTP server type)
|
// It would also be nice to associate a handshake with the UA string (but that is only for HTTP server type)
|
||||||
// go diagnostics.Append("tls_client_hello", struct {
|
// go telemetry.Append("tls_client_hello", struct {
|
||||||
// NoSNI bool `json:"no_sni,omitempty"`
|
// NoSNI bool `json:"no_sni,omitempty"`
|
||||||
// CipherSuites []uint16 `json:"cipher_suites,omitempty"`
|
// CipherSuites []uint16 `json:"cipher_suites,omitempty"`
|
||||||
// SupportedCurves []tls.CurveID `json:"curves,omitempty"`
|
// SupportedCurves []tls.CurveID `json:"curves,omitempty"`
|
||||||
|
@ -121,9 +121,9 @@ func (cfg *Config) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certif
|
||||||
// })
|
// })
|
||||||
cert, err := cfg.getCertDuringHandshake(strings.ToLower(clientHello.ServerName), true, true)
|
cert, err := cfg.getCertDuringHandshake(strings.ToLower(clientHello.ServerName), true, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
go diagnostics.Increment("tls_handshake_count")
|
go telemetry.Increment("tls_handshake_count")
|
||||||
} else {
|
} else {
|
||||||
go diagnostics.Append("tls_handshake_error", err.Error())
|
go telemetry.Append("tls_handshake_error", err.Error())
|
||||||
}
|
}
|
||||||
return &cert.Certificate, err
|
return &cert.Certificate, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -175,11 +175,11 @@ func setupTLS(c *caddy.Controller) error {
|
||||||
case "max_certs":
|
case "max_certs":
|
||||||
c.Args(&maxCerts)
|
c.Args(&maxCerts)
|
||||||
config.OnDemand = true
|
config.OnDemand = true
|
||||||
diagnostics.Increment("tls_on_demand_count")
|
telemetry.Increment("tls_on_demand_count")
|
||||||
case "ask":
|
case "ask":
|
||||||
c.Args(&askURL)
|
c.Args(&askURL)
|
||||||
config.OnDemand = true
|
config.OnDemand = true
|
||||||
diagnostics.Increment("tls_on_demand_count")
|
telemetry.Increment("tls_on_demand_count")
|
||||||
case "dns":
|
case "dns":
|
||||||
args := c.RemainingArgs()
|
args := c.RemainingArgs()
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
|
@ -254,7 +254,7 @@ func setupTLS(c *caddy.Controller) error {
|
||||||
return c.Errf("Unable to load certificate and key files for '%s': %v", c.Key, err)
|
return c.Errf("Unable to load certificate and key files for '%s': %v", c.Key, err)
|
||||||
}
|
}
|
||||||
log.Printf("[INFO] Successfully loaded TLS assets from %s and %s", certificateFile, keyFile)
|
log.Printf("[INFO] Successfully loaded TLS assets from %s and %s", certificateFile, keyFile)
|
||||||
diagnostics.Increment("tls_manual_cert_count")
|
telemetry.Increment("tls_manual_cert_count")
|
||||||
}
|
}
|
||||||
|
|
||||||
// load a directory of certificates, if specified
|
// load a directory of certificates, if specified
|
||||||
|
@ -274,7 +274,7 @@ func setupTLS(c *caddy.Controller) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("self-signed: %v", err)
|
return fmt.Errorf("self-signed: %v", err)
|
||||||
}
|
}
|
||||||
diagnostics.Increment("tls_self_signed_count")
|
telemetry.Increment("tls_self_signed_count")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -355,7 +355,7 @@ func loadCertsInDir(cfg *Config, c *caddy.Controller, dir string) error {
|
||||||
return c.Errf("%s: failed to load cert and key for '%s': %v", path, c.Key, err)
|
return c.Errf("%s: failed to load cert and key for '%s': %v", path, c.Key, err)
|
||||||
}
|
}
|
||||||
log.Printf("[INFO] Successfully loaded TLS assets from %s", path)
|
log.Printf("[INFO] Successfully loaded TLS assets from %s", path)
|
||||||
diagnostics.Increment("tls_manual_cert_count")
|
telemetry.Increment("tls_manual_cert_count")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrapSignals create signal handlers for all applicable signals for this
|
// TrapSignals create signal handlers for all applicable signals for this
|
||||||
|
@ -54,8 +54,8 @@ func trapSignalsCrossPlatform() {
|
||||||
|
|
||||||
log.Println("[INFO] SIGINT: Shutting down")
|
log.Println("[INFO] SIGINT: Shutting down")
|
||||||
|
|
||||||
diagnostics.AppendUnique("sigtrap", "SIGINT")
|
telemetry.AppendUnique("sigtrap", "SIGINT")
|
||||||
go diagnostics.StopEmitting() // not guaranteed to finish in time; that's OK (just don't block!)
|
go telemetry.StopEmitting() // not guaranteed to finish in time; that's OK (just don't block!)
|
||||||
|
|
||||||
// important cleanup actions before shutdown callbacks
|
// important cleanup actions before shutdown callbacks
|
||||||
for _, f := range OnProcessExit {
|
for _, f := range OnProcessExit {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/mholt/caddy/diagnostics"
|
"github.com/mholt/caddy/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// trapSignalsPosix captures POSIX-only signals.
|
// trapSignalsPosix captures POSIX-only signals.
|
||||||
|
@ -52,14 +52,14 @@ func trapSignalsPosix() {
|
||||||
exitCode = 3
|
exitCode = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.AppendUnique("sigtrap", "SIGTERM")
|
telemetry.AppendUnique("sigtrap", "SIGTERM")
|
||||||
go diagnostics.StopEmitting() // won't finish in time, but that's OK - just don't block
|
go telemetry.StopEmitting() // won't finish in time, but that's OK - just don't block
|
||||||
|
|
||||||
os.Exit(exitCode)
|
os.Exit(exitCode)
|
||||||
|
|
||||||
case syscall.SIGUSR1:
|
case syscall.SIGUSR1:
|
||||||
log.Println("[INFO] SIGUSR1: Reloading")
|
log.Println("[INFO] SIGUSR1: Reloading")
|
||||||
go diagnostics.AppendUnique("sigtrap", "SIGUSR1")
|
go telemetry.AppendUnique("sigtrap", "SIGUSR1")
|
||||||
|
|
||||||
// Start with the existing Caddyfile
|
// Start with the existing Caddyfile
|
||||||
caddyfileToUse, inst, err := getCurrentCaddyfile()
|
caddyfileToUse, inst, err := getCurrentCaddyfile()
|
||||||
|
@ -91,14 +91,14 @@ func trapSignalsPosix() {
|
||||||
|
|
||||||
case syscall.SIGUSR2:
|
case syscall.SIGUSR2:
|
||||||
log.Println("[INFO] SIGUSR2: Upgrading")
|
log.Println("[INFO] SIGUSR2: Upgrading")
|
||||||
go diagnostics.AppendUnique("sigtrap", "SIGUSR2")
|
go telemetry.AppendUnique("sigtrap", "SIGUSR2")
|
||||||
if err := Upgrade(); err != nil {
|
if err := Upgrade(); err != nil {
|
||||||
log.Printf("[ERROR] SIGUSR2: upgrading: %v", err)
|
log.Printf("[ERROR] SIGUSR2: upgrading: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
case syscall.SIGHUP:
|
case syscall.SIGHUP:
|
||||||
// ignore; this signal is sometimes sent outside of the user's control
|
// ignore; this signal is sometimes sent outside of the user's control
|
||||||
go diagnostics.AppendUnique("sigtrap", "SIGHUP")
|
go telemetry.AppendUnique("sigtrap", "SIGHUP")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package diagnostics
|
package telemetry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
@ -139,7 +139,7 @@ func Append(key string, value interface{}) {
|
||||||
sliceVal, sliceOk := bufVal.([]interface{})
|
sliceVal, sliceOk := bufVal.([]interface{})
|
||||||
if inBuffer && !sliceOk {
|
if inBuffer && !sliceOk {
|
||||||
bufferMu.Unlock()
|
bufferMu.Unlock()
|
||||||
log.Printf("[PANIC] Diagnostics: key %s already used for non-slice value", key)
|
log.Printf("[PANIC] Telemetry: key %s already used for non-slice value", key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if sliceVal == nil {
|
if sliceVal == nil {
|
||||||
|
@ -169,7 +169,7 @@ func AppendUnique(key string, value interface{}) {
|
||||||
setVal, setOk := bufVal.(countingSet)
|
setVal, setOk := bufVal.(countingSet)
|
||||||
if inBuffer && !setOk {
|
if inBuffer && !setOk {
|
||||||
bufferMu.Unlock()
|
bufferMu.Unlock()
|
||||||
log.Printf("[PANIC] Diagnostics: key %s already used for non-counting-set value", key)
|
log.Printf("[PANIC] Telemetry: key %s already used for non-counting-set value", key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if setVal == nil {
|
if setVal == nil {
|
||||||
|
@ -212,7 +212,7 @@ func atomicAdd(key string, amount int) {
|
||||||
intVal, intOk := bufVal.(int)
|
intVal, intOk := bufVal.(int)
|
||||||
if inBuffer && !intOk {
|
if inBuffer && !intOk {
|
||||||
bufferMu.Unlock()
|
bufferMu.Unlock()
|
||||||
log.Printf("[PANIC] Diagnostics: key %s already used for non-integer value", key)
|
log.Printf("[PANIC] Telemetry: key %s already used for non-integer value", key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !inBuffer {
|
if !inBuffer {
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package diagnostics
|
package telemetry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -12,26 +12,25 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package diagnostics implements the client for server-side diagnostics
|
// Package telemetry implements the client for server-side telemetry
|
||||||
// of the network. Functions in this package are synchronous and blocking
|
// of the network. Functions in this package are synchronous and blocking
|
||||||
// unless otherwise specified. For convenience, most functions here do
|
// unless otherwise specified. For convenience, most functions here do
|
||||||
// not return errors, but errors are logged to the standard logger.
|
// not return errors, but errors are logged to the standard logger.
|
||||||
//
|
//
|
||||||
// To use this package, first call Init(). You can then call any of the
|
// To use this package, first call Init(). You can then call any of the
|
||||||
// collection/aggregation functions. Call StartEmitting() when you are
|
// collection/aggregation functions. Call StartEmitting() when you are
|
||||||
// ready to begin sending diagnostic updates.
|
// ready to begin sending telemetry updates.
|
||||||
//
|
//
|
||||||
// When collecting metrics (functions like Set, AppendUnique, or Increment),
|
// When collecting metrics (functions like Set, AppendUnique, or Increment),
|
||||||
// it may be desirable and even recommended to invoke them in a new
|
// it may be desirable and even recommended to invoke them in a new
|
||||||
// goroutine (use the go keyword) in case there is lock contention;
|
// goroutine in case there is lock contention; they are thread-safe (unless
|
||||||
// they are thread-safe (unless noted), and you may not want them to
|
// noted), and you may not want them to block the main thread of execution.
|
||||||
// block the main thread of execution. However, sometimes blocking
|
// However, sometimes blocking may be necessary too; for example, adding
|
||||||
// may be necessary too; for example, adding startup metrics to the
|
// startup metrics to the buffer before the call to StartEmitting().
|
||||||
// buffer before the call to StartEmitting().
|
|
||||||
//
|
//
|
||||||
// This package is designed to be as fast and space-efficient as reasonably
|
// This package is designed to be as fast and space-efficient as reasonably
|
||||||
// possible, so that it does not disrupt the flow of execution.
|
// possible, so that it does not disrupt the flow of execution.
|
||||||
package diagnostics
|
package telemetry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -53,17 +52,17 @@ import (
|
||||||
func logEmit(final bool) {
|
func logEmit(final bool) {
|
||||||
err := emit(final)
|
err := emit(final)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Sending diagnostics: %v", err)
|
log.Printf("[ERROR] Sending telemetry: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit sends an update to the diagnostics server.
|
// emit sends an update to the telemetry server.
|
||||||
// Set final to true if this is the last call to emit.
|
// Set final to true if this is the last call to emit.
|
||||||
// If final is true, no future updates will be scheduled.
|
// If final is true, no future updates will be scheduled.
|
||||||
// Otherwise, the next update will be scheduled.
|
// Otherwise, the next update will be scheduled.
|
||||||
func emit(final bool) error {
|
func emit(final bool) error {
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return fmt.Errorf("diagnostics not enabled")
|
return fmt.Errorf("telemetry not enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure only one update happens at a time;
|
// ensure only one update happens at a time;
|
||||||
|
@ -71,7 +70,7 @@ func emit(final bool) error {
|
||||||
updateMu.Lock()
|
updateMu.Lock()
|
||||||
if updating {
|
if updating {
|
||||||
updateMu.Unlock()
|
updateMu.Unlock()
|
||||||
log.Println("[NOTICE] Skipping this diagnostics update because previous one is still working")
|
log.Println("[NOTICE] Skipping this telemetry update because previous one is still working")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
updating = true
|
updating = true
|
||||||
|
@ -100,7 +99,7 @@ func emit(final bool) error {
|
||||||
if i > 0 && err != nil {
|
if i > 0 && err != nil {
|
||||||
// don't hammer the server; first failure might have been
|
// don't hammer the server; first failure might have been
|
||||||
// a fluke, but back off more after that
|
// a fluke, but back off more after that
|
||||||
log.Printf("[WARNING] Sending diagnostics (attempt %d): %v - backing off and retrying", i, err)
|
log.Printf("[WARNING] Sending telemetry (attempt %d): %v - backing off and retrying", i, err)
|
||||||
time.Sleep(time.Duration((i+1)*(i+1)*(i+1)) * time.Second)
|
time.Sleep(time.Duration((i+1)*(i+1)*(i+1)) * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +113,7 @@ func emit(final bool) error {
|
||||||
// check for any special-case response codes
|
// check for any special-case response codes
|
||||||
if resp.StatusCode == http.StatusGone {
|
if resp.StatusCode == http.StatusGone {
|
||||||
// the endpoint has been deprecated and is no longer servicing clients
|
// the endpoint has been deprecated and is no longer servicing clients
|
||||||
err = fmt.Errorf("diagnostics server replied with HTTP %d; upgrade required", resp.StatusCode)
|
err = fmt.Errorf("telemetry server replied with HTTP %d; upgrade required", resp.StatusCode)
|
||||||
if clen := resp.Header.Get("Content-Length"); clen != "0" && clen != "" {
|
if clen := resp.Header.Get("Content-Length"); clen != "0" && clen != "" {
|
||||||
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
||||||
if readErr != nil {
|
if readErr != nil {
|
||||||
|
@ -128,7 +127,7 @@ func emit(final bool) error {
|
||||||
}
|
}
|
||||||
if resp.StatusCode == http.StatusUnavailableForLegalReasons {
|
if resp.StatusCode == http.StatusUnavailableForLegalReasons {
|
||||||
// the endpoint is unavailable, at least to this client, for legal reasons (!)
|
// the endpoint is unavailable, at least to this client, for legal reasons (!)
|
||||||
err = fmt.Errorf("diagnostics server replied with HTTP %d %s: please consult the project website and developers for guidance", resp.StatusCode, resp.Status)
|
err = fmt.Errorf("telemetry server replied with HTTP %d %s: please consult the project website and developers for guidance", resp.StatusCode, resp.Status)
|
||||||
if clen := resp.Header.Get("Content-Length"); clen != "0" && clen != "" {
|
if clen := resp.Header.Get("Content-Length"); clen != "0" && clen != "" {
|
||||||
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
||||||
if readErr != nil {
|
if readErr != nil {
|
||||||
|
@ -144,7 +143,7 @@ func emit(final bool) error {
|
||||||
// okay, ensure we can interpret the response
|
// okay, ensure we can interpret the response
|
||||||
if ct := resp.Header.Get("Content-Type"); (resp.StatusCode < 300 || resp.StatusCode >= 400) &&
|
if ct := resp.Header.Get("Content-Type"); (resp.StatusCode < 300 || resp.StatusCode >= 400) &&
|
||||||
!strings.Contains(ct, "json") {
|
!strings.Contains(ct, "json") {
|
||||||
err = fmt.Errorf("diagnostics server replied with unknown content-type: '%s' and HTTP %s", ct, resp.Status)
|
err = fmt.Errorf("telemetry server replied with unknown content-type: '%s' and HTTP %s", ct, resp.Status)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -167,12 +166,12 @@ func emit(final bool) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !final {
|
if !final {
|
||||||
log.Printf("[NOTICE] Sending diagnostics: we were too early; waiting %s before trying again", reply.NextUpdate)
|
log.Printf("[NOTICE] Sending telemetry: we were too early; waiting %s before trying again", reply.NextUpdate)
|
||||||
time.Sleep(reply.NextUpdate)
|
time.Sleep(reply.NextUpdate)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else if resp.StatusCode >= 400 {
|
} else if resp.StatusCode >= 400 {
|
||||||
err = fmt.Errorf("diagnostics server returned status code %d", resp.StatusCode)
|
err = fmt.Errorf("telemetry server returned status code %d", resp.StatusCode)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,14 +180,14 @@ func emit(final bool) error {
|
||||||
if err == nil && !final {
|
if err == nil && !final {
|
||||||
// (remember, if there was an error, we return it
|
// (remember, if there was an error, we return it
|
||||||
// below, so it WILL get logged if it's supposed to)
|
// below, so it WILL get logged if it's supposed to)
|
||||||
log.Println("[INFO] Sending diagnostics: success")
|
log.Println("[INFO] Sending telemetry: success")
|
||||||
}
|
}
|
||||||
|
|
||||||
// even if there was an error after all retries, we should
|
// even if there was an error after all retries, we should
|
||||||
// schedule the next update using our default update
|
// schedule the next update using our default update
|
||||||
// interval because the server might be healthy later
|
// interval because the server might be healthy later
|
||||||
|
|
||||||
// ensure we won't slam the diagnostics server
|
// ensure we won't slam the telemetry server
|
||||||
if reply.NextUpdate < 1*time.Second {
|
if reply.NextUpdate < 1*time.Second {
|
||||||
reply.NextUpdate = defaultUpdateInterval
|
reply.NextUpdate = defaultUpdateInterval
|
||||||
}
|
}
|
||||||
|
@ -247,13 +246,13 @@ func resetBuffer() map[string]interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response contains the body of a response from the
|
// Response contains the body of a response from the
|
||||||
// diagnostics server.
|
// telemetry server.
|
||||||
type Response struct {
|
type Response struct {
|
||||||
// NextUpdate is how long to wait before the next update.
|
// NextUpdate is how long to wait before the next update.
|
||||||
NextUpdate time.Duration `json:"next_update"`
|
NextUpdate time.Duration `json:"next_update"`
|
||||||
|
|
||||||
// Stop instructs the diagnostics server to stop sending
|
// Stop instructs the telemetry server to stop sending
|
||||||
// diagnostics. This would only be done under extenuating
|
// telemetry. This would only be done under extenuating
|
||||||
// circumstances, but we are prepared for it nonetheless.
|
// circumstances, but we are prepared for it nonetheless.
|
||||||
Stop bool `json:"stop,omitempty"`
|
Stop bool `json:"stop,omitempty"`
|
||||||
|
|
||||||
|
@ -262,7 +261,7 @@ type Response struct {
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Payload is the data that gets sent to the diagnostics server.
|
// Payload is the data that gets sent to the telemetry server.
|
||||||
type Payload struct {
|
type Payload struct {
|
||||||
// The universally unique ID of the instance
|
// The universally unique ID of the instance
|
||||||
InstanceID string `json:"instance_id"`
|
InstanceID string `json:"instance_id"`
|
||||||
|
@ -337,7 +336,7 @@ var (
|
||||||
updateTimerMu sync.Mutex
|
updateTimerMu sync.Mutex
|
||||||
|
|
||||||
// instanceUUID is the ID of the current instance.
|
// instanceUUID is the ID of the current instance.
|
||||||
// This MUST be set to emit diagnostics.
|
// This MUST be set to emit telemetry.
|
||||||
// This MUST NOT be openly exposed to clients, for privacy.
|
// This MUST NOT be openly exposed to clients, for privacy.
|
||||||
instanceUUID uuid.UUID
|
instanceUUID uuid.UUID
|
||||||
|
|
||||||
|
@ -352,12 +351,12 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// endpoint is the base URL to remote diagnostics server;
|
// endpoint is the base URL to remote telemetry server;
|
||||||
// the instance ID will be appended to it.
|
// the instance ID will be appended to it.
|
||||||
endpoint = "https://diagnostics-staging.caddyserver.com/update/" // TODO: make configurable, "http://localhost:8085/update/"
|
endpoint = "https://telemetry-staging.caddyserver.com/v1/update/"
|
||||||
|
|
||||||
// defaultUpdateInterval is how long to wait before emitting
|
// defaultUpdateInterval is how long to wait before emitting
|
||||||
// more diagnostic data if all retires fail. This value is
|
// more telemetry data if all retires fail. This value is
|
||||||
// only used if the client receives a nonsensical value, or
|
// only used if the client receives a nonsensical value, or
|
||||||
// doesn't send one at all, or if a connection can't be made,
|
// doesn't send one at all, or if a connection can't be made,
|
||||||
// likely indicating a problem with the server. Thus, this
|
// likely indicating a problem with the server. Thus, this
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package diagnostics
|
package telemetry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
Loading…
Reference in New Issue
Block a user