tricorder

package
v0.0.0-...-cf6bbf6 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2019 License: Apache-2.0 Imports: 28 Imported by: 193

Documentation

Overview

Package tricorder provides health metrics of an application via http.

Using tricorder in code

Use the tricorder package in your application like so:

import "github.com/Cloud-Foundations/tricorder/go/tricorder"
import "net/http"
import "net/rpc"
func main() {
	doYourInitialization();
	registerYourOwnHttpHandlers();
	// Needed to support Go RPC. Client must call.
	rpc.HandleHTTP()
	if err := http.ListenAndServe(":8080", http.DefaultServeMux); err != nil {
		fmt.Println(err)
	}
}

Viewing Metrics with a Web Browser

Package tricorder uses the net/http package register its web UI at path "/metrics". Package tricorder registers static content such as CSS files at "/metricsstatic".

URL formats to view metrics:

http://yourhostname.com/metrics
	View all top level metrics in HTML
http://yourhostname.com/metrics/single/metric/path
	View the metric with path single/metric/path in HTML.
http://yourhostname.com/metrics/dirpath
	View all metrics with paths starting with 'dirpath/' in HTML.
	Does not expand metrics under subdirectories such as
	dirpath/asubdir but shows subdirectories such as
	dirpath/subdir as a hyper link instead.
http://yourhostname.com/metrics/single/metric/path?format=text
	Value of metric single/metric/path in plain text.
http://yourhostname.com/metrics/dirpath/?format=text
	Shows all metrics starting with 'dirpath/' in plain text.
	Unlike the HTML version, expands all subdirectories under
	/dirpath.
	Shows in this format:
		dirpath/subdir/ametric 21.3
		dirpath/first 12345
		dirpath/second 5.28

Fetching metrics using go RPC

Package tricorder registers the following go rpc methods. You can see these methods by visiting http://yourhostname.com/debug/rpc

MetricsServer.ListMetrics:

Recursively lists all metrics under a particular path. Request is the absolute path as a string. Response is a messages.MetricList type.

MetricsServer.GetMetric

Gets a single metric with a particular path or returns messages.ErrMetricNotFound if there is no such metric. Request is the absolute path as a string. Response is a messages.Metric type.

Example:

import "github.com/Cloud-Foundations/tricorder/go/tricorder/messages"
client, _ := rpc.DialHTTP("tcp", ":8080")
defer client.Close()
var metrics messages.MetricList
client.Call("MetricsServer.ListMetrics", "/a/directory", &metrics)
var metric messages.Metric
err := client.Call("MetricsServer.GetMetric", "/a/metric", &metric)
if err == nil {
	// we found /a/metric
}

Fetching metrics using REST API

Package tricorder registers its REST API at "/metricsapi"

REST urls:

http://yourhostname.com/metricsapi/
	Returns a json array of every metric
http://yourhostname.com/metricsapi/a/path
	Returns a possibly empty json array array of every metric
	anywhere under /a/path.
http://yourhostname.com/metricsapi/path/to/metric?singleton=true
	Returns a metric json object with absolute path
	/path/to/metric or gives a 404 error if no such metric
	exists.

Sample metric json object:

{
	"path": "/proc/foo/bar/baz",
	"description": "Another float value",
	"unit": "None",
	"kind": "float64",
	"bits": 64,
	"value": 12.375,
	"timestamp": "1461347384.190380063",
	"groupId": 0
}

For more information on the json schema, see the messages.Metric type.

Register Custom Metrics

To add additional metrics to the default metrics tricorder provides, Use tricorder.RegisterMetric() and tricorder.RegisterDirectory(). Always pass the address of a variable to RegisterMetric() so that tricorder can see changes in the variable's value.

To register a time.Time, you can pass a **time.Time to RegisterMetric(). To update the time value, change the pointer to point to a different time value rather than changing the existing time in place. This makes the update atomic.

Metric types:

bool
	tricorder.RegisterMetric(
		"a/path/to/bool",
		&boolValue,
		tricorder.None,
		"bool value description")
int, int8, int16, int32, int64
	tricorder.RegisterMetric(
		"a/path/to/int",
		&intValue,
		tricorder.None,
		"int value description")

uint, uint8, uint16, uint32, uint64
	tricorder.RegisterMetric(
		"a/path/to/uint",
		&uintValue,
		tricorder.None,
		"uint value description")

