omhttp

package
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 21, 2023 License: Apache-2.0 Imports: 10 Imported by: 1

README

OpenMetrics HTTP

Go Reference

The omhttp package provides HTTP-related convenience helpers.

Examples

To expose metrics on an HTTP server endpoint:

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/bsm/openmetrics"
	"github.com/bsm/openmetrics/omhttp"
)

func main() {
	// Create test registry and register instrument.
	reg := openmetrics.NewConsistentRegistry(mockNow)
	httpRequests := reg.Counter(openmetrics.Desc{
		Name:	"http_requests",
		Labels:	[]string{"path", "status"},
	})

	// Create a mock http.ServeMux and mount a metrics route.
	mux := http.NewServeMux()
	mux.Handle("/metrics", omhttp.NewHandler(reg))

	// Record a mock request.
	httpRequests.With("/home", "200").Add(1)

	// GET /metrics endpoint.
	w := httptest.NewRecorder()
	mux.ServeHTTP(w, httptest.NewRequest("GET", "/metrics", nil))
	fmt.Print(w.Body.String())

}

To instrument HTTP servers:

package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"strconv"
	"time"

	"github.com/bsm/openmetrics"
	"github.com/bsm/openmetrics/omhttp"
)

func main() {
	reg := openmetrics.NewConsistentRegistry(mockNow)

	// Register metrics.
	httpRequests := reg.Counter(openmetrics.Desc{
		Name:	"http_requests",
		Labels:	[]string{"path", "status"},
	})
	httpRequestBytes := reg.Counter(openmetrics.Desc{
		Name:	"http_requests",
		Unit:	"bytes",
		Labels:	[]string{"path", "status"},
	})
	httpRequestTimes := reg.Histogram(openmetrics.Desc{
		Name:	"http_requests",
		Unit:	"seconds",
		Labels:	[]string{"path", "status"},
	}, .1, .2, 0.5, 1)

	// Create a mock http.ServeMux with two routes.
	mux := http.NewServeMux()
	mux.HandleFunc("/home", func(w http.ResponseWriter, _ *http.Request) { io.WriteString(w, "Welcome Home!") })
	mux.HandleFunc("/about", func(w http.ResponseWriter, _ *http.Request) { io.WriteString(w, "What's this about?") })

	// Init the instrumentation middleware.
	middleware := omhttp.Instrument(func(req *http.Request, status, bytes int, elapsed time.Duration) {
		statusString := strconv.Itoa(status)

		// replace elapsed with fixed values for consistent test output
		if req.RemoteAddr == "192.0.2.1:1234" {
			elapsed = 187 * time.Millisecond
		}

		httpRequests.With(req.URL.Path, statusString).Add(1)
		httpRequestBytes.With(req.URL.Path, statusString).Add(float64(bytes))
		httpRequestTimes.With(req.URL.Path, statusString).Observe(elapsed.Seconds())
	})

	// Serve two requests.
	handler := middleware(mux)
	handler.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/home", nil))
	handler.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/missing", nil))

	// Write out buffer.
	buf := new(bytes.Buffer)
	if _, err := reg.WriteTo(buf); err != nil {
		panic(err)
	}
	fmt.Print(buf.String())

}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultHandler

func DefaultHandler(opts ...HandlerOption) http.Handler

DefaultHandler is a short-cut for NewHandler(openmetrics.DefaultRegistry(), opts...).

func Instrument

func Instrument(fn InstrumentFunc) func(http.Handler) http.Handler

Instrument returns request instrumentation a middleware.

Example
reg := openmetrics.NewConsistentRegistry(mockNow)

// Register metrics.
httpRequests := reg.Counter(openmetrics.Desc{
	Name:   "http_requests",
	Labels: []string{"path", "status"},
})
httpRequestBytes := reg.Counter(openmetrics.Desc{
	Name:   "http_requests",
	Unit:   "bytes",
	Labels: []string{"path", "status"},
})
httpRequestTimes := reg.Histogram(openmetrics.Desc{
	Name:   "http_requests",
	Unit:   "seconds",
	Labels: []string{"path", "status"},
}, []float64{.1, .2, 0.5, 1})

// Create a mock http.ServeMux with two routes.
mux := http.NewServeMux()
mux.HandleFunc("/home", func(w http.ResponseWriter, _ *http.Request) { _, _ = io.WriteString(w, "Welcome Home!") })
mux.HandleFunc("/about", func(w http.ResponseWriter, _ *http.Request) { _, _ = io.WriteString(w, "What's this about?") })

