salp

package module
v1.0.0-beta.1 Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2021 License: MIT Imports: 3 Imported by: 0

README

Salp

Salp is a library that enables Go programs to create and fire USDT probes at runtime. Such probes allow API-stable (i.e. not dependent on function names) tracing of executables written in Go - especially important since function tracing of Go code requires some unappealing (though not unimpressive) hacks. Salp uses the libstapsdt library to create and fire these probes.

GoDoc

Build

Dependencies

Salp depends on libstapsdt which in turn depends on libelf and libdl. libstapsdt can be built from source or (for debian based distros) installed via an Ubuntu PPA. Full instructions are available in the docs for libstapsdt

Build and Test

If libstdapsdt is installed globally (e.g. from the PPA above or via make install), you should be able to simply go build or go test. However if you have built libstapsdt from source then you will need to tell the cgo tool how to find the headers and .so files for libstapsdt using the CGO_CFLAGS, CGO_LDFLAGS, and LD_LIBRARY_PATH environment variables.

export CGO_CFLAGS="-I/path/to/libstapsdt/src"
export CGO_LDFLAGS="-L/path/to/libstapsdt/out"
export LD_LIBRARY_PATH="/path/to/libstapsdt/out"

Demo

This repository contains a demo executable that will fire two different probes every second. The demo can be observed using the trace and tplist tools from the bcc project. Use two terminals to run the demo - one to execute the tracable salpdemo go program and one to run the bcc tools and see their output. In the first window run

go run internal/salpdemo.go

This program will print out how to monitor itself but then won't print out anything after that. In the second window run the bcc trace program on the salpdemo process, monitoring probes p1 and p2.

sudo trace -p "$(pgrep -n salpdemo)"                    \
    'u::p1 "i=%d err='%s' date='%s'", arg1, arg2, arg3' \
    'u::p2 "j=%d flag=%d", arg1, arg2'

or alternatively the same thing with bpftrace

sudo bpftrace -p "$(pgrep -n salpdemo)" /dev/stdin <<EOF
  usdt:p1 { printf("i=%d err='%s' date='%s'\n", arg0, str(arg1), str(arg2)); }
  usdt:p2 { printf("j=%d flag=%d\n", arg0, arg1); }
EOF

Either trace invocations will output the values of the three args to probe 1 and the two args to probe 2.

Documentation

Overview

Package salp enables the definition and firing of USDT probes at runtime by Go programs running on Linux. These probes impose little or no overhead when not in use and are available for use by any tool that is able to monitor USDT probe points (e.g. the trace tool from the bcc project).

Example
package main

import (
	"strconv"
	"time"

	"github.com/mmcshane/salp"
)

func main() {
	// Provider and probe creation should occur early on, probably during
	// initialization

	// Create a provider to which we will attach probes. The provider
	// acts as a namespace & container for probe instances.
	provider := salp.NewProvider("my-example-provider")
	defer salp.UnloadAndDispose(provider)

	// Create a probe that can be fired with 4 args: a string, a uint8,
	// an int16, and another string
	probe1 := salp.MustAddProbe(provider, "my-example-probe",
		salp.String, salp.Uint8, salp.Int16, salp.String)

	// Create a second probe that takes only a single string argument
	probe2 := salp.MustAddProbe(provider, "my-other-examaple-probe", salp.String)

	// Now that the probes have been created, enable the provider by calling
	// Load().
	salp.MustLoadProvider(provider)

	// Initialization of our provider and 2 probes is now complete, the probes
	// are ready to be fired. Firing probes happens after initialization, inline
	// with execution of your program.

	// Fire both probes 10 times
	for i := 0; i < 10; i++ {
		probe1.Fire(strconv.Itoa(i), 5, 10, "foo")
		probe2.Fire(time.Now().Format(time.RFC1123))
		time.Sleep(1 * time.Second)
	}
}
Output:

Index

Examples

Constants