float32, float64
	tricorder.RegisterMetric(
		"a/path/to/float",
		&floatValue,
		tricorder.None,
		"float value description")

string
	tricorder.RegisterMetric(
		"a/path/to/string",
		&stringValue,
		tricorder.None,
		"string value description")

time.Time
	tricorder.RegisterMetric(
		"a/path/to/time",
		&timeValue,
		tricorder.None,
		"time value description")
	tricorder.RegisterMetric(
		"another/path/to/time",
		&pointerToAnotherTimeValue,
		tricorder.None,
		"another time description")
time.Duration
	tricorder.RegisterMetric(
		"a/path/to/duration",
		&durationValue,
		tricorder.None,
		"duration value description")

If code generates a metric's value, register the callback function like so

func generateAnInt() int {
	return 537;
}
tricorder.RegisterMetric(
	"path/to/intValue",
	generateAnInt,
	tricorder.None,
	"generated int description")

Tricorder can collect a distribution of values in a metric. With distributions, the client program must manually add values. Although Distributions store values internally as float64, they can accept time.Duration instances as well as float32 or float64. Each distribution has associated with it a particular measurement unit to allow it to internally convert non floating point values such as time.Duration to the correct floating point equivalent. For example, if the unit is units.Second, the distribution converts an added time.Duration to a floating point value expressed in seconds. The distribution's unit is set when the distribution is first registered. Once set, the unit of a distribution may not be changed. A distribution will panic if a caller tries to add values to an unregistered distribution that has no assigned unit. Distributions are safe to use from multiple goroutines.

globalDist := tricorder.PowersOfTen.NewCumulativeDistribution()
tricorder.RegisterMetric(
	"path/to/distribution",
	globalDist,
	tricorder.None,
	"A distribution description")

func doSomethingDuringProgram() {
	globalDist.Add(getSomeFloatValue())
	globalDist.Add(getAnotherFloatValue())
}

Tricorder can store a list of values in a metric. In lists, values are always of the same type. List instances are safe to use from multiple goroutines.

globalList := tricorder.NewList(
	[]int{2,3,5,7}, tricorder.ImmutableSlice)
tricorder.RegisterMetric(
	"path/to/list",
	globalList,
	tricorder.None,
	"A list description")

func doSomethingDuringProgram() {
	globalList.Change([]int{1,4,9,16}, tricorder.ImmutableSlice)
}

Index

Constants

View Source
const (
	// Indicates that passed slice may change.
	MutableSlice = true
	// Indicates that passed slice will never change.
	ImmutableSlice = false
)
View Source
const CollectorServiceName = "Scotty"

CollectorServiceName contains the name of the service that collects tricorder metrics. This is used in environments where ingress to applications is routinely blocked, and the applications need to call out to the collector. See the github.com/Cloud-Foundations/Dominator/lib/net/reverseconnection package for more information.

Variables

View Source
var (
	// GetDirectory returns this if given path is not found.
	ErrNotFound = errors.New("tricorder: Path not found.")
	// RegisterMetric returns this if given path is already in use.
	ErrPathInUse = errors.New("tricorder: Path in use")
	// RegisterMetric returns this if passed unit is wrong.
	ErrWrongUnit = errors.New("tricorder: Wrong unit")
	// RegisterMetric returns this if passed metric type is not supported.
	ErrWrongType = errors.New("tricorder: Metric not of a valid type")
)
View Source
var (
	// Ranges in powers of two
	PowersOfTwo = NewExponentialBucketer(20, 1.0, 2.0)
	// Ranges in powers of four
	PowersOfFour = NewExponentialBucketer(11, 1.0, 4.0)
	// Ranges in powers of 10
	PowersOfTen = NewExponentialBucketer(7, 1.0, 10.0)
)
View Source
var (
	// The default group. Its update function does nothing and returns
	// the current system time.
	DefaultGroup = NewGroup()
)

Functions

func ReadMyMetrics

func ReadMyMetrics(path string) messages.MetricList

ReadMyMetrics reads all the current tricorder metrics in this process at or under path. If no metrics found under path, ReadMyMetrics returns an empty slice

func RegisterFlags

func RegisterFlags()

RegisterFlags registers each application flag as a metric under /proc/flags in the default group.

func RegisterMetric

func RegisterMetric(
	path string,
	metric interface{},
	unit units.Unit,
	description string) error

RegisterMetric registers a single metric with the health system in the default group.

