mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	diagnostics: AppendUnique(), restructure sets, add metrics, fix bugs
This commit is contained in:
		
							parent
							
								
									703cf7bf8b
								
							
						
					
					
						commit
						6b3c2212a1
					
				
							
								
								
									
										3
									
								
								caddy.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								caddy.go
									
									
									
									
									
								
							@ -44,6 +44,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/mholt/caddy/caddyfile"
 | 
						"github.com/mholt/caddy/caddyfile"
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configurable application parameters
 | 
					// Configurable application parameters
 | 
				
			||||||
@ -573,6 +574,8 @@ func ValidateAndExecuteDirectives(cdyfile Input, inst *Instance, justValidate bo
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						diagnostics.Set("num_server_blocks", len(sblocks))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate)
 | 
						return executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -152,18 +152,18 @@ func Run() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Begin diagnostics (these are no-ops if diagnostics disabled)
 | 
						// Begin diagnostics (these are no-ops if diagnostics disabled)
 | 
				
			||||||
	diagnostics.Set("caddy_version", appVersion)
 | 
						diagnostics.Set("caddy_version", appVersion)
 | 
				
			||||||
	// TODO: plugins
 | 
					 | 
				
			||||||
	diagnostics.Set("num_listeners", len(instance.Servers()))
 | 
						diagnostics.Set("num_listeners", len(instance.Servers()))
 | 
				
			||||||
 | 
						diagnostics.Set("server_type", serverType)
 | 
				
			||||||
	diagnostics.Set("os", runtime.GOOS)
 | 
						diagnostics.Set("os", runtime.GOOS)
 | 
				
			||||||
	diagnostics.Set("arch", runtime.GOARCH)
 | 
						diagnostics.Set("arch", runtime.GOARCH)
 | 
				
			||||||
	diagnostics.Set("cpu", struct {
 | 
						diagnostics.Set("cpu", struct {
 | 
				
			||||||
		NumLogical int    `json:"num_logical"`
 | 
							BrandName  string `json:"brand_name,omitempty"`
 | 
				
			||||||
		AESNI      bool   `json:"aes_ni"`
 | 
							NumLogical int    `json:"num_logical,omitempty"`
 | 
				
			||||||
		BrandName  string `json:"brand_name"`
 | 
							AESNI      bool   `json:"aes_ni,omitempty"`
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
 | 
							BrandName:  cpuid.CPU.BrandName,
 | 
				
			||||||
		NumLogical: runtime.NumCPU(),
 | 
							NumLogical: runtime.NumCPU(),
 | 
				
			||||||
		AESNI:      cpuid.CPU.AesNi(),
 | 
							AESNI:      cpuid.CPU.AesNi(),
 | 
				
			||||||
		BrandName:  cpuid.CPU.BrandName,
 | 
					 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	diagnostics.StartEmitting()
 | 
						diagnostics.StartEmitting()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,8 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parse parses the input just enough to group tokens, in
 | 
					// Parse parses the input just enough to group tokens, in
 | 
				
			||||||
@ -369,6 +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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for p.Next() {
 | 
						for p.Next() {
 | 
				
			||||||
		if p.Val() == "{" {
 | 
							if p.Val() == "{" {
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,8 @@ import (
 | 
				
			|||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// tlsHandler is a http.Handler that will inject a value
 | 
					// tlsHandler is a http.Handler that will inject a value
 | 
				
			||||||
@ -97,6 +99,13 @@ 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 {
 | 
				
			||||||
 | 
								go diagnostics.AppendUnique("mitm", "likely")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								go diagnostics.AppendUnique("mitm", "unlikely")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							go diagnostics.AppendUnique("mitm", "unknown")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if mitm && h.closeOnMITM {
 | 
						if mitm && h.closeOnMITM {
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,6 @@ 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"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const serverType = "http"
 | 
					const serverType = "http"
 | 
				
			||||||
@ -206,8 +205,6 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	diagnostics.Set("num_sites", len(h.siteConfigs))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// we must map (group) each config to a bind address
 | 
						// we must map (group) each config to a bind address
 | 
				
			||||||
	groups, err := groupSiteConfigsByListenAddr(h.siteConfigs)
 | 
						groups, err := groupSiteConfigsByListenAddr(h.siteConfigs)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
				
			|||||||
@ -346,7 +346,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go diagnostics.AppendUniqueString("user_agent", r.Header.Get("User-Agent"))
 | 
						go diagnostics.AppendUnique("user_agent", r.Header.Get("User-Agent"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 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
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,8 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"sync/atomic"
 | 
						"sync/atomic"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// configGroup is a type that keys configs by their hostname
 | 
					// configGroup is a type that keys configs by their hostname
 | 
				
			||||||
@ -98,6 +100,23 @@ func (cg configGroup) GetConfigForClient(clientHello *tls.ClientHelloInfo) (*tls
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// This method is safe for use as a tls.Config.GetCertificate callback.
 | 
					// This method is safe for use as a tls.Config.GetCertificate callback.
 | 
				
			||||||
func (cfg *Config) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
 | 
					func (cfg *Config) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
 | 
				
			||||||
 | 
						go diagnostics.Append("client_hello", struct {
 | 
				
			||||||
 | 
							NoSNI             bool                  `json:"no_sni,omitempty"`
 | 
				
			||||||
 | 
							CipherSuites      []uint16              `json:"cipher_suites,omitempty"`
 | 
				
			||||||
 | 
							SupportedCurves   []tls.CurveID         `json:"curves,omitempty"`
 | 
				
			||||||
 | 
							SupportedPoints   []uint8               `json:"points,omitempty"`
 | 
				
			||||||
 | 
							SignatureSchemes  []tls.SignatureScheme `json:"sig_scheme,omitempty"`
 | 
				
			||||||
 | 
							ALPN              []string              `json:"alpn,omitempty"`
 | 
				
			||||||
 | 
							SupportedVersions []uint16              `json:"versions,omitempty"`
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							NoSNI:             clientHello.ServerName == "",
 | 
				
			||||||
 | 
							CipherSuites:      clientHello.CipherSuites,
 | 
				
			||||||
 | 
							SupportedCurves:   clientHello.SupportedCurves,
 | 
				
			||||||
 | 
							SupportedPoints:   clientHello.SupportedPoints,
 | 
				
			||||||
 | 
							SignatureSchemes:  clientHello.SignatureSchemes,
 | 
				
			||||||
 | 
							ALPN:              clientHello.SupportedProtos,
 | 
				
			||||||
 | 
							SupportedVersions: clientHello.SupportedVersions,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
	cert, err := cfg.getCertDuringHandshake(strings.ToLower(clientHello.ServerName), true, true)
 | 
						cert, err := cfg.getCertDuringHandshake(strings.ToLower(clientHello.ServerName), true, true)
 | 
				
			||||||
	return &cert.Certificate, err
 | 
						return &cert.Certificate, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -113,7 +113,7 @@ func Set(key string, val interface{}) {
 | 
				
			|||||||
// Append appends value to a list named key.
 | 
					// Append appends value to a list named key.
 | 
				
			||||||
// If key is new, a new list will be created.
 | 
					// If key is new, a new list will be created.
 | 
				
			||||||
// If key maps to a type that is not a list,
 | 
					// If key maps to a type that is not a list,
 | 
				
			||||||
// an error is logged, and this is a no-op.
 | 
					// a panic is logged, and this is a no-op.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// TODO: is this function needed/useful?
 | 
					// TODO: is this function needed/useful?
 | 
				
			||||||
func Append(key string, value interface{}) {
 | 
					func Append(key string, value interface{}) {
 | 
				
			||||||
@ -142,66 +142,38 @@ func Append(key string, value interface{}) {
 | 
				
			|||||||
	bufferMu.Unlock()
 | 
						bufferMu.Unlock()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AppendUniqueString adds value to a set named key.
 | 
					// AppendUnique adds value to a set  namedkey.
 | 
				
			||||||
// Set items are unordered. Values in the set
 | 
					// Set items are unordered. Values in the set
 | 
				
			||||||
// are unique, but repeat values are counted.
 | 
					// are unique, but how many times they are
 | 
				
			||||||
 | 
					// appended is counted.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// If key is new, a new set will be created.
 | 
					// If key is new, a new set will be created for
 | 
				
			||||||
// If key maps to a type that is not a string
 | 
					// values with that key. If key maps to a type
 | 
				
			||||||
// set, an error is logged, and this is a no-op.
 | 
					// that is not a counting set, a panic is logged,
 | 
				
			||||||
func AppendUniqueString(key, value string) {
 | 
					// and this is a no-op.
 | 
				
			||||||
 | 
					func AppendUnique(key string, value interface{}) {
 | 
				
			||||||
	if !enabled {
 | 
						if !enabled {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bufferMu.Lock()
 | 
						bufferMu.Lock()
 | 
				
			||||||
	if bufferItemCount >= maxBufferItems {
 | 
					 | 
				
			||||||
		bufferMu.Unlock()
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	bufVal, inBuffer := buffer[key]
 | 
						bufVal, inBuffer := buffer[key]
 | 
				
			||||||
	mapVal, mapOk := bufVal.(map[string]int)
 | 
						setVal, setOk := bufVal.(countingSet)
 | 
				
			||||||
	if inBuffer && !mapOk {
 | 
						if inBuffer && !setOk {
 | 
				
			||||||
		bufferMu.Unlock()
 | 
							bufferMu.Unlock()
 | 
				
			||||||
		log.Printf("[PANIC] Diagnostics: key %s already used for non-map value", key)
 | 
							log.Printf("[PANIC] Diagnostics: key %s already used for non-counting-set value", key)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if mapVal == nil {
 | 
						if setVal == nil {
 | 
				
			||||||
		buffer[key] = map[string]int{value: 1}
 | 
							// ensure the buffer is not too full, then add new unique value
 | 
				
			||||||
 | 
							if bufferItemCount >= maxBufferItems {
 | 
				
			||||||
 | 
								bufferMu.Unlock()
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							buffer[key] = countingSet{value: 1}
 | 
				
			||||||
		bufferItemCount++
 | 
							bufferItemCount++
 | 
				
			||||||
	} else if mapOk {
 | 
						} else if setOk {
 | 
				
			||||||
		mapVal[value]++
 | 
							// unique value already exists, so just increment counter
 | 
				
			||||||
	}
 | 
							setVal[value]++
 | 
				
			||||||
	bufferMu.Unlock()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// AppendUniqueInt adds value to a set named key.
 | 
					 | 
				
			||||||
// Set items are unordered. Values in the set
 | 
					 | 
				
			||||||
// are unique, but repeat values are counted.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// If key is new, a new set will be created.
 | 
					 | 
				
			||||||
// If key maps to a type that is not an integer
 | 
					 | 
				
			||||||
// set, an error is logged, and this is a no-op.
 | 
					 | 
				
			||||||
func AppendUniqueInt(key string, value int) {
 | 
					 | 
				
			||||||
	if !enabled {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	bufferMu.Lock()
 | 
					 | 
				
			||||||
	if bufferItemCount >= maxBufferItems {
 | 
					 | 
				
			||||||
		bufferMu.Unlock()
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	bufVal, inBuffer := buffer[key]
 | 
					 | 
				
			||||||
	mapVal, mapOk := bufVal.(map[int]int)
 | 
					 | 
				
			||||||
	if inBuffer && !mapOk {
 | 
					 | 
				
			||||||
		bufferMu.Unlock()
 | 
					 | 
				
			||||||
		log.Printf("[PANIC] Diagnostics: key %s already used for non-map value", key)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if mapVal == nil {
 | 
					 | 
				
			||||||
		buffer[key] = map[int]int{value: 1}
 | 
					 | 
				
			||||||
		bufferItemCount++
 | 
					 | 
				
			||||||
	} else if mapOk {
 | 
					 | 
				
			||||||
		mapVal[value]++
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bufferMu.Unlock()
 | 
						bufferMu.Unlock()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -209,7 +181,7 @@ func AppendUniqueInt(key string, value int) {
 | 
				
			|||||||
// Increment adds 1 to a value named key.
 | 
					// Increment adds 1 to a value named key.
 | 
				
			||||||
// If it does not exist, it is created with
 | 
					// If it does not exist, it is created with
 | 
				
			||||||
// a value of 1. If key maps to a type that
 | 
					// a value of 1. If key maps to a type that
 | 
				
			||||||
// is not an integer, an error is logged,
 | 
					// is not an integer, a panic is logged,
 | 
				
			||||||
// and this is a no-op.
 | 
					// and this is a no-op.
 | 
				
			||||||
func Increment(key string) {
 | 
					func Increment(key string) {
 | 
				
			||||||
	incrementOrDecrement(key, true)
 | 
						incrementOrDecrement(key, true)
 | 
				
			||||||
 | 
				
			|||||||
@ -21,13 +21,16 @@
 | 
				
			|||||||
// 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 diagnostic updates.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// When collecting metrics (functions like Set, Append*, or Increment),
 | 
					// When collecting metrics (functions like Set, AppendUnique, or Increment),
 | 
				
			||||||
// it may be desirable and even recommended to run 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 (use the go keyword) in case there is lock contention;
 | 
				
			||||||
// they are thread-safe (unless noted), and you may not want them to
 | 
					// they are thread-safe (unless noted), and you may not want them to
 | 
				
			||||||
// block the main thread of execution. However, sometimes blocking
 | 
					// block the main thread of execution. However, sometimes blocking
 | 
				
			||||||
// may be necessary too; for example, adding startup metrics to the
 | 
					// may be necessary too; for example, adding 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
 | 
				
			||||||
 | 
					// possible, so that it does not disrupt the flow of execution.
 | 
				
			||||||
package diagnostics
 | 
					package diagnostics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
@ -122,11 +125,6 @@ func emit(final bool) error {
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// ensure we won't slam the diagnostics server
 | 
					 | 
				
			||||||
		if reply.NextUpdate < 1*time.Second {
 | 
					 | 
				
			||||||
			reply.NextUpdate = defaultUpdateInterval
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// make sure we didn't send the update too soon; if so,
 | 
							// make sure we didn't send the update too soon; if so,
 | 
				
			||||||
		// just wait and try again -- this is a special case of
 | 
							// just wait and try again -- this is a special case of
 | 
				
			||||||
		// error that we handle differently, as you can see
 | 
							// error that we handle differently, as you can see
 | 
				
			||||||
@ -151,6 +149,11 @@ func emit(final bool) error {
 | 
				
			|||||||
	// 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
 | 
				
			||||||
 | 
						if reply.NextUpdate < 1*time.Second {
 | 
				
			||||||
 | 
							reply.NextUpdate = defaultUpdateInterval
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// schedule the next update (if this wasn't the last one and
 | 
						// schedule the next update (if this wasn't the last one and
 | 
				
			||||||
	// if the remote server didn't tell us to stop sending)
 | 
						// if the remote server didn't tell us to stop sending)
 | 
				
			||||||
	if !final && !reply.Stop {
 | 
						if !final && !reply.Stop {
 | 
				
			||||||
@ -216,6 +219,30 @@ type Payload struct {
 | 
				
			|||||||
	Data map[string]interface{} `json:"data,omitempty"`
 | 
						Data map[string]interface{} `json:"data,omitempty"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// countingSet implements a set that counts how many
 | 
				
			||||||
 | 
					// times a key is inserted. It marshals to JSON in a
 | 
				
			||||||
 | 
					// way such that keys are converted to values next
 | 
				
			||||||
 | 
					// to their associated counts.
 | 
				
			||||||
 | 
					type countingSet map[interface{}]int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MarshalJSON implements the json.Marshaler interface.
 | 
				
			||||||
 | 
					// It converts the set to an array so that the values
 | 
				
			||||||
 | 
					// are JSON object values instead of keys, since keys
 | 
				
			||||||
 | 
					// are difficult to query in databases.
 | 
				
			||||||
 | 
					func (s countingSet) MarshalJSON() ([]byte, error) {
 | 
				
			||||||
 | 
						type Item struct {
 | 
				
			||||||
 | 
							Value interface{} `json:"value"`
 | 
				
			||||||
 | 
							Count int         `json:"count"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var list []Item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for k, v := range s {
 | 
				
			||||||
 | 
							list = append(list, Item{Value: k, Count: v})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return json.Marshal(list)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	// httpClient should be used for HTTP requests. It
 | 
						// httpClient should be used for HTTP requests. It
 | 
				
			||||||
	// is configured with a timeout for reliability.
 | 
						// is configured with a timeout for reliability.
 | 
				
			||||||
@ -253,7 +280,7 @@ var (
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	// endpoint is the base URL to remote diagnostics server;
 | 
						// endpoint is the base URL to remote diagnostics 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:8081/update/"
 | 
						endpoint = "https://diagnostics-staging.caddyserver.com/update/" // TODO: make configurable, "http://localhost:8085/update/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// defaultUpdateInterval is how long to wait before emitting
 | 
						// defaultUpdateInterval is how long to wait before emitting
 | 
				
			||||||
	// more diagnostic data. This value is only used if the
 | 
						// more diagnostic data. This value is only used if the
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										57
									
								
								plugins.go
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								plugins.go
									
									
									
									
									
								
							@ -53,29 +53,59 @@ var (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DescribePlugins returns a string describing the registered plugins.
 | 
					// DescribePlugins returns a string describing the registered plugins.
 | 
				
			||||||
func DescribePlugins() string {
 | 
					func DescribePlugins() string {
 | 
				
			||||||
 | 
						pl := ListPlugins()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	str := "Server types:\n"
 | 
						str := "Server types:\n"
 | 
				
			||||||
	for name := range serverTypes {
 | 
						for _, name := range pl["server_types"] {
 | 
				
			||||||
		str += "  " + name + "\n"
 | 
							str += "  " + name + "\n"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// List the loaders in registration order
 | 
					 | 
				
			||||||
	str += "\nCaddyfile loaders:\n"
 | 
						str += "\nCaddyfile loaders:\n"
 | 
				
			||||||
	for _, loader := range caddyfileLoaders {
 | 
						for _, name := range pl["caddyfile_loaders"] {
 | 
				
			||||||
		str += "  " + loader.name + "\n"
 | 
							str += "  " + name + "\n"
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if defaultCaddyfileLoader.name != "" {
 | 
					 | 
				
			||||||
		str += "  " + defaultCaddyfileLoader.name + "\n"
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(eventHooks) > 0 {
 | 
						if len(eventHooks) > 0 {
 | 
				
			||||||
		// List the event hook plugins
 | 
					 | 
				
			||||||
		str += "\nEvent hook plugins:\n"
 | 
							str += "\nEvent hook plugins:\n"
 | 
				
			||||||
		for hookPlugin := range eventHooks {
 | 
							for _, name := range pl["event_hooks"] {
 | 
				
			||||||
			str += "  hook." + hookPlugin + "\n"
 | 
								str += "  hook." + name + "\n"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Let's alphabetize the rest of these...
 | 
						str += "\nOther plugins:\n"
 | 
				
			||||||
 | 
						for _, name := range pl["others"] {
 | 
				
			||||||
 | 
							str += "  " + name + "\n"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return str
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListPlugins makes a list of the registered plugins,
 | 
				
			||||||
 | 
					// keyed by plugin type.
 | 
				
			||||||
 | 
					func ListPlugins() map[string][]string {
 | 
				
			||||||
 | 
						p := make(map[string][]string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// server type plugins
 | 
				
			||||||
 | 
						for name := range serverTypes {
 | 
				
			||||||
 | 
							p["server_types"] = append(p["server_types"], name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// caddyfile loaders in registration order
 | 
				
			||||||
 | 
						for _, loader := range caddyfileLoaders {
 | 
				
			||||||
 | 
							p["caddyfile_loaders"] = append(p["caddyfile_loaders"], loader.name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if defaultCaddyfileLoader.name != "" {
 | 
				
			||||||
 | 
							p["caddyfile_loaders"] = append(p["caddyfile_loaders"], defaultCaddyfileLoader.name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// event hook plugins
 | 
				
			||||||
 | 
						if len(eventHooks) > 0 {
 | 
				
			||||||
 | 
							for name := range eventHooks {
 | 
				
			||||||
 | 
								p["event_hooks"] = append(p["event_hooks"], name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// alphabetize the rest of the plugins
 | 
				
			||||||
	var others []string
 | 
						var others []string
 | 
				
			||||||
	for stype, stypePlugins := range plugins {
 | 
						for stype, stypePlugins := range plugins {
 | 
				
			||||||
		for name := range stypePlugins {
 | 
							for name := range stypePlugins {
 | 
				
			||||||
@ -89,12 +119,11 @@ func DescribePlugins() string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sort.Strings(others)
 | 
						sort.Strings(others)
 | 
				
			||||||
	str += "\nOther plugins:\n"
 | 
					 | 
				
			||||||
	for _, name := range others {
 | 
						for _, name := range others {
 | 
				
			||||||
		str += "  " + name + "\n"
 | 
							p["others"] = append(p["others"], name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return str
 | 
						return p
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ValidDirectives returns the list of all directives that are
 | 
					// ValidDirectives returns the list of all directives that are
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user