// Init the instrumentation middleware.
middleware := omhttp.Instrument(func(req *http.Request, status, bytes int, elapsed time.Duration) {
	statusString := strconv.Itoa(status)

	// replace elapsed with fixed values for consistent test output
	if req.RemoteAddr == "192.0.2.1:1234" {
		elapsed = 187 * time.Millisecond
	}

	httpRequests.With(req.URL.Path, statusString).Add(1)
	httpRequestBytes.With(req.URL.Path, statusString).Add(float64(bytes))
	httpRequestTimes.With(req.URL.Path, statusString).Observe(elapsed.Seconds())
})

// Serve two requests.
handler := middleware(mux)
handler.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/home", nil))
handler.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/missing", nil))

// Write out buffer.
buf := new(bytes.Buffer)
if _, err := reg.WriteTo(buf); err != nil {
	panic(err)
}
fmt.Print(buf.String())
Output:

# TYPE http_requests counter
http_requests_total{path="/missing",status="404"} 1
http_requests_created{path="/missing",status="404"} 1515151515.757576
http_requests_total{path="/home",status="200"} 1
http_requests_created{path="/home",status="200"} 1515151515.757576
# TYPE http_requests_bytes counter
# UNIT http_requests_bytes bytes
http_requests_bytes_total{path="/missing",status="404"} 19
http_requests_bytes_created{path="/missing",status="404"} 1515151515.757576
http_requests_bytes_total{path="/home",status="200"} 13
http_requests_bytes_created{path="/home",status="200"} 1515151515.757576
# TYPE http_requests_seconds histogram
# UNIT http_requests_seconds seconds
http_requests_seconds_bucket{path="/missing",status="404",le="0.1"} 0
http_requests_seconds_bucket{path="/missing",status="404",le="0.2"} 1
http_requests_seconds_bucket{path="/missing",status="404",le="0.5"} 1
http_requests_seconds_bucket{path="/missing",status="404",le="1"} 1
http_requests_seconds_bucket{path="/missing",status="404",le="+Inf"} 1
http_requests_seconds_count{path="/missing",status="404"} 1
http_requests_seconds_sum{path="/missing",status="404"} 0.187
http_requests_seconds_created{path="/missing",status="404"} 1515151515.757576
http_requests_seconds_bucket{path="/home",status="200",le="0.1"} 0
http_requests_seconds_bucket{path="/home",status="200",le="0.2"} 1
http_requests_seconds_bucket{path="/home",status="200",le="0.5"} 1
http_requests_seconds_bucket{path="/home",status="200",le="1"} 1
http_requests_seconds_bucket{path="/home",status="200",le="+Inf"} 1
http_requests_seconds_count{path="/home",status="200"} 1
http_requests_seconds_sum{path="/home",status="200"} 0.187
http_requests_seconds_created{path="/home",status="200"} 1515151515.757576
# EOF

func NewHandler

func NewHandler(reg *openmetrics.Registry, opts ...HandlerOption) http.Handler

NewHandler inits a new handler.

Example
// Create test registry and register instrument.
reg := openmetrics.NewConsistentRegistry(mockNow)
httpRequests := reg.Counter(openmetrics.Desc{
	Name:   "http_requests",
	Labels: []string{"path", "status"},
})

// Create a mock http.ServeMux and mount a metrics route.
mux := http.NewServeMux()
mux.Handle("/metrics", omhttp.NewHandler(reg))

// Record a mock request.
httpRequests.With("/home", "200").Add(1)

// GET /metrics endpoint.
w := httptest.NewRecorder()
mux.ServeHTTP(w, httptest.NewRequest("GET", "/metrics", nil))
fmt.Print(w.Body.String())
Output:

# TYPE http_requests counter
http_requests_total{path="/home",status="200"} 1
http_requests_created{path="/home",status="200"} 1515151515.757576
# EOF

Types

type HandlerOption

type HandlerOption interface {
	// contains filtered or unexported methods
}

A HandlerOption configures the handler.

func LimitConcurrency

func LimitConcurrency(n int) HandlerOption

LimitConcurrency limits the number of concurrent requests that can be made to the handler. The endpoint will start responding with 503 Service Unavailable once this limit is exceeded.

func NoCompression

func NoCompression() HandlerOption

NoCompression disables default compression of the response body based on Accept-Encoding request headers.

type InstrumentFunc

type InstrumentFunc func(req *http.Request, status, bytes int, elapsed time.Duration)

type ResponseWriter

type ResponseWriter interface {
	http.ResponseWriter
	// Status returns the HTTP status of the request, or 0 if one has not
	// yet been sent.
	Status() int
	// BytesWritten returns the total number of bytes sent to the client.
	BytesWritten() int
}

ResponseWriter is a proxy around an http.ResponseWriter with support for instrumentation.

func NewResponseWriter

func NewResponseWriter(w http.ResponseWriter, protoMajor int) ResponseWriter

NewResponseWriter creates a proxy around a http.ResponseWriter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL