mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 13:49:58 +00:00
TUN-528: Move cloudflared into a separate repo
This commit is contained in:
307
vendor/github.com/mholt/caddy/telemetry/collection.go
generated
vendored
Normal file
307
vendor/github.com/mholt/caddy/telemetry/collection.go
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Init initializes this package so that it may
|
||||
// be used. Do not call this function more than
|
||||
// once. Init panics if it is called more than
|
||||
// once or if the UUID value is empty. Once this
|
||||
// function is called, the rest of the package
|
||||
// may safely be used. If this function is not
|
||||
// called, the collector functions may still be
|
||||
// invoked, but they will be no-ops.
|
||||
//
|
||||
// Any metrics keys that are passed in the second
|
||||
// argument will be permanently disabled for the
|
||||
// lifetime of the process.
|
||||
func Init(instanceID uuid.UUID, disabledMetricsKeys []string) {
|
||||
if enabled {
|
||||
panic("already initialized")
|
||||
}
|
||||
if str := instanceID.String(); str == "" ||
|
||||
str == "00000000-0000-0000-0000-000000000000" {
|
||||
panic("empty UUID")
|
||||
}
|
||||
instanceUUID = instanceID
|
||||
disabledMetricsMu.Lock()
|
||||
for _, key := range disabledMetricsKeys {
|
||||
disabledMetrics[strings.TrimSpace(key)] = false
|
||||
}
|
||||
disabledMetricsMu.Unlock()
|
||||
enabled = true
|
||||
}
|
||||
|
||||
// StartEmitting sends the current payload and begins the
|
||||
// transmission cycle for updates. This is the first
|
||||
// update sent, and future ones will be sent until
|
||||
// StopEmitting is called.
|
||||
//
|
||||
// This function is non-blocking (it spawns a new goroutine).
|
||||
//
|
||||
// This function panics if it was called more than once.
|
||||
// It is a no-op if this package was not initialized.
|
||||
func StartEmitting() {
|
||||
if !enabled {
|
||||
return
|
||||
}
|
||||
updateTimerMu.Lock()
|
||||
if updateTimer != nil {
|
||||
updateTimerMu.Unlock()
|
||||
panic("updates already started")
|
||||
}
|
||||
updateTimerMu.Unlock()
|
||||
updateMu.Lock()
|
||||
if updating {
|
||||
updateMu.Unlock()
|
||||
panic("update already in progress")
|
||||
}
|
||||
updateMu.Unlock()
|
||||
go logEmit(false)
|
||||
}
|
||||
|
||||
// StopEmitting sends the current payload and terminates
|
||||
// the update cycle. No more updates will be sent.
|
||||
//
|
||||
// It is a no-op if the package was never initialized
|
||||
// or if emitting was never started.
|
||||
//
|
||||
// NOTE: This function is blocking. Run in a goroutine if
|
||||
// you want to guarantee no blocking at critical times
|
||||
// like exiting the program.
|
||||
func StopEmitting() {
|
||||
if !enabled {
|
||||
return
|
||||
}
|
||||
updateTimerMu.Lock()
|
||||
if updateTimer == nil {
|
||||
updateTimerMu.Unlock()
|
||||
return
|
||||
}
|
||||
updateTimerMu.Unlock()
|
||||
logEmit(true) // likely too early; may take minutes to return
|
||||
}
|
||||
|
||||
// Reset empties the current payload buffer.
|
||||
func Reset() {
|
||||
resetBuffer()
|
||||
}
|
||||
|
||||
// Set puts a value in the buffer to be included
|
||||
// in the next emission. It overwrites any
|
||||
// previous value.
|
||||
//
|
||||
// This function is safe for multiple goroutines,
|
||||
// and it is recommended to call this using the
|
||||
// go keyword after the call to SendHello so it
|
||||
// doesn't block crucial code.
|
||||
func Set(key string, val interface{}) {
|
||||
if !enabled || isDisabled(key) {
|
||||
return
|
||||
}
|
||||
bufferMu.Lock()
|
||||
if _, ok := buffer[key]; !ok {
|
||||
if bufferItemCount >= maxBufferItems {
|
||||
bufferMu.Unlock()
|
||||
return
|
||||
}
|
||||
bufferItemCount++
|
||||
}
|
||||
buffer[key] = val
|
||||
bufferMu.Unlock()
|
||||
}
|
||||
|
||||
// SetNested puts a value in the buffer to be included
|
||||
// in the next emission, nested under the top-level key
|
||||
// as subkey. It overwrites any previous value.
|
||||
//
|
||||
// This function is safe for multiple goroutines,
|
||||
// and it is recommended to call this using the
|
||||
// go keyword after the call to SendHello so it
|
||||
// doesn't block crucial code.
|
||||
func SetNested(key, subkey string, val interface{}) {
|
||||
if !enabled || isDisabled(key) {
|
||||
return
|
||||
}
|
||||
bufferMu.Lock()
|
||||
if topLevel, ok1 := buffer[key]; ok1 {
|
||||
topLevelMap, ok2 := topLevel.(map[string]interface{})
|
||||
if !ok2 {
|
||||
bufferMu.Unlock()
|
||||
log.Printf("[PANIC] Telemetry: key %s is already used for non-nested-map value", key)
|
||||
return
|
||||
}
|
||||
if _, ok3 := topLevelMap[subkey]; !ok3 {
|
||||
// don't exceed max buffer size
|
||||
if bufferItemCount >= maxBufferItems {
|
||||
bufferMu.Unlock()
|
||||
return
|
||||
}
|
||||
bufferItemCount++
|
||||
}
|
||||
topLevelMap[subkey] = val
|
||||
} else {
|
||||
// don't exceed max buffer size
|
||||
if bufferItemCount >= maxBufferItems {
|
||||
bufferMu.Unlock()
|
||||
return
|
||||
}
|
||||
bufferItemCount++
|
||||
buffer[key] = map[string]interface{}{subkey: val}
|
||||
}
|
||||
bufferMu.Unlock()
|
||||
}
|
||||
|
||||
// Append appends value to a list named key.
|
||||
// If key is new, a new list will be created.
|
||||
// If key maps to a type that is not a list,
|
||||
// a panic is logged, and this is a no-op.
|
||||
func Append(key string, value interface{}) {
|
||||
if !enabled || isDisabled(key) {
|
||||
return
|
||||
}
|
||||
bufferMu.Lock()
|
||||
if bufferItemCount >= maxBufferItems {
|
||||
bufferMu.Unlock()
|
||||
return
|
||||
}
|
||||
// TODO: Test this...
|
||||
bufVal, inBuffer := buffer[key]
|
||||
sliceVal, sliceOk := bufVal.([]interface{})
|
||||
if inBuffer && !sliceOk {
|
||||
bufferMu.Unlock()
|
||||
log.Printf("[PANIC] Telemetry: key %s already used for non-slice value", key)
|
||||
return
|
||||
}
|
||||
if sliceVal == nil {
|
||||
buffer[key] = []interface{}{value}
|
||||
} else if sliceOk {
|
||||
buffer[key] = append(sliceVal, value)
|
||||
}
|
||||
bufferItemCount++
|
||||
bufferMu.Unlock()
|
||||
}
|
||||
|
||||
// AppendUnique adds value to a set named key.
|
||||
// Set items are unordered. Values in the set
|
||||
// are unique, but how many times they are
|
||||
// appended is counted. The value must be
|
||||
// hashable.
|
||||
//
|
||||
// If key is new, a new set will be created for
|
||||
// values with that key. If key maps to a type
|
||||
// that is not a counting set, a panic is logged,
|
||||
// and this is a no-op.
|
||||
func AppendUnique(key string, value interface{}) {
|
||||
if !enabled || isDisabled(key) {
|
||||
return
|
||||
}
|
||||
bufferMu.Lock()
|
||||
bufVal, inBuffer := buffer[key]
|
||||
setVal, setOk := bufVal.(countingSet)
|
||||
if inBuffer && !setOk {
|
||||
bufferMu.Unlock()
|
||||
log.Printf("[PANIC] Telemetry: key %s already used for non-counting-set value", key)
|
||||
return
|
||||
}
|
||||
if setVal == nil {
|
||||
// ensure the buffer is not too full, then add new unique value
|
||||
if bufferItemCount >= maxBufferItems {
|
||||
bufferMu.Unlock()
|
||||
return
|
||||
}
|
||||
buffer[key] = countingSet{value: 1}
|
||||
bufferItemCount++
|
||||
} else if setOk {
|
||||
// unique value already exists, so just increment counter
|
||||
setVal[value]++
|
||||
}
|
||||
bufferMu.Unlock()
|
||||
}
|
||||
|
||||
// Add adds amount to a value named key.
|
||||
// If it does not exist, it is created with
|
||||
// a value of 1. If key maps to a type that
|
||||
// is not an integer, a panic is logged,
|
||||
// and this is a no-op.
|
||||
func Add(key string, amount int) {
|
||||
atomicAdd(key, amount)
|
||||
}
|
||||
|
||||
// Increment is a shortcut for Add(key, 1)
|
||||
func Increment(key string) {
|
||||
atomicAdd(key, 1)
|
||||
}
|
||||
|
||||
// atomicAdd adds amount (negative to subtract)
|
||||
// to key.
|
||||
func atomicAdd(key string, amount int) {
|
||||
if !enabled || isDisabled(key) {
|
||||
return
|
||||
}
|
||||
bufferMu.Lock()
|
||||
bufVal, inBuffer := buffer[key]
|
||||
intVal, intOk := bufVal.(int)
|
||||
if inBuffer && !intOk {
|
||||
bufferMu.Unlock()
|
||||
log.Printf("[PANIC] Telemetry: key %s already used for non-integer value", key)
|
||||
return
|
||||
}
|
||||
if !inBuffer {
|
||||
if bufferItemCount >= maxBufferItems {
|
||||
bufferMu.Unlock()
|
||||
return
|
||||
}
|
||||
bufferItemCount++
|
||||
}
|
||||
buffer[key] = intVal + amount
|
||||
bufferMu.Unlock()
|
||||
}
|
||||
|
||||
// FastHash hashes input using a 32-bit hashing algorithm
|
||||
// that is fast, and returns the hash as a hex-encoded string.
|
||||
// Do not use this for cryptographic purposes.
|
||||
func FastHash(input []byte) string {
|
||||
h := fnv.New32a()
|
||||
h.Write(input)
|
||||
return fmt.Sprintf("%x", h.Sum32())
|
||||
}
|
||||
|
||||
// isDisabled returns whether key is
|
||||
// a disabled metric key. ALL collection
|
||||
// functions should call this and not
|
||||
// save the value if this returns true.
|
||||
func isDisabled(key string) bool {
|
||||
// for keys that are augmented with data, such as
|
||||
// "tls_client_hello_ua:<hash>", just
|
||||
// check the prefix "tls_client_hello_ua"
|
||||
checkKey := key
|
||||
if idx := strings.Index(key, ":"); idx > -1 {
|
||||
checkKey = key[:idx]
|
||||
}
|
||||
|
||||
disabledMetricsMu.RLock()
|
||||
_, ok := disabledMetrics[checkKey]
|
||||
disabledMetricsMu.RUnlock()
|
||||
return ok
|
||||
}
|
Reference in New Issue
Block a user