If metric is a distribution type such as *CumulativeDistribution or *NonCumulativeDistribution that has no assigned unit, then RegisterMetric makes unit be the assigned unit of the distribution being registered.

path is the absolute path of the metric e.g "/proc/rpc"; metric is the metric to register; unit is the unit of measurement for the metric; description is the description of the metric.

RegisterMetric returns ErrPathInUse if path already represents a metric or a directory. RegisterMetric returns ErrWrongUnit if metric is a distribution type such as *CumulativeDistribution or *NonCumulativeDistribution that already has an assigned unit and unit does not match that assigned unit. RegisterMetric returns ErrWrongType if metric is not of a valid type.

func RegisterMetricInGroup

func RegisterMetricInGroup(
	path string,
	metric interface{},
	g *Group,
	unit units.Unit,
	description string) error

RegisterMetricInGroup works just like RegisterMetric but allows the caller to specify the group to which the variable or callback function being registered belongs.

func SetFlagUnit

func SetFlagUnit(name string, unit units.Unit)

SetFlagUnit sets the unit for a specific flag. If the flag is a time.Duration, the default unit is units.Second; otherwise the default unit is units.None. If the client wishes to override the default unit for a flag, they call this before calling RegisterFlags.

func UnregisterPath

func UnregisterPath(path string)

UnregisterPath unregisters the metric or DirectorySpec at the given path. UnregisterPath ignores requests to unregister the root path.

Types

type Bucketer

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

Bucketer represents the organization of values into buckets for distributions. Bucketer instances are immutable.

func NewArbitraryBucketer

func NewArbitraryBucketer(endpoints ...float64) *Bucketer

NewArbitraryBucketer returns a Bucketer representing specific endpoints NewArbitraryBucketer(10.0, 20.0, 30.0) means 4 buckets: <10.0; 10.0 - 20.0; 20.0 - 30.0; >= 30.0. NewArbitraryBucketer panics if it is called with no arguments. It is the caller's responsibility to ensure that the arguments are in ascending order.

func NewExponentialBucketer

func NewExponentialBucketer(count int, start, scale float64) *Bucketer

NewExponentialBucketer returns a Bucketer representing buckets on a geometric scale. NewExponentialBucketer(25, 3.0, 1.7) means 25 buckets starting with <3.0; 3.0 - 5.1; 5.1 - 8.67; 8.67 - 14.739 etc. NewExponentialBucketer panics if count < 2 or if start <= 0 or if scale <= 1.

func NewGeometricBucketer

func NewGeometricBucketer(lower, upper float64) *Bucketer

NewGeometricBucketer returns a Bucketer representing endpoints of the form 10^k, 2*10^k, 5*10^k. lower is the lower bound of the endpoints; upper is the upper bound of the endpoints. NewGeometricBucker(0.5, 50) ==> <0.5; 0.5-1; 1-2; 2-5; 5-10; 10-20; 20-50; >=50

func NewLinearBucketer

func NewLinearBucketer(count int, start, increment float64) *Bucketer

NewLinearBucketer returns a Bucketer representing bucktes on a linear scale. NewLinearBucketer(5, 0, 10) means 5 buckets starting with <0; 0-10; 10-20; 20-30; >=30. NewLinearBucketer panics if count < 2 or if increment <= 0.

func (*Bucketer) NewCumulativeDistribution

func (b *Bucketer) NewCumulativeDistribution() *CumulativeDistribution

NewCumulativeDistribution creates a new CumulativeDistribution that uses this bucketer to distribute values.

func (*Bucketer) NewNonCumulativeDistribution

func (b *Bucketer) NewNonCumulativeDistribution() *NonCumulativeDistribution

NewNonCumulativeDistribution creates a new NonCumulativeDistribution that uses this bucketer to distribute values.

type CumulativeDistribution

type CumulativeDistribution distribution

CumulativeDistribution represents a metric that is a distribution of values. Cumulative distributions only receive new values.

func (*CumulativeDistribution) Add

func (c *CumulativeDistribution) Add(value interface{})

Add adds a single value to this CumulativeDistribution instance. value can be a float32, float64, or a time.Duration. If a time.Duration, Add converts it to this instance's assigned unit. Add panics if value is not a float32, float64, or time.Duration or this instance has no assigned unit.

type DirectoryGroup

type DirectoryGroup struct {
	Group     *Group
	Directory *DirectorySpec
}

DirectoryGroup combines a group and directory for the purpose of registering metrics.

func (DirectoryGroup) RegisterMetric

func (dg DirectoryGroup) RegisterMetric(
	path string,
	metric interface{},
	unit units.Unit,
	description string) error

RegisterMetric works just like the package level RegisterMetric except that path is relative to dg.Directory, and the metric being registered becomes part of the dg.Group group.

type DirectorySpec

type DirectorySpec directory

DirectorySpec represents a specific directory in the heirarchy of metrics.

func GetDirectory

func GetDirectory(path string) (*DirectorySpec, error)

GetDirectory returns the DirectorySpec registered with path. If no such path exists, returns nil, ErrNotFound. If the path is a metric, returns nil, ErrPathInUse.

func RegisterDirectory

func RegisterDirectory(path string) (dirSpec *DirectorySpec, err error)

RegisterDirectory returns the the DirectorySpec registered with path. If nothing is registered with path, RegisterDirectory registers a new DirectorySpec with path and returns it. RegisterDirectory returns ErrPathInUse if path is already associated with a metric.

func (*DirectorySpec) AbsPath

func (d *DirectorySpec) AbsPath() string

Returns the absolute path this object represents

func (*DirectorySpec) RegisterDirectory

func (d *DirectorySpec) RegisterDirectory(
	path string) (dirSpec *DirectorySpec, err error)

RegisterDirectory works just like the package level RegisterDirectory except that path is relative to this DirectorySpec.

func (*DirectorySpec) RegisterMetric

func (d *DirectorySpec) RegisterMetric(
	path string,
	metric interface{},
	unit units.Unit,
	description string) error

RegisterMetric works just like the package level RegisterMetric except that path is relative to this DirectorySpec.

func (*DirectorySpec) RegisterMetricInGroup

func (d *DirectorySpec) RegisterMetricInGroup(
	path string,
	metric interface{},
	g *Group,
	unit units.Unit,
	description string) error

RegisterMetricInGroup works just like the package level RegisterMetricWithGroup except that path is relative to this DirectorySpec.

func (*DirectorySpec) UnregisterDirectory

func (d *DirectorySpec) UnregisterDirectory()

UnregisterDirectory unregisters this DirectorySpec instance along with all metrics and directories within it. The caller can unregister any DirectorySpec instance except the one representing the top level directory. That DirectorySpec instance simply ignores calls to UnregisterDirectory. Metrics registered with an unregistered DirectorySpec instance will not be reported.

func (*DirectorySpec) UnregisterPath

func (d *DirectorySpec) UnregisterPath(path string)

UnregisterPath works just like the package level UnregisterPath except that path is relative to this DirectorySpec.

type Group

type Group region

A group represents a collection of variables for metrics that are all updated by a common function. Each time a client sends a request for one or more metrics backed by variables within a particular group, tricorder calls that group’s update function one time before reading any of the variables in that group to respond to the client. However, to provide a consistent view of the variables within a group, tricorder will never call a group’s update function once it has begun reading variables in that group to service an in-process request. If tricorder does happen to receive an incoming request for metrics from a given group after tricorder has begun reading variables in that same group to service another in-process request, tricorder will skip calling the group’s update function for the incoming request. In this case, the two requests will read the same data from that group.

func NewGroup

func NewGroup() *Group

NewGroup creates a new group with the default update function. The default update function does nothing and returns the current system time.

func (*Group) RegisterMetric

func (g *Group) RegisterMetric(
	path string,
	metric interface{},
	unit units.Unit,
	description string) error

RegisterMetric registers metric in this group. It is the same as calling RegisterMetricInGroup(path, metric, g, unit, description)

func (*Group) RegisterUpdateFunc

func (g *Group) RegisterUpdateFunc(updateFunc func() time.Time)

RegisterUpdateFunc registers an update function with group while clearing any previously registered update function

type List

type List listType

List represents a metric that is a list of values of the same type. List instances are safe to use with multiple goroutines.

func NewList

func NewList(aSlice interface{}, sliceIsMutable bool) *List

NewList returns a new list containing the values in aSlice.

aSlice must be a slice of any type that tricorder supports that represents a single value. For example aSlice can be an []int32, []int64, or []time.Time, but it cannot be a []*tricorder.List. Moreover, aSlice cannot be a slice of pointers such as []*int64. NewList panics if aSlice is not a slice or is a slice of an unsupported type.

If caller passes an []int or []uint for aSlice, NewList converts it internally to either an []int32, []int64, []uint32, []uint64 depending on whether or not the architecture is 32 or 64 bit. This conversion happens even if sliceIsMutable is false and requires creating a copy of the slice. Therefore, we recommend that for aSlice caller always use either []int32 or []int64 instead []int or either []uint32 or []uint64 instead of []uint.

sliceIsMutable lets tricorder know whether or not caller plans to modify aSlice in the future. If caller passes ImmutableSlice or false for sliceIsMutable and later modifies aSlice, the results are undefined. If caller passes MutableSlice or true and later modifies aSlice, tricorder will continue to report the original values in aSlice.

To change the values in a List, caller must use the Change method.

func (*List) Change

func (l *List) Change(aSlice interface{}, sliceIsMutable bool)

Change updates this instance so that it contains only the values found in aSlice.

Change panics if it would change the type of elements this instance contains. For instance, creating a list with a []int64 and then calling Change with a []string panics.

The parameters aSlice and sliceIsMutable work the same way as in NewList.

type NonCumulativeDistribution

type NonCumulativeDistribution distribution

Unlike in CumulativeDistributions,values in NonCumulativeDistributions can change shifting from bucket to bucket.

func (*NonCumulativeDistribution) Add

func (c *NonCumulativeDistribution) Add(value interface{})

Add adds a single value to this NonCumulativeDistribution instance. value can be a float32, float64, or a time.Duration. If a time.Duration, Add converts it to this instance's assigned unit. Add panics if value is not a float32, float64, or time.Duration or this instance has no assigned unit.

func (*NonCumulativeDistribution) Count

func (d *NonCumulativeDistribution) Count() uint64

Count returns the number of values in this distribution

func (*NonCumulativeDistribution) Remove

func (d *NonCumulativeDistribution) Remove(valueToBeRemoved interface{})

Remove removes a value from this NonCumulativeDistribution instance. valueToBeRemoved can be a float32, float64, or a time.Duration. If a time.Duration, Remove converts it to this instance's assigned unit. The reliability of Remove() depends on the caller providing a value already in the distribution. Failure to do this results in undefined behavior. Remove updates all distribution statistics in the expected way; however, it leaves min and max unchanged. To have min and max reflect the current min and max instead of the all-time min and max, see UpdateMinMax(). Remove panics if oldValue and newValue are not a float32, float64, or time.Duration or this instance has no assigned unit.

func (*NonCumulativeDistribution) Sum

Sum returns the sum of the values in this distribution.

func (*NonCumulativeDistribution) Update

func (d *NonCumulativeDistribution) Update(oldValue, newValue interface{})

Update updates a value in this NonCumulativeDistribution instance. oldValue and newValue can be a float32, float64, or a time.Duration. If a time.Duration, Update converts them this instance's assigned unit. The reliability of Update() depends on the caller providing the correct old value of what is being changed. Failure to do this results in undefined behavior. Update updates all distribution statistics in the expected way; however, it updates min and max such that min only gets smaller and max only gets larger. If update Updates values such that they fall into a narrower range than before, min and max remain unchanged to indicate the all-time min and all-time max. To have min and max reflect the current min and max instead of the all-time min and max, see UpdateMinMax(). Update panics if oldValue and newValue are not a float32, float64, or time.Duration or this instance has no assigned unit.

func (*NonCumulativeDistribution) UpdateMinMax

func (d *NonCumulativeDistribution) UpdateMinMax()

UpdateMinMax() estimates the current min and max of this distribution. and updates min and max accordingly. As this call may be expensive, clients need not use unless both are true: 1) the client has made calls to Update which narrowed the current min and max. 2) The client wants min and max to reflect the current min and max instead of the all-time min and max. This method only estimates. The only guarantees that it makes upon returning are: original_min <= min <= current_min and old_max >= max >= current_max. In fact, calling this method may do nothing at all which would still be correct behavior.

Directories

Path Synopsis
Package duration provides utilities for dealing with times and durations.
Package duration provides utilities for dealing with times and durations.
Package messages provides the types needed to collect metrics via the go rpc calls and the REST API mentioned in the tricorder package.
Package messages provides the types needed to collect metrics via the go rpc calls and the REST API mentioned in the tricorder package.
Package types contains the various types for metric values.
Package types contains the various types for metric values.
Package units contains the various units of measurement for a metric.
Package units contains the various units of measurement for a metric.

Jump to

Keyboard shortcuts

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