client_golang/registry.go

145 lines
3.8 KiB
Go
Raw Normal View History

/*
Copyright (c) 2012, Matt T. Proud
All rights reserved.
2012-05-20 01:59:25 +04:00
Use of this source code is governed by a BSD-style license that can be found in
the LICENSE file.
*/
2012-05-20 01:59:25 +04:00
package registry
2012-05-20 01:59:25 +04:00
import (
"encoding/base64"
2012-05-20 01:59:25 +04:00
"encoding/json"
"github.com/matttproud/golang_instrumentation/metrics"
"log"
"net/http"
"strings"
"sync"
"time"
)
const (
authorization = "Authorization"
contentType = "Content-Type"
jsonContentType = "application/json"
jsonSuffix = ".json"
)
/*
This callback accumulates the microsecond duration of the reporting framework's
overhead such that it can be reported.
*/
2012-05-20 01:59:25 +04:00
var requestLatencyAccumulator metrics.CompletionCallback = func(duration time.Duration) {
microseconds := float64(duration / time.Millisecond)
2012-05-20 01:59:25 +04:00
requestLatencyLogarithmicAccumulating.Add(microseconds)
requestLatencyEqualAccumulating.Add(microseconds)
requestLatencyLogarithmicTallying.Add(microseconds)
requestLatencyEqualTallying.Add(microseconds)
2012-05-20 01:59:25 +04:00
}
/*
Registry is, as the name implies, a registrar where metrics are listed.
In most situations, using DefaultRegistry is sufficient versus creating one's
own.
*/
2012-05-20 01:59:25 +04:00
type Registry struct {
mutex sync.RWMutex
NameToMetric map[string]metrics.Metric
}
/*
This builds a new metric registry. It is not needed in the majority of
cases.
*/
2012-05-20 01:59:25 +04:00
func NewRegistry() *Registry {
return &Registry{
NameToMetric: make(map[string]metrics.Metric),
}
}
/*
This is the default registry with which Metric objects are associated. It
is primarily a read-only object after server instantiation.
*/
2012-05-20 01:59:25 +04:00
var DefaultRegistry = NewRegistry()
/*
Associate a Metric with the DefaultRegistry.
*/
func Register(name, unusedDocstring string, unusedBaseLabels map[string]string, metric metrics.Metric) {
DefaultRegistry.Register(name, unusedDocstring, unusedBaseLabels, metric)
2012-05-20 01:59:25 +04:00
}
/*
Register a metric with a given name. Name should be globally unique.
*/
func (r *Registry) Register(name, unusedDocstring string, unusedBaseLabels map[string]string, metric metrics.Metric) {
2012-05-20 01:59:25 +04:00
r.mutex.Lock()
defer r.mutex.Unlock()
if _, present := r.NameToMetric[name]; !present {
r.NameToMetric[name] = metric
log.Printf("Registered %s.\n", name)
} else {
log.Printf("Attempted to register duplicate %s metric.\n", name)
}
}
func (register *Registry) YieldBasicAuthExporter(username, password string) http.HandlerFunc {
exporter := register.YieldExporter()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authenticated := false
2013-01-09 15:47:33 +04:00
if auth := r.Header.Get(authorization); auth != "" {
base64Encoded := strings.SplitAfter(auth, " ")[1]
decoded, err := base64.URLEncoding.DecodeString(base64Encoded)
if err == nil {
usernamePassword := strings.Split(string(decoded), ":")
if usernamePassword[0] == username && usernamePassword[1] == password {
authenticated = true
}
}
}
if authenticated {
exporter.ServeHTTP(w, r)
} else {
w.Header().Add("WWW-Authenticate", "Basic")
http.Error(w, "access forbidden", 401)
}
})
}
/*
Create a http.HandlerFunc that is tied to r Registry such that requests
against it generate a representation of the housed metrics.
*/
func (registry *Registry) YieldExporter() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var instrumentable metrics.InstrumentableCall = func() {
requestCount.Increment()
url := r.URL
if strings.HasSuffix(url.Path, jsonSuffix) {
w.Header().Set(contentType, jsonContentType)
composite := make(map[string]interface{}, len(registry.NameToMetric))
for name, metric := range registry.NameToMetric {
composite[name] = metric.Marshallable()
}
data, _ := json.Marshal(composite)
w.Write(data)
} else {
w.WriteHeader(http.StatusNotFound)
}
2012-05-20 01:59:25 +04:00
}
metrics.InstrumentCall(instrumentable, requestLatencyAccumulator)
2012-05-20 01:59:25 +04:00
}
}