prober

package
v1.80.0 Latest Latest
Warning

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

Go to latest
Published: Jan 30, 2025 License: BSD-3-Clause Imports: 48 Imported by: 5

Documentation

Overview

Package prober implements a simple blackbox prober. Each probe runs in its own goroutine, and run results are recorded as Prometheus metrics.

Index

Examples

Constants

View Source
const (
	ProbeStatusUnknown   = "unknown"
	ProbeStatusRunning   = "running"
	ProbeStatusFailed    = "failed"
	ProbeStatusSucceeded = "succeeded"
)

Variables

This section is empty.

Functions

func DERP added in v1.34.0

func DERP(p *Prober, derpMapURL string, opts ...DERPOpt) (*derpProber, error)

DERP creates a new derpProber.

If derpMapURL is "local", the DERPMap is fetched via the local machine's tailscaled.

func WithPageLink(text, url string) statusHandlerOpt

WithPageLink adds a top-level link to the status page.

func WithProbeLink(textTpl, urlTpl string) statusHandlerOpt

WithProbeLink adds a link to each probe on the status page. The textTpl and urlTpl are Go templates that will be rendered with the respective ProbeInfo struct as the data.

func WithTitle added in v1.72.0

func WithTitle(title string) statusHandlerOpt

WithTitle sets the title of the status page.

Types

type DERPOpt added in v1.62.0

type DERPOpt func(*derpProber)

func WithBandwidthProbing added in v1.62.0

func WithBandwidthProbing(interval time.Duration, size int64, tunAddress string) DERPOpt

WithBandwidthProbing enables bandwidth probing. When enabled, a payload of `size` bytes will be regularly transferred through each DERP server, and each pair of DERP servers in every region. If tunAddress is specified, probes will use a TCP connection over a TUN device at this address in order to exercise TCP-in-TCP in similar fashion to TCP over Tailscale via DERP.

func WithMeshProbing added in v1.62.0

func WithMeshProbing(interval time.Duration) DERPOpt

WithMeshProbing enables mesh probing. When enabled, a small message will be transferred through each DERP server and each pair of DERP servers.

func WithQueuingDelayProbing added in v1.80.0

func WithQueuingDelayProbing(qdPacketsPerSecond int, qdPacketTimeout time.Duration) DERPOpt

WithQueuingDelayProbing enables/disables queuing delay probing. qdSendRate is the number of packets sent per second. qdTimeout is the amount of time after which a sent packet is considered to have timed out.

func WithRegionCodeOrID added in v1.80.0

func WithRegionCodeOrID(regionCode string) DERPOpt

WithRegionCodeOrID restricts probing to the specified region identified by its code (e.g. "lax") or its id (e.g. "17"). This is case sensitive.

func WithSTUNProbing added in v1.62.0

func WithSTUNProbing(interval time.Duration) DERPOpt

WithSTUNProbing enables STUN/UDP probing, with a STUN request being sent to each DERP server every `interval`.

func WithTLSProbing added in v1.62.0

func WithTLSProbing(interval time.Duration) DERPOpt

WithTLSProbing enables TLS probing that will check TLS certificate on port 443 of each DERP server every `interval`.

type ForEachAddrOpts added in v1.64.0

type ForEachAddrOpts struct {
	// Logf is the logger to use for logging. If nil, no logging is done.
	Logf logger.Logf
	// Networks is the list of networks to resolve; if non-empty, it should
	// contain at least one of "ip", "ip4", or "ip6".
	//
	// If empty, "ip" is assumed.
	Networks []string
	// LookupNetIP is the function to use to resolve the hostname to one or
	// more IP addresses.
	//
	// If nil, net.DefaultResolver.LookupNetIP is used.
	LookupNetIP func(context.Context, string, string) ([]netip.Addr, error)
}

ForEachAddrOpts contains options for ForEachAddr. The zero value for all fields is valid unless stated otherwise.

type Labels added in v1.64.0

type Labels map[string]string

Labels is a set of metric labels used by a prober.

func (Labels) With added in v1.64.0

func (l Labels) With(k, v string) Labels

type Probe

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

Probe is a probe that healthchecks something and updates Prometheus metrics with the results.

func (*Probe) Close

func (p *Probe) Close() error

Close shuts down the Probe and unregisters it from its Prober. It is safe to Run a new probe of the same name after Close returns.

func (*Probe) Collect added in v1.40.0

func (p *Probe) Collect(ch chan<- prometheus.Metric)

Collect implements prometheus.Collector.

func (*Probe) Describe added in v1.40.0

func (p *Probe) Describe(ch chan<- *prometheus.Desc)

Describe implements prometheus.Collector.

func (*Probe) IsContinuous added in v1.80.0

func (p *Probe) IsContinuous() bool

IsContinuous indicates that this is a continuous probe.

type ProbeClass added in v1.64.0

type ProbeClass struct {
	// Probe is a function that probes something and reports whether the Probe
	// succeeded. The provided context's deadline must be obeyed for correct
	// Probe scheduling.
	Probe func(context.Context) error

	// Class defines a user-facing name of the probe class that will be used
	// in the `class` metric label.
	Class string

	// Labels defines a set of metric labels that will be added to all metrics
	// exposed by this probe class.
	Labels Labels

	// Timeout is the maximum time the probe function is allowed to run before
	// its context is cancelled. Defaults to 80% of the scheduling interval.
	Timeout time.Duration

	// Concurrency is the maximum number of concurrent probe executions
	// allowed for this probe class. Defaults to 1.
	Concurrency int

	// Metrics allows a probe class to export custom Metrics. Can be nil.
	Metrics func(prometheus.Labels) []prometheus.Metric
}

ProbeClass defines a probe of a specific type: a probing function that will be regularly ran, and metric labels that will be added automatically to all probes using this class.

func ForEachAddr added in v1.64.0

func ForEachAddr(host string, makeProbes func(netip.Addr) []*Probe, opts ForEachAddrOpts) ProbeClass

ForEachAddr returns a Probe that resolves a given hostname into all available IP addresses, and then calls a function to create new Probes every time a new IP is discovered. The Probes returned will be closed if an IP address is no longer in the DNS record for the given hostname. This can be used to healthcheck every IP address that a hostname resolves to.

Example

This example demonstrates how to use ForEachAddr to create a TLS probe for each IP address in the DNS record of a given hostname.

package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"net/netip"
	"os"
	"os/signal"
	"time"

	"tailscale.com/prober"
	"tailscale.com/types/logger"
)

const (
	every30s = 30 * time.Second
)

var (
	hostname = flag.String("hostname", "tailscale.com", "hostname to probe")
	oneshot  = flag.Bool("oneshot", true, "run probes once and exit")
	verbose  = flag.Bool("verbose", false, "enable verbose logging")
)

// This example demonstrates how to use ForEachAddr to create a TLS probe for
// each IP address in the DNS record of a given hostname.
func main() {
	flag.Parse()

	p := prober.New().WithSpread(true)
	if *oneshot {
		p = p.WithOnce(true)
	}

	// This function is called every time we discover a new IP address to check.
	makeTLSProbe := func(addr netip.Addr) []*prober.Probe {
		pf := prober.TLSWithIP(*hostname, netip.AddrPortFrom(addr, 443))
		if *verbose {
			logger := logger.WithPrefix(log.Printf, fmt.Sprintf("[tls %s]: ", addr))
			pf = probeLogWrapper(logger, pf)
		}

		probe := p.Run(fmt.Sprintf("website/%s/tls", addr), every30s, nil, pf)
		return []*prober.Probe{probe}
	}

	// Determine whether to use IPv4 or IPv6 based on whether we can create
	// an IPv6 listening socket on localhost.
	sock, err := net.Listen("tcp", "[::1]:0")
	supportsIPv6 := err == nil
	if sock != nil {
		sock.Close()
	}

	networks := []string{"ip4"}
	if supportsIPv6 {
		networks = append(networks, "ip6")
	}

	var vlogf logger.Logf = logger.Discard
	if *verbose {
		vlogf = log.Printf
	}

	// This is the outer probe that resolves the hostname and creates a new
	// TLS probe for each IP.
	p.Run("website/dns", every30s, nil, prober.ForEachAddr(*hostname, makeTLSProbe, prober.ForEachAddrOpts{
		Logf:     vlogf,
		Networks: networks,
	}))

	defer log.Printf("done")

	// Wait until all probes have run if we're running in oneshot mode.
	if *oneshot {
		p.Wait()
		return
	}

	// Otherwise, wait until we get a signal.
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	<-sigCh
}

func probeLogWrapper(logf logger.Logf, pc prober.ProbeClass) prober.ProbeClass {
	return prober.ProbeClass{
		Probe: func(ctx context.Context) error {
			logf("starting probe")
			err := pc.Probe(ctx)
			logf("probe finished with %v", err)
			return err
		},
	}
}
Output:

