xstats

package module
Version: v0.0.0-...-c673675 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2017 License: MIT Imports: 6 Imported by: 29

README

XStats

godoc license Build Status Coverage

Package xstats is a generic client for service instrumentation.

xstats is inspired from Go-kit's metrics package but it takes a slightly different path. Instead of having to create an instance for each metric, xstats use a single instance to log every metrics you want. This reduces the boiler plate when you have a lot a metrics in your app. It's also easier in term of dependency injection.

Talking about dependency injection, xstats comes with a xhandler.Handler integration so it can automatically inject the xstats client within the net/context of each request. Each request's xstats instance have its own tags storage ; This let you inject some per request contextual tags to be included with all observations sent within the lifespan of the request.

xstats is pluggable and comes with integration for expvar, StatsD and DogStatsD, the Datadog augmented version of StatsD with support for tags. More integration may come later (PR welcome).

Supported Clients

Install

go get github.com/rs/xstats

Usage

// Defines interval between flushes to statsd server
flushInterval := 5 * time.Second

// Connection to the statsd server
statsdWriter, err := net.Dial("udp", "127.0.0.1:8126")
if err != nil {
    log.Fatal(err)
}

// Create the stats client
s := xstats.New(dogstatsd.New(statsdWriter, flushInterval))

// Global tags sent with all metrics (only with supported clients like datadog's)
s.AddTags("role:my-service", "dc:sv6")

// Send some observations
s.Count("requests", 1, "tag")
s.Timing("something", 5*time.Millisecond, "tag")

Integration with github.com/rs/xhandler:

var xh xhandler.HandlerC

// Here is your handler
xh = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // Get the xstats request's instance from the context. You can safely assume it will
    // be always there, if the handler is removed, xstats.FromContext will return a nop
    // instance.
    m := xstats.FromRequest(r)

    // Count something
    m.Count("requests", 1, "route:index")
})

// Install the metric handler with dogstatsd backend client and some env tags
flushInterval := 5 * time.Second
tags := []string{"role:my-service"}
statsdWriter, err := net.Dial("udp", "127.0.0.1:8126")
if err != nil {
    log.Fatal(err)
}
xh = xstats.NewHandler(dogstatsd.New(statsdWriter, flushInterval), tags, xh)

// Root context
ctx := context.Background()
h := xhandler.New(ctx, xh)
http.Handle("/", h)

if err := http.ListenAndServe(":8080", nil); err != nil {
    log.Fatal(err)
}

Testing

func TestFunc(t *testing.T) {
    m := mock.New()
    s := xstats.New(m)
    m.On("Timing", "something", 5*time.Millisecond, "tag")
    s.Timing("something", 5*time.Millisecond, "tag")
    s.AssertExpectations(t)
}

Licenses

All source code is licensed under the MIT License.

Documentation

Overview

Package xstats is a generic client for service instrumentation.

xstats is inspired from Go-kit's metrics (https://github.com/go-kit/kit/tree/master/metrics) package but it takes a slightly different path. Instead of having to create an instance for each metric, xstats use a single instance to log every metrics you want. This reduces the boiler plate when you have a lot a metrics in your app. It's also easier in term of dependency injection.

Talking about dependency injection, xstats comes with a xhandler.Handler integration so it can automatically inject the xstats client within the net/context of each request. Each request's xstats instance have its own tags storage ; This let you inject some per request contextual tags to be included with all observations sent within the lifespan of the request.

xstats is pluggable and comes with integration for StatsD and DogStatsD, the Datadog (http://datadoghq.com) augmented version of StatsD with support for tags. More integration may come later (PR welcome).

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// DisablePooling will disable the use of sync.Pool fo resource management when true.
	// This allows for XStater instances to persist beyond the scope of an HTTP request
	// handler. However, using this option puts a greater pressure on GC and changes
	// the memory usage patterns of the library. Use only if there is a requirement
	// for persistent stater references.
	DisablePooling = false
)

Functions

func Close

func Close(xs XStater) error

Close will call Close() on any xstats.XStater that implements io.Closer

func CloseSender

func CloseSender(s Sender) error

CloseSender will call Close() on any xstats.Sender that implements io.Closer

func NewContext

func NewContext(ctx context.Context, xs XStater) context.Context

NewContext returns a copy of the parent context and associates it with passed stats.

func NewHandler

func NewHandler(s Sender, tags []string) func(http.Handler) http.Handler

NewHandler creates a new handler with the provided metric client. If some tags are provided, the will be added to all logged metrics.

Example
package main

import (
	"log"
	"net"
	"net/http"
	"time"

	"github.com/rs/xhandler"
	"github.com/rs/xstats"
	"github.com/rs/xstats/dogstatsd"
)

func main() {
	c := xhandler.Chain{}

	// Install the metric handler with dogstatsd backend client and some env tags
	flushInterval := 5 * time.Second
	tags := []string{"role:my-service"}
	statsdWriter, err := net.Dial("udp", "127.0.0.1:8126")
	if err != nil {
		log.Fatal(err)
	}
	c.Use(xstats.NewHandler(dogstatsd.New(statsdWriter, flushInterval), tags))

	// Here is your handler
	h := c.HandlerH(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Get the xstats request's instance from the context. You can safely assume it will
		// be always there, if the handler is removed, xstats.FromContext will return a nop
		// instance.
		m := xstats.FromRequest(r)

		// Count something
		m.Count("requests", 1, "route:index")
	}))

	http.Handle("/", h)

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
Output:

func NewHandlerPrefix

func NewHandlerPrefix(s Sender, tags []string, prefix string) func(http.Handler) http.Handler

NewHandlerPrefix creates a new handler with the provided metric client. If some tags are provided, the will be added to all logged metrics. If the prefix argument is provided, all produced metrics will have this prefix prepended.

Types

type Copier

type Copier interface {
	Copy() XStater
}

Copier is an interface to an XStater that supports coping

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler injects a per request metrics client in the net/context which can be retrived using xstats.FromContext(ctx)

type MultiSender

type MultiSender []Sender

MultiSender lets you assign more than one sender to xstats in order to multicast observeration to different systems.

Example
package main

import (
	"net"
	"time"

	"github.com/rs/xstats"
	"github.com/rs/xstats/dogstatsd"
	"github.com/rs/xstats/expvar"
)

func main() {
	// Create an expvar sender
	s1 := expvar.New("stats")

	// Create the stats sender
	statsdWriter, _ := net.Dial("udp", "127.0.0.1:8126")
	s2 := dogstatsd.New(statsdWriter, 5*time.Second)

	// Create a xstats with a sender composed of the previous two.
	// You may also create a NewHandler() the same way.
	s := xstats.New(xstats.MultiSender{s1, s2})

	// Send some observations
	s.Count("requests", 1, "tag")
	s.Timing("something", 5*time.Millisecond, "tag")
}
Output:

func (MultiSender) Close

func (s MultiSender) Close() error

Close implements the io.Closer interface

func (MultiSender) Count

func (s MultiSender) Count(stat string, count float64, tags ...string)

Count implements the xstats.Sender interface

func (MultiSender) Gauge

func (s MultiSender) Gauge(stat string, value float64, tags ...string)

Gauge implements the xstats.Sender interface

func (MultiSender) Histogram

func (s MultiSender) Histogram(stat string, value float64, tags ...string)

Histogram implements the xstats.Sender interface

func (MultiSender) Timing

func (s MultiSender) Timing(stat string, duration time.Duration, tags ...string)

Timing implements the xstats.Sender interface

type Scoper

type Scoper interface {
	Scope(scope string, scopes ...string) XStater
}

Scoper is an interface to an XStater, that supports scoping

type Sender

type Sender interface {
	// Gauge measure the value of a particular thing at a particular time,
	// like the amount of fuel in a car’s gas tank or the number of users
	// connected to a system.
	Gauge(stat string, value float64, tags ...string)

	// Count track how many times something happened per second, like
	// the number of database requests or page views.
	Count(stat string, count float64, tags ...string)

	// Histogram track the statistical distribution of a set of values,
	// like the duration of a number of database queries or the size of
	// files uploaded by users. Each histogram will track the average,
	// the minimum, the maximum, the median, the 95th percentile and the count.
	Histogram(stat string, value float64, tags ...string)

	// Timing mesures the elapsed time
	Timing(stat string, value time.Duration, tags ...string)
}

Sender define an interface to a stats system like statsd or datadog to send service's metrics.

type XStater

type XStater interface {
	Sender

	// AddTag adds a tag to the request client, this tag will be sent with all
	// subsequent stats queries.
	AddTags(tags ...string)

	// GetTags returns the tags associated with the XStater, all the tags that
	// will be sent along with all the stats queries.
	GetTags() []string
}

XStater is a wrapper around a Sender to inject env tags within all observations.

func Copy

func Copy(xs XStater) XStater

Copy makes a copy of the given XStater if it implements the Copier interface. Otherwise it returns a nop stats.

func FromContext

func FromContext(ctx context.Context) XStater

FromContext retreives the request's xstats client from a given context if any. If no xstats is embeded in the context, a nop instance is returned so you can use it safely without having to test for it's presence.

func FromRequest

func FromRequest(r *http.Request) XStater

FromRequest gets the xstats client in the request's context. This is a shortcut for xstats.FromContext(r.Context())

func New

func New(s Sender) XStater

New returns a new xstats client with the provided backend sender.

Example
package main

import (
	"log"
	"net"
	"time"

	"github.com/rs/xstats"
	"github.com/rs/xstats/dogstatsd"
)

func main() {
	// Defines interval between flushes to statsd server
	flushInterval := 5 * time.Second

	// Connection to the statsd server
	statsdWriter, err := net.Dial("udp", "127.0.0.1:8126")
	if err != nil {
		log.Fatal(err)
	}

	// Create the stats client
	s := xstats.New(dogstatsd.New(statsdWriter, flushInterval))

	// Global tags sent with all metrics (only with supported clients like datadog's)
	s.AddTags("role:my-service", "dc:sv6")

	// Send some observations
	s.Count("requests", 1, "tag")
	s.Timing("something", 5*time.Millisecond, "tag")
}
Output:

func NewPrefix

func NewPrefix(s Sender, prefix string) XStater

NewPrefix returns a new xstats client with the provided backend sender. The prefix is prepended to all metric names.

func NewScoping

func NewScoping(s Sender, delimiter string, scopes ...string) XStater

NewScoping returns a new xstats client with the provided backend sender. The delimiter is used to delimit scopes. Initial scopes can be provided.

Example
package main

import (
	"log"
	"net"
	"time"

	"github.com/rs/xstats"
	"github.com/rs/xstats/dogstatsd"
)

func main() {
	// Defines interval between flushes to statsd server
	flushInterval := 5 * time.Second

	// Connection to the statsd server
	statsdWriter, err := net.Dial("udp", "127.0.0.1:8126")
	if err != nil {
		log.Fatal(err)
	}

	// Create the stats client
	s := xstats.NewScoping(dogstatsd.New(statsdWriter, flushInterval), ".", "my-thing")

	// Global tags sent with all metrics (only with supported clients like datadog's)
	s.AddTags("role:my-service", "dc:sv6")

	// Send some observations
	s.Count("requests", 1, "tag")
	s.Timing("something", 5*time.Millisecond, "tag")

	// Scope the client
	ss := xstats.Scope(s, "my-sub-thing")
	ss.Histogram("latency", 50, "tag")
}
Output:

func Scope

func Scope(xs XStater, scope string, scopes ...string) XStater

Scope makes a scoped copy of the given XStater if it implements the Scoper interface. Otherwise it returns a nop stats.

Directories

Path Synopsis
Package dogstatsd implement Datadog extended StatsD protocol for github.com/rs/xstats
Package dogstatsd implement Datadog extended StatsD protocol for github.com/rs/xstats
Package mock implements mock object for xstats Sender interface based on github.com/stretchr/testify/mock package mock implementation
Package mock implements mock object for xstats Sender interface based on github.com/stretchr/testify/mock package mock implementation
Package statsd implement the StatsD protocol for github.com/rs/xstats
Package statsd implement the StatsD protocol for github.com/rs/xstats
Package telegrafstatsd implement telegraf extended StatsD protocol for github.com/rs/xstats
Package telegrafstatsd implement telegraf extended StatsD protocol for github.com/rs/xstats

Jump to

Keyboard shortcuts

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