View Source
const (
	// Probe argument should be treated as a uint8
	Uint8 = ProbeArgType(C.uint8)

	// Probe argument should be treated as a bool
	Bool = Uint8

	//Probe argument should be treated as a byte
	Byte = Uint8

	// Probe argument should be treated as an int8
	Int8 = ProbeArgType(C.int8)

	// Probe argument should be treated as a uint16
	Uint16 = ProbeArgType(C.uint16)

	// Probe argument should be treated as an int16
	Int16 = ProbeArgType(C.int16)

	// Probe argument should be treated as a uint32
	Uint32 = ProbeArgType(C.uint32)

	// Probe argument should be treated as an int32
	Int32 = ProbeArgType(C.int32)

	// Probe argument should be treated as a uint64
	Uint64 = ProbeArgType(C.uint64)

	// Probe argument should be treated as an int64
	Int64 = ProbeArgType(C.int64)

	// Probe argument should be treated as a uint64
	String = ProbeArgType(C.uint64)

	// Probe argument should be treated as a Go error
	Error = String
)

ProbeArgTypes are used to specify the type of parameters accepted when firing a Probe

Variables

This section is empty.

Functions

func MustLoadProvider

func MustLoadProvider(p *Provider)

MustLoadProvider is a helper function the either calls Load() on the supplied Provider instance or in the case of an error, panics

func UnloadAndDispose

func UnloadAndDispose(p *Provider)

UnloadAndDispose is a convenience function suitable for deferred invocation that calls p.Unload() and then p.Dispose().

Types

type Probe

type Probe = C.struct_SDTProbe

Probe is a location in Go code that can be "fired" with a set of arguments such that extrenal tools (e.g. the `trace` tool from bcc) can attach to a running process and inspect the values at runtime.

func MustAddProbe

func MustAddProbe(p *Provider, name string, argTypes ...ProbeArgType) *Probe

MustAddProbe is a helper function that either adds a probe with the supplied name and argument types to the specified provider or, in the case of an error, panics.

func (*Probe) Enabled

func (p *Probe) Enabled() bool

Enabled returns true iff the provider associated with this Probe is in a loaded state and the Probe is being monitored by an agent such as the bcc trace tool.

func (*Probe) Fire

func (p *Probe) Fire(args ...interface{})

Fire invokes the Probe with the provided arguments. The type and arity of this invocation should match what was described by the ProbeArgType arguments originally given to the Provider.AddProbe invocation that created this Probe. Cheap to invoke if the probe is not enabled (see: Enabled())

func (*Probe) Name

func (p *Probe) Name() string

Name gets the name of this Probe as provided when it was originally created.

type ProbeArgType

type ProbeArgType C.ArgType_t

ProbeArgType specifies the type of each individual parameter than can be specified when firing a Probe.

type Provider

type Provider = C.struct_SDTProvider

Provider represents a named collection of probes

func NewProvider

func NewProvider(name string) *Provider

NewProvider creates a libstapsdt error probe provider with the supplied name. Provider instances are in either a loaded or an unloaded state. When Provders are unloaded (their initial state), probes can be created via AddProbe. Once the Provider is loaded via the Load() function, the probe set should not be changed. Probes can be cleared from the Provider instance by unloading it via the Unload() function. Probe addition is not threadsafe steps must be taken by clients of this library to ensure that at most one thread is adding a Probe at a time.

func (*Provider) AddProbe

func (p *Provider) AddProbe(name string, argTypes ...ProbeArgType) (*Probe, error)

AddProbe creates a new Probe instance with the supplied name and assiciates it with this Provider. The argTypes describe the arguments that are expected to be supplied when Fire is called on this Probe.

func (*Provider) Dispose

func (p *Provider) Dispose()

Dispose cleans up the Provider datastructures and frees associated memory from the underlying C library (libstapsdt). The Provider instance is useless after this method is invoked.

func (*Provider) Load

func (p *Provider) Load() error

Load transitions the provider from the unloaded state into the loaded state which causes associated Probes to become active (i.e. calling Fire() on the probe will actually work).

func (*Provider) Name

func (p *Provider) Name() string

Name returns the name of the provider as a string

func (*Provider) Unload

func (p *Provider) Unload()

Unload transitions this Provider from the loaded to the unloaded state. Associated probes are detached and must be re-attached in order to function.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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