func FuncProbe added in v1.64.0

func FuncProbe(fn func(context.Context) error) ProbeClass

FuncProbe wraps a simple probe function in a ProbeClass.

func HTTP

func HTTP(url, wantText string) ProbeClass

HTTP returns a ProbeClass that healthchecks an HTTP URL.

The probe function sends a GET request for url, expects an HTTP 200 response, and verifies that want is present in the response body.

func TCP

func TCP(addr string) ProbeClass

TCP returns a Probe that healthchecks a TCP endpoint.

The ProbeFunc reports whether it can successfully connect to addr.

func TLS

func TLS(hostPort string) ProbeClass

TLS returns a Probe that healthchecks a TLS endpoint.

The ProbeFunc connects to a hostPort (host:port string), does a TLS handshake, verifies that the hostname matches the presented certificate, checks certificate validity time and OCSP revocation status.

func TLSWithIP added in v1.62.0

func TLSWithIP(certDomain string, dialAddr netip.AddrPort) ProbeClass

TLSWithIP is like TLS, but dials the provided dialAddr instead of using DNS resolution. The certDomain is the expected name in the cert (and the SNI name to send).

type ProbeInfo added in v1.38.0

type ProbeInfo struct {
	Name            string
	Class           string
	Interval        time.Duration
	Labels          map[string]string
	Start           time.Time
	End             time.Time
	Latency         time.Duration
	Status          ProbeStatus
	Error           string
	RecentResults   []bool
	RecentLatencies []time.Duration
}

ProbeInfo is a snapshot of the configuration and state of a Probe.

func (ProbeInfo) Continuous added in v1.80.0

func (pb ProbeInfo) Continuous() bool

func (ProbeInfo) RecentMedianLatency added in v1.72.0

func (pb ProbeInfo) RecentMedianLatency() time.Duration

RecentMedianLatency returns the median latency of the probe in the recent history.

func (ProbeInfo) RecentSuccessRatio added in v1.72.0

func (pb ProbeInfo) RecentSuccessRatio() float64

RecentSuccessRatio returns the success ratio of the probe in the recent history.

type ProbeStatus added in v1.80.0

type ProbeStatus string

ProbeStatus indicates the status of a probe.

type Prober

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

a Prober manages a set of probes and keeps track of their results.

func New

func New() *Prober

New returns a new Prober.

func (*Prober) ProbeInfo added in v1.38.0

func (p *Prober) ProbeInfo() map[string]ProbeInfo

ProbeInfo returns the state of all probes.

func (*Prober) Run

func (p *Prober) Run(name string, interval time.Duration, labels Labels, pc ProbeClass) *Probe

Run executes probe class function every interval, and exports probe results under probeName.

If interval is negative, the probe will run continuously. If it encounters a failure while running continuously, it will pause for -1*interval and then retry.

Registering a probe under an already-registered name panics.

func (*Prober) RunHandler added in v1.72.0

func (p *Prober) RunHandler(w http.ResponseWriter, r *http.Request) error

RunHandler runs a probe by name and returns the result as an HTTP response.

func (*Prober) StatusHandler added in v1.72.0

func (p *Prober) StatusHandler(opts ...statusHandlerOpt) tsweb.ReturnHandlerFunc

StatusHandler is a handler for the probe overview HTTP endpoint. It shows a list of probes and their current status.

func (*Prober) Wait added in v1.38.0

func (p *Prober) Wait()

Wait blocks until all probes have finished execution. It should typically be used with the `once` mode to wait for probes to finish before collecting their results.

func (*Prober) WithMetricNamespace added in v1.40.0

func (p *Prober) WithMetricNamespace(n string) *Prober

WithMetricNamespace allows changing metric name prefix from the default `prober`.

func (*Prober) WithOnce added in v1.38.0

func (p *Prober) WithOnce(s bool) *Prober

WithOnce mode can be used if you want to run all configured probes once rather than on a schedule.

func (*Prober) WithSpread added in v1.34.0

func (p *Prober) WithSpread(s bool) *Prober

WithSpread is used to enable random delay before the first run of each added probe.

type RunHandlerResponse added in v1.72.0

type RunHandlerResponse struct {
	ProbeInfo             ProbeInfo
	PreviousSuccessRatio  float64
	PreviousMedianLatency time.Duration
}

RunHandlerResponse is the JSON response format for the RunHandler.

Jump to

Keyboard shortcuts

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