mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-14 06:46:27 +03:00
Refactor diagnostics -> telemetry
This commit is contained in:
parent
7c868afd32
commit
52316952a5
16 changed files with 96 additions and 97 deletions
4
caddy.go
4
caddy.go
|
@ -44,7 +44,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/mholt/caddy/caddyfile"
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
// Configurable application parameters
|
||||
|
@ -617,7 +617,7 @@ func ValidateAndExecuteDirectives(cdyfile Input, inst *Instance, justValidate bo
|
|||
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)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
"github.com/klauspost/cpuid"
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddytls"
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
"github.com/xenolf/lego/acme"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
|
@ -52,7 +52,6 @@ func init() {
|
|||
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.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.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
|
||||
flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate")
|
||||
|
@ -89,9 +88,9 @@ func Run() {
|
|||
})
|
||||
}
|
||||
|
||||
// initialize diagnostics client
|
||||
if !noDiag {
|
||||
initDiagnostics()
|
||||
// initialize telemetry client
|
||||
if enableTelemetry {
|
||||
initTelemetry()
|
||||
}
|
||||
|
||||
// Check for one-time actions
|
||||
|
@ -150,13 +149,13 @@ func Run() {
|
|||
// Execute instantiation events
|
||||
caddy.EmitEvent(caddy.InstanceStartupEvent, instance)
|
||||
|
||||
// Begin diagnostics (these are no-ops if diagnostics disabled)
|
||||
diagnostics.Set("caddy_version", appVersion)
|
||||
diagnostics.Set("num_listeners", len(instance.Servers()))
|
||||
diagnostics.Set("server_type", serverType)
|
||||
diagnostics.Set("os", runtime.GOOS)
|
||||
diagnostics.Set("arch", runtime.GOARCH)
|
||||
diagnostics.Set("cpu", struct {
|
||||
// Begin telemetry (these are no-ops if telemetry disabled)
|
||||
telemetry.Set("caddy_version", appVersion)
|
||||
telemetry.Set("num_listeners", len(instance.Servers()))
|
||||
telemetry.Set("server_type", serverType)
|
||||
telemetry.Set("os", runtime.GOOS)
|
||||
telemetry.Set("arch", runtime.GOARCH)
|
||||
telemetry.Set("cpu", struct {
|
||||
BrandName string `json:"brand_name,omitempty"`
|
||||
NumLogical int `json:"num_logical,omitempty"`
|
||||
AESNI bool `json:"aes_ni,omitempty"`
|
||||
|
@ -165,7 +164,7 @@ func Run() {
|
|||
NumLogical: runtime.NumCPU(),
|
||||
AESNI: cpuid.CPU.AesNi(),
|
||||
})
|
||||
diagnostics.StartEmitting()
|
||||
telemetry.StartEmitting()
|
||||
|
||||
// Twiddle your thumbs
|
||||
instance.Wait()
|
||||
|
@ -290,8 +289,8 @@ func setCPU(cpu string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// initDiagnostics initializes the diagnostics engine.
|
||||
func initDiagnostics() {
|
||||
// initTelemetry initializes the telemetry engine.
|
||||
func initTelemetry() {
|
||||
uuidFilename := filepath.Join(caddy.AssetsPath(), "uuid")
|
||||
|
||||
newUUID := func() uuid.UUID {
|
||||
|
@ -327,7 +326,7 @@ func initDiagnostics() {
|
|||
}
|
||||
}
|
||||
|
||||
diagnostics.Init(id)
|
||||
telemetry.Init(id)
|
||||
}
|
||||
|
||||
const appName = "Caddy"
|
||||
|
@ -342,7 +341,6 @@ var (
|
|||
version bool
|
||||
plugins bool
|
||||
validate bool
|
||||
noDiag bool
|
||||
)
|
||||
|
||||
// Build information obtained with the help of -ldflags
|
||||
|
@ -356,4 +354,6 @@ var (
|
|||
gitCommit string // git rev-parse HEAD
|
||||
gitShortStat string // git diff-index --shortstat
|
||||
gitFilesModified string // git diff-index --name-only HEAD
|
||||
|
||||
enableTelemetry = true
|
||||
)
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
// 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
|
||||
p.block.Tokens[dir] = append(p.block.Tokens[dir], p.tokens[p.cursor])
|
||||
diagnostics.AppendUnique("directives", dir)
|
||||
telemetry.AppendUnique("directives", dir)
|
||||
|
||||
for p.Next() {
|
||||
if p.Val() == "{" {
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
r = r.WithContext(context.WithValue(r.Context(), MitmCtxKey, mitm))
|
||||
if mitm {
|
||||
go diagnostics.AppendUnique("http_mitm", "likely")
|
||||
go telemetry.AppendUnique("http_mitm", "likely")
|
||||
} else {
|
||||
go diagnostics.AppendUnique("http_mitm", "unlikely")
|
||||
go telemetry.AppendUnique("http_mitm", "unlikely")
|
||||
}
|
||||
} else {
|
||||
go diagnostics.AppendUnique("http_mitm", "unknown")
|
||||
go telemetry.AppendUnique("http_mitm", "unknown")
|
||||
}
|
||||
|
||||
if mitm && h.closeOnMITM {
|
||||
|
|
|
@ -29,7 +29,7 @@ import (
|
|||
"github.com/mholt/caddy/caddyfile"
|
||||
"github.com/mholt/caddy/caddyhttp/staticfiles"
|
||||
"github.com/mholt/caddy/caddytls"
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
const serverType = "http"
|
||||
|
@ -220,9 +220,9 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
|
|||
|
||||
var atLeastOneSiteLooksLikeProduction bool
|
||||
for _, cfg := range h.siteConfigs {
|
||||
// if we aren't sure yet whether it's a "production" server,
|
||||
// continue to see if all the addresses (both sites and
|
||||
// listeners) are loopback
|
||||
// see if all the addresses (both sites and
|
||||
// listeners) are loopback to help us determine
|
||||
// if this is a "production" instance or not
|
||||
if !atLeastOneSiteLooksLikeProduction {
|
||||
if !caddy.IsLoopback(cfg.Addr.Host) &&
|
||||
!caddy.IsLoopback(cfg.ListenHost) &&
|
||||
|
@ -272,17 +272,17 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
|
|||
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
|
||||
// real-looking domains in local development. We can't easily tell
|
||||
// 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.
|
||||
deploymentGuess := "dev"
|
||||
if looksLikeProductionCA && atLeastOneSiteLooksLikeProduction {
|
||||
deploymentGuess = "production"
|
||||
deploymentGuess = "prod"
|
||||
}
|
||||
diagnostics.Set("http_deployment_guess", deploymentGuess)
|
||||
diagnostics.Set("http_num_sites", len(h.siteConfigs))
|
||||
telemetry.Set("http_deployment_guess", deploymentGuess)
|
||||
telemetry.Set("http_num_sites", len(h.siteConfigs))
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ import (
|
|||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyhttp/staticfiles"
|
||||
"github.com/mholt/caddy/caddytls"
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
// 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)
|
||||
go diagnostics.AppendUnique("http_user_agent", r.Header.Get("User-Agent"))
|
||||
go diagnostics.Increment("http_request_count")
|
||||
go telemetry.AppendUnique("http_user_agent", r.Header.Get("User-Agent"))
|
||||
go telemetry.Increment("http_request_count")
|
||||
|
||||
// copy the original, unchanged URL into the context
|
||||
// so it can be referenced by middlewares
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
|
@ -166,7 +166,7 @@ func (cfg *Config) CacheManagedCertificate(domain string) (Certificate, error) {
|
|||
if err != nil {
|
||||
return cert, err
|
||||
}
|
||||
diagnostics.Increment("tls_managed_cert_count")
|
||||
telemetry.Increment("tls_managed_cert_count")
|
||||
return cfg.cacheCertificate(cert), nil
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ func (cfg *Config) cacheUnmanagedCertificatePEMFile(certFile, keyFile string) er
|
|||
return err
|
||||
}
|
||||
cfg.cacheCertificate(cert)
|
||||
diagnostics.Increment("tls_manual_cert_count")
|
||||
telemetry.Increment("tls_manual_cert_count")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ func (cfg *Config) cacheUnmanagedCertificatePEMBytes(certBytes, keyBytes []byte)
|
|||
return err
|
||||
}
|
||||
cfg.cacheCertificate(cert)
|
||||
diagnostics.Increment("tls_manual_cert_count")
|
||||
telemetry.Increment("tls_manual_cert_count")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
"github.com/xenolf/lego/acme"
|
||||
)
|
||||
|
||||
|
@ -268,7 +268,7 @@ Attempts:
|
|||
break
|
||||
}
|
||||
|
||||
go diagnostics.Increment("tls_acme_certs_obtained")
|
||||
go telemetry.Increment("tls_acme_certs_obtained")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -340,7 +340,7 @@ func (c *ACMEClient) Renew(name string) error {
|
|||
}
|
||||
|
||||
caddy.EmitEvent(caddy.CertRenewEvent, name)
|
||||
go diagnostics.Increment("tls_acme_certs_renewed")
|
||||
go telemetry.Increment("tls_acme_certs_renewed")
|
||||
|
||||
return saveCertResource(c.storage, newCertMeta)
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ func (c *ACMEClient) Revoke(name string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
go diagnostics.Increment("tls_acme_certs_revoked")
|
||||
go telemetry.Increment("tls_acme_certs_revoked")
|
||||
|
||||
err = c.storage.DeleteSite(name)
|
||||
if err != nil {
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
// 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)
|
||||
// go diagnostics.Append("tls_client_hello", struct {
|
||||
// go telemetry.Append("tls_client_hello", struct {
|
||||
// NoSNI bool `json:"no_sni,omitempty"`
|
||||
// CipherSuites []uint16 `json:"cipher_suites,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)
|
||||
if err == nil {
|
||||
go diagnostics.Increment("tls_handshake_count")
|
||||
go telemetry.Increment("tls_handshake_count")
|
||||
} else {
|
||||
go diagnostics.Append("tls_handshake_error", err.Error())
|
||||
go telemetry.Append("tls_handshake_error", err.Error())
|
||||
}
|
||||
return &cert.Certificate, err
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -175,11 +175,11 @@ func setupTLS(c *caddy.Controller) error {
|
|||
case "max_certs":
|
||||
c.Args(&maxCerts)
|
||||
config.OnDemand = true
|
||||
diagnostics.Increment("tls_on_demand_count")
|
||||
telemetry.Increment("tls_on_demand_count")
|
||||
case "ask":
|
||||
c.Args(&askURL)
|
||||
config.OnDemand = true
|
||||
diagnostics.Increment("tls_on_demand_count")
|
||||
telemetry.Increment("tls_on_demand_count")
|
||||
case "dns":
|
||||
args := c.RemainingArgs()
|
||||
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)
|
||||
}
|
||||
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
|
||||
|
@ -274,7 +274,7 @@ func setupTLS(c *caddy.Controller) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("self-signed: %v", err)
|
||||
}
|
||||
diagnostics.Increment("tls_self_signed_count")
|
||||
telemetry.Increment("tls_self_signed_count")
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
log.Printf("[INFO] Successfully loaded TLS assets from %s", path)
|
||||
diagnostics.Increment("tls_manual_cert_count")
|
||||
telemetry.Increment("tls_manual_cert_count")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"os/signal"
|
||||
"sync"
|
||||
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
// TrapSignals create signal handlers for all applicable signals for this
|
||||
|
@ -54,8 +54,8 @@ func trapSignalsCrossPlatform() {
|
|||
|
||||
log.Println("[INFO] SIGINT: Shutting down")
|
||||
|
||||
diagnostics.AppendUnique("sigtrap", "SIGINT")
|
||||
go diagnostics.StopEmitting() // not guaranteed to finish in time; that's OK (just don't block!)
|
||||
telemetry.AppendUnique("sigtrap", "SIGINT")
|
||||
go telemetry.StopEmitting() // not guaranteed to finish in time; that's OK (just don't block!)
|
||||
|
||||
// important cleanup actions before shutdown callbacks
|
||||
for _, f := range OnProcessExit {
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/mholt/caddy/diagnostics"
|
||||
"github.com/mholt/caddy/telemetry"
|
||||
)
|
||||
|
||||
// trapSignalsPosix captures POSIX-only signals.
|
||||
|
@ -52,14 +52,14 @@ func trapSignalsPosix() {
|
|||
exitCode = 3
|
||||
}
|
||||
|
||||
diagnostics.AppendUnique("sigtrap", "SIGTERM")
|
||||
go diagnostics.StopEmitting() // won't finish in time, but that's OK - just don't block
|
||||
telemetry.AppendUnique("sigtrap", "SIGTERM")
|
||||
go telemetry.StopEmitting() // won't finish in time, but that's OK - just don't block
|
||||
|
||||
os.Exit(exitCode)
|
||||
|
||||
case syscall.SIGUSR1:
|
||||
log.Println("[INFO] SIGUSR1: Reloading")
|
||||
go diagnostics.AppendUnique("sigtrap", "SIGUSR1")
|
||||
go telemetry.AppendUnique("sigtrap", "SIGUSR1")
|
||||
|
||||
// Start with the existing Caddyfile
|
||||
caddyfileToUse, inst, err := getCurrentCaddyfile()
|
||||
|
@ -91,14 +91,14 @@ func trapSignalsPosix() {
|
|||
|
||||
case syscall.SIGUSR2:
|
||||
log.Println("[INFO] SIGUSR2: Upgrading")
|
||||
go diagnostics.AppendUnique("sigtrap", "SIGUSR2")
|
||||
go telemetry.AppendUnique("sigtrap", "SIGUSR2")
|
||||
if err := Upgrade(); err != nil {
|
||||
log.Printf("[ERROR] SIGUSR2: upgrading: %v", err)
|
||||
}
|
||||
|
||||
case syscall.SIGHUP:
|
||||
// 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
|
||||
// limitations under the License.
|
||||
|
||||
package diagnostics
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
@ -139,7 +139,7 @@ func Append(key string, value interface{}) {
|
|||
sliceVal, sliceOk := bufVal.([]interface{})
|
||||
if inBuffer && !sliceOk {
|
||||
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
|
||||
}
|
||||
if sliceVal == nil {
|
||||
|
@ -169,7 +169,7 @@ func AppendUnique(key string, value interface{}) {
|
|||
setVal, setOk := bufVal.(countingSet)
|
||||
if inBuffer && !setOk {
|
||||
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
|
||||
}
|
||||
if setVal == nil {
|
||||
|
@ -212,7 +212,7 @@ func atomicAdd(key string, amount int) {
|
|||
intVal, intOk := bufVal.(int)
|
||||
if inBuffer && !intOk {
|
||||
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
|
||||
}
|
||||
if !inBuffer {
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package diagnostics
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -12,26 +12,25 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// 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
|
||||
// unless otherwise specified. For convenience, most functions here do
|
||||
// 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
|
||||
// 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),
|
||||
// it may be desirable and even recommended to invoke them in a new
|
||||
// goroutine (use the go keyword) in case there is lock contention;
|
||||
// they are thread-safe (unless noted), and you may not want them to
|
||||
// block the main thread of execution. However, sometimes blocking
|
||||
// may be necessary too; for example, adding startup metrics to the
|
||||
// buffer before the call to StartEmitting().
|
||||
// goroutine in case there is lock contention; they are thread-safe (unless
|
||||
// noted), and you may not want them to block the main thread of execution.
|
||||
// However, sometimes blocking may be necessary too; for example, adding
|
||||
// startup metrics to the buffer before the call to StartEmitting().
|
||||
//
|
||||
// This package is designed to be as fast and space-efficient as reasonably
|
||||
// possible, so that it does not disrupt the flow of execution.
|
||||
package diagnostics
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -53,17 +52,17 @@ import (
|
|||
func logEmit(final bool) {
|
||||
err := emit(final)
|
||||
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.
|
||||
// If final is true, no future updates will be scheduled.
|
||||
// Otherwise, the next update will be scheduled.
|
||||
func emit(final bool) error {
|
||||
if !enabled {
|
||||
return fmt.Errorf("diagnostics not enabled")
|
||||
return fmt.Errorf("telemetry not enabled")
|
||||
}
|
||||
|
||||
// ensure only one update happens at a time;
|
||||
|
@ -71,7 +70,7 @@ func emit(final bool) error {
|
|||
updateMu.Lock()
|
||||
if updating {
|
||||
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
|
||||
}
|
||||
updating = true
|
||||
|
@ -100,7 +99,7 @@ func emit(final bool) error {
|
|||
if i > 0 && err != nil {
|
||||
// don't hammer the server; first failure might have been
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
@ -114,7 +113,7 @@ func emit(final bool) error {
|
|||
// check for any special-case response codes
|
||||
if resp.StatusCode == http.StatusGone {
|
||||
// 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 != "" {
|
||||
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
|
@ -128,7 +127,7 @@ func emit(final bool) error {
|
|||
}
|
||||
if resp.StatusCode == http.StatusUnavailableForLegalReasons {
|
||||
// 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 != "" {
|
||||
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
|
@ -144,7 +143,7 @@ func emit(final bool) error {
|
|||
// okay, ensure we can interpret the response
|
||||
if ct := resp.Header.Get("Content-Type"); (resp.StatusCode < 300 || resp.StatusCode >= 400) &&
|
||||
!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()
|
||||
continue
|
||||
}
|
||||
|
@ -167,12 +166,12 @@ func emit(final bool) error {
|
|||
}
|
||||
}
|
||||
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)
|
||||
continue
|
||||
}
|
||||
} 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
|
||||
}
|
||||
|
||||
|
@ -181,14 +180,14 @@ func emit(final bool) error {
|
|||
if err == nil && !final {
|
||||
// (remember, if there was an error, we return it
|
||||
// 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
|
||||
// schedule the next update using our default update
|
||||
// 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 {
|
||||
reply.NextUpdate = defaultUpdateInterval
|
||||
}
|
||||
|
@ -247,13 +246,13 @@ func resetBuffer() map[string]interface{} {
|
|||
}
|
||||
|
||||
// Response contains the body of a response from the
|
||||
// diagnostics server.
|
||||
// telemetry server.
|
||||
type Response struct {
|
||||
// NextUpdate is how long to wait before the next update.
|
||||
NextUpdate time.Duration `json:"next_update"`
|
||||
|
||||
// Stop instructs the diagnostics server to stop sending
|
||||
// diagnostics. This would only be done under extenuating
|
||||
// Stop instructs the telemetry server to stop sending
|
||||
// telemetry. This would only be done under extenuating
|
||||
// circumstances, but we are prepared for it nonetheless.
|
||||
Stop bool `json:"stop,omitempty"`
|
||||
|
||||
|
@ -262,7 +261,7 @@ type Response struct {
|
|||
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 {
|
||||
// The universally unique ID of the instance
|
||||
InstanceID string `json:"instance_id"`
|
||||
|
@ -337,7 +336,7 @@ var (
|
|||
updateTimerMu sync.Mutex
|
||||
|
||||
// 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.
|
||||
instanceUUID uuid.UUID
|
||||
|
||||
|
@ -352,12 +351,12 @@ var (
|
|||
)
|
||||
|
||||
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.
|
||||
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
|
||||
// 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
|
||||
// doesn't send one at all, or if a connection can't be made,
|
||||
// likely indicating a problem with the server. Thus, this
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package diagnostics
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"encoding/json"
|
Loading…
Reference in a new issue