optel

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

go-optel

Go Reference

A dependency-free Go client for Adobe's helix-rum-js wire format, the operational telemetry (OpTel) beacons that SLICC's web pages and native apps send. It is used by slicc-cli. OpTel is Adobe's RUM-style operational telemetry, not OpenTelemetry.

go get github.com/ai-ecoverse/go-optel
package main

import (
	"os"
	"time"

	optel "github.com/ai-ecoverse/go-optel"
)

func main() {
	client := optel.Configure("slicc-cli", optel.Options{})
	defer client.Flush(2 * time.Second)

	client.Sample(optel.Enter, "follow", "")

	if _, err := os.Open("missing.json"); err != nil {
		client.ReportError("config", err)
	}
}

Configure makes the one sampling decision for the process, Sample(optel.Enter, …) records the subcommand, ReportError sanitizes and sends a failure, and Flush waits up to the timeout for beacons still in flight. All methods are safe on a nil *Client, so a caller that opts out can skip Configure and keep the calls.

Checkpoints

A headless CLI has no clicks, views or Core Web Vitals, so it sends two checkpoints:

  • Enter when the process starts, with the subcommand as source.
  • Error for an operational failure, always through ReportError.

The first beacon of a process is preceded by top, as in the other clients. Checkpoint stays an open string, so other checkpoints are possible, but a CLI should rarely need them.

Privacy

A CLI's error strings carry secrets by construction. Go's net/http and net/url errors include the whole request URL, with any token in its path or query, and file errors include the home directory and so the login name. ReportError runs every message through Sanitize:

  • Every absolute URL becomes scheme://host/....
  • Absolute POSIX and Windows paths shrink to their first segment or drive.
  • Only then is the message cut to 200 characters, so a cut never leaves part of a secret behind.

Never call client.Sample(optel.Error, source, err.Error()) directly.

Sampling

One decision per Configure, that is per process, not per beacon, as the web and Swift clients decide once per page view or session. The beacon goes to <collect base>/.rum/<weight>, by default https://rum.hlx.page/.rum/100.

variable values
OPTEL_RATE on (weight 1, every process), high (10), low (1000), off; anything else is weight 100
OPTEL_DEBUG log each beacon to stderr

Callers add their own opt-out on top; slicc-cli honors SLICC_NO_TELEMETRY=1 and never configures a client for a development build.

Development

npm run lint runs the slicc lint tools, gofmt, go mod tidy -diff, go vet and golangci-lint. npm test runs the integration tests in test/integration/ against a local collector. Unit tests stay next to the code and out of git (npm run test:unit). Releases are GitHub tags cut by semantic-release on main; the Go module proxy serves them.

Releases

semantic-release tags vX.Y.Z from conventional commits on main. The release fails unless the next major matches the module path: v0.x or v1.x without a suffix, exactly vN.x with a /vN suffix. A breaking change first needs the module path moved to /v2, and that change must itself be released as v2.0.0. After tagging, the workflow asks proxy.golang.org and pkg.go.dev to fetch the new version, best effort.

Never move or delete a pushed tag. sum.golang.org records the checksum of every version forever, so a moved tag breaks every build that fetches it. Retract a bad version with a retract directive in go.mod and cut a new release.

Documentation

Index

Constants

View Source
const (
	EnvRateKey  = "OPTEL_RATE"
	EnvDebugKey = "OPTEL_DEBUG"
)
View Source
const DefaultCollectBaseURL = "https://rum.hlx.page/"
View Source
const DefaultTimeout = 10 * time.Second
View Source
const DefaultWeight = 100
View Source
const MaxMessageLength = 200

Variables

This section is empty.

Functions

func BuildReferer

func BuildReferer(appID, viewPath string) string

func GenerateSessionID

func GenerateSessionID() string

func ParseWeight

func ParseWeight(rate string) int

func ResolveDebug

func ResolveDebug(environment map[string]string) bool

func ResolveRate

func ResolveRate(explicit string, environment map[string]string) string

func Sanitize

func Sanitize(msg string) string

Types

type Checkpoint

type Checkpoint string
const (
	Top         Checkpoint = "top"
	Enter       Checkpoint = "enter"
	Navigate    Checkpoint = "navigate"
	Reload      Checkpoint = "reload"
	CWV         Checkpoint = "cwv"
	PagesViewed Checkpoint = "pagesviewed"
	Click       Checkpoint = "click"
	ViewBlock   Checkpoint = "viewblock"
	ViewMedia   Checkpoint = "viewmedia"
	FormSubmit  Checkpoint = "formsubmit"
	Error       Checkpoint = "error"
)

type Client

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

func Configure

func Configure(appID string, opts Options) *Client

func (*Client) Flush

func (c *Client) Flush(timeout time.Duration)

func (*Client) ReportError

func (c *Client) ReportError(source string, err error)

func (*Client) Sample

func (c *Client) Sample(checkpoint Checkpoint, source, target string)

type Event

type Event struct {
	Weight     int        `json:"weight"`
	ID         string     `json:"id"`
	Referer    string     `json:"referer"`
	Checkpoint Checkpoint `json:"checkpoint"`
	T          int        `json:"t"`
	Source     string     `json:"source,omitempty"`
	Target     string     `json:"target,omitempty"`
}

type HTTPTransport

type HTTPTransport struct {
	Client  *http.Client
	Timeout time.Duration

	Debug func(format string, args ...any)
}

func NewHTTPTransport

func NewHTTPTransport(debug bool) *HTTPTransport

func (*HTTPTransport) Send

func (t *HTTPTransport) Send(event Event, collectBaseURL string, wg *sync.WaitGroup)

type Options

type Options struct {
	Rate string

	CollectBaseURL string

	Transport Transport

	RandomSource RandomSource

	Debug *bool

	Environment map[string]string
}

type RandomSource

type RandomSource interface {
	Float64() float64
}
var DefaultRandomSource RandomSource = systemRandomSource{}

type SamplingConfig

type SamplingConfig struct {
	Weight int
}

func NewSamplingConfig

func NewSamplingConfig(rate string) SamplingConfig

type Session

type Session struct {
	ID       string
	Weight   int
	Selected bool
}

func NewSession

func NewSession(id string, config SamplingConfig, random RandomSource) Session

type Transport

type Transport interface {
	Send(event Event, collectBaseURL string, wg *sync.WaitGroup)
}

Jump to

Keyboard shortcuts

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