detrix

package module
v1.1.1 Latest Latest
Warning

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

Go to latest
Published: Feb 26, 2026 License: MIT Imports: 14 Imported by: 0

README

Detrix Go Client

Go client library for Detrix debug-on-demand observability.

Installation

go get github.com/flashus/detrix/clients/go

Prerequisites:

  • Go 1.21+
  • Delve debugger (dlv) installed and in PATH

Install Delve:

go install github.com/go-delve/delve/cmd/dlv@latest

Quick Start

package main

import (
    "log"
    detrix "github.com/flashus/detrix/clients/go"
)

func main() {
    // Initialize client (starts control plane, stays SLEEPING)
    err := detrix.Init(detrix.Config{
        Name:      "my-service",
        DaemonURL: "http://127.0.0.1:8090",
    })
    if err != nil {
        log.Fatal(err)
    }
    defer detrix.Shutdown()

    // Your application code...
    runApp()
}

Try It

Run the end-to-end example that simulates an AI agent: starts a sample app, wakes it, adds metrics, and captures events.

# 1. Start the Detrix server
detrix serve --daemon

# 2. Build the Go fixture app (from clients/go/)
cd ../../fixtures/go && go build -gcflags="all=-N -l" -o detrix_example_app . && cd ../../clients/go

# 3. Run the agent simulation
go run ./examples/test_wake --daemon-port 8090

Other examples in examples/:

Example Description Run
basic_usage Init / wake / sleep cycle go run ./examples/basic_usage
trade_bot Long-running app with embedded client go run ./examples/trade_bot
test_wake Agent simulation (starts app, wakes, observes) go run ./examples/test_wake

API

Init(cfg Config) error

Initialize the Detrix client. Starts the control plane HTTP server in SLEEPING state.

detrix.Init(detrix.Config{
    Name:        "my-service",           // Connection name (default: "detrix-client-{pid}")
    DaemonURL:   "http://127.0.0.1:8090", // Daemon URL
    ControlHost: "127.0.0.1",             // Control plane host
    ControlPort: 0,                       // Control plane port (0 = auto)
    DebugPort:   0,                       // Debug adapter port (0 = auto)
})
Wake() (WakeResponse, error)

Start the debugger and register with the daemon.

resp, err := detrix.Wake()
if err != nil {
    log.Printf("Wake failed: %v", err)
}
fmt.Printf("Debug port: %d\n", resp.DebugPort)
Sleep() (SleepResponse, error)

Stop the debugger and unregister from the daemon.

resp, err := detrix.Sleep()
// Delve process is fully stopped (unlike Python's debugpy)
Status() StatusResponse

Get the current client status.

status := detrix.Status()
fmt.Printf("State: %s, Port: %d\n", status.State, status.ControlPort)
Shutdown() error

Stop the client and clean up resources.

detrix.Shutdown()

Environment Variables

Variable Description Default
DETRIX_NAME Connection name detrix-client-{pid}
DETRIX_DAEMON_URL Daemon URL http://127.0.0.1:8090
DETRIX_CONTROL_HOST Control plane host 127.0.0.1
DETRIX_CONTROL_PORT Control plane port 0 (auto)
DETRIX_DEBUG_PORT Debug adapter port 0 (auto)
DETRIX_TOKEN Auth token for remote access -
DETRIX_DELVE_PATH Path to dlv binary searches PATH
DETRIX_HOME Detrix home directory ~/detrix
DETRIX_HEALTH_CHECK_TIMEOUT Health check timeout (seconds) 2.0
DETRIX_REGISTER_TIMEOUT Registration timeout (seconds) 5.0
DETRIX_UNREGISTER_TIMEOUT Unregistration timeout (seconds) 2.0

Build Information

The client automatically detects build metadata (commit SHA, version tag) from:

  1. Explicit parameters (via Config.BuildCommit, Config.BuildTag)
  2. Environment variables:
    • DETRIX_BUILD_COMMIT / DETRIX_BUILD_TAG (recommended for Docker)
    • GIT_COMMIT, CI_COMMIT_SHA, GITHUB_SHA (CI auto-detection)
    • GIT_TAG, CI_COMMIT_TAG, GITHUB_REF_NAME (tag detection)
  3. Compile-time injection (via ldflags):
    go build -ldflags="-X github.com/flashus/detrix/clients/go.Version=1.0.0 \
      -X github.com/flashus/detrix/clients/go.BuildCommit=$(git rev-parse HEAD)"
    
  4. Runtime git detection (local dev only, requires .git directory)
Docker Example
FROM golang:1.21 AS builder
ARG GIT_COMMIT=unknown
ARG GIT_TAG=unknown

ENV DETRIX_BUILD_COMMIT=${GIT_COMMIT}
ENV DETRIX_BUILD_TAG=${GIT_TAG}

# These will be captured at build time
RUN go build -ldflags="-X main.BuildCommit=${GIT_COMMIT}" ./cmd/myapp

Build with:

docker build --build-arg GIT_COMMIT=$(git rev-parse HEAD) \
             --build-arg GIT_TAG=$(git describe --tags) .

Control Plane API

The client exposes an HTTP control plane (same as Python client):

Endpoint Method Auth Description
/detrix/health GET No Health check
/detrix/status GET Yes* Get current status
/detrix/info GET Yes* Get process info
/detrix/wake POST Yes* Start debugger
/detrix/sleep POST Yes* Stop debugger

*Localhost requests bypass authentication

Architecture

Unlike Python's debugpy which runs in-process, Go uses Delve as a separate process:

┌─────────────────────────────────────┐
│  Go Application                     │
│  ┌─────────────────────────────────┐│
│  │ Detrix Client                   ││
│  │ - Control plane HTTP server     ││
│  │ - Delve process manager         ││
│  └─────────────────────────────────┘│
└─────────────────────────────────────┘
        │ spawns & manages
        ↓
┌─────────────────────────────────────┐
│  Delve Process                      │
│  - Attaches via ptrace              │
│  - DAP server for Detrix daemon     │
└─────────────────────────────────────┘

Advantages over Python:

  • Can fully stop debugger on Sleep() (Python's debugpy cannot stop its listener)
  • Clean resource management
  • Fresh debugger state on each Wake()

Expression Evaluation

Go metrics use logpoints for fast, non-blocking evaluation:

// Simple variables - RECOMMENDED for production observability
addMetric(connID, file, 100, "symbol", "order_symbol", "go")
addMetric(connID, file, 101, "quantity", "order_qty", "go")
addMetric(connID, file, 102, "user.Name", "username", "go")
addMetric(connID, file, 103, "order.Price", "price", "go")

Characteristics:

  • Non-blocking (no pause in execution)
  • Minimal overhead
  • Production-safe
Function Calls (Supported but Blocking)

Detrix supports Go function calls via Delve's call command, but with important caveats:

// Function calls - WORK but BLOCK the process
addMetric(connID, file, 111, `len(symbol)`, "symbol_len", "go")
addMetric(connID, file, 112, `user.GetBalance()`, "balance", "go")
addMetric(connID, file, 113, `calculatePnl(entry, current, qty)`, "pnl", "go")

How it works:

  1. Detrix auto-detects function calls in expressions
  2. Uses breakpoint mode (pauses execution)
  3. Adds call prefix automatically for Delve DAP
  4. Resumes execution after evaluation

Warnings:

  • BLOCKS the target process while function executes
  • Delve marks this as "highly EXPERIMENTAL"
  • May cause issues with concurrent code
  • Better for debugging than production observability

Critical limitation - Variadic functions NOT supported:

// ❌ DOES NOT WORK - variadic functions fail with error like:
// "Unable to evaluate expression: can not convert value of type string to []interface {}"
addMetric(connID, file, 111, `fmt.Sprintf("%s x%d", symbol, qty)`, ...)
addMetric(connID, file, 112, `fmt.Println(symbol)`, ...)  // variadic

// ✅ WORKS - non-variadic functions
addMetric(connID, file, 111, `len(symbol)`, ...)           // builtin
addMetric(connID, file, 112, `user.GetBalance()`, ...)     // method
addMetric(connID, file, 113, `math.Sqrt(value)`, ...)      // fixed arity

Delve's call command cannot handle variadic functions (... parameters). The error is returned in the event value for easy debugging. See Delve Issue #2261.

When to use function calls:

  • Calling getters/methods that do simple calculations
  • Built-in functions like len(), cap()
  • User-defined functions with fixed parameter counts
  • One-off debugging sessions

Preferred alternative: Capture variables separately and format in your agent:

// Non-blocking approach - RECOMMENDED
addMetric(connID, file, 111, "symbol", "order_symbol", "go")
addMetric(connID, file, 112, "quantity", "order_qty", "go")
// Format in your analysis tool instead
Mixing Metric Modes

Detrix supports mixing simple variables (logpoint mode) and function calls (breakpoint mode) in the same file, as long as they're on different lines:

// Line 111: Simple variable - uses logpoint mode (non-blocking)
addMetric(connID, file, 111, "symbol", "order_symbol", "go")

// Line 116: Function call - uses breakpoint mode (blocking)
addMetric(connID, file, 116, "len(symbol)", "symbol_len", "go")

// Both work together! Each is processed independently.

How it works:

  1. When a metric is added, Detrix decides mode based on the expression:
    • Simple variable → logpoint (with logMessage)
    • Function call OR introspection → breakpoint (no logMessage)
  2. ALL breakpoints for the file are sent in one setBreakpoints request
  3. Logpoints capture via DAP output events (non-blocking)
  4. Breakpoints capture via DAP stopped events (pauses briefly)

Important constraints:

  • ⚠️ Only ONE metric per line (DAP limitation)
  • Metrics on the same line: last one wins
  • Function calls should be on different lines from simple variables
Introspection (Breakpoint Mode)

For stack traces and memory snapshots, Detrix uses breakpoint mode:

// With introspection - pauses briefly for data capture
addMetric(connID, file, 120, "pnl", "pnl_value", "go")
// + set captureStackTrace: true or captureMemorySnapshot: true
Technical Reference

Platform Notes

Linux

May require ptrace permissions:

# Check current setting
cat /proc/sys/kernel/yama/ptrace_scope

# If value is 1 or higher, Delve spawned by the client can still attach
# because it's a child process. No changes needed.
macOS

May need to grant Developer Tools access in System Preferences → Security & Privacy.

Testing

cd clients/go
go test ./...

License

MIT

Documentation

Overview

Package detrix provides the Detrix Go client for debug-on-demand observability.

This client enables Go applications to be observed by the Detrix daemon without any code modifications or performance overhead when inactive.

Basic usage:

import "github.com/anthropics/detrix-go"

func main() {
    // Initialize client (starts control plane, stays SLEEPING)
    err := detrix.Init(detrix.Config{
        Name:      "my-service",
        DaemonURL: "http://127.0.0.1:8090",
    })
    if err != nil {
        log.Fatal(err)
    }
    defer detrix.Shutdown()

    // ... your application code ...

    // When you need observability:
    resp, err := detrix.Wake()
    if err != nil {
        log.Printf("Wake failed: %v", err)
    }

    // When done:
    detrix.Sleep()
}

Unlike Python's debugpy, Delve can be fully stopped on Sleep(), providing cleaner resource management.

Index

Constants

View Source
const (
	WakeStatusAwake            = generated.Awake
	WakeStatusAlreadyAwake     = generated.AlreadyAwake
	SleepStatusSleeping        = generated.SleepResponseStatusSleeping
	SleepStatusAlreadySleeping = generated.SleepResponseStatusAlreadySleeping
)

Re-export status constants for convenience.

Variables

View Source
var (
	ErrNotInitialized     = errors.New("detrix client not initialized")
	ErrAlreadyInitialized = errors.New("detrix client already initialized")
	ErrWakeInProgress     = errors.New("wake operation already in progress")
)

Common errors

View Source
var (
	// Version is the client version (set via ldflags or defaults to "1.0.0")
	Version = "1.1.1"

	// BuildCommit is the git commit SHA (set via ldflags)
	BuildCommit = ""

	// BuildTime is when the binary was built (set via ldflags)
	BuildTime = ""
)

Version information (can be set via ldflags at build time)

Functions

func Init

func Init(cfg Config) error

Init initializes the Detrix client.

This starts the control plane HTTP server but does NOT contact the daemon. The client starts in SLEEPING state.

Configuration can also be provided via environment variables:

  • DETRIX_NAME
  • DETRIX_DAEMON_URL
  • DETRIX_CONTROL_HOST
  • DETRIX_CONTROL_PORT
  • DETRIX_DEBUG_PORT
  • DETRIX_DELVE_PATH
  • DETRIX_HOME
  • DETRIX_HEALTH_CHECK_TIMEOUT (seconds, e.g. "2.0")
  • DETRIX_REGISTER_TIMEOUT (seconds, e.g. "5.0")
  • DETRIX_UNREGISTER_TIMEOUT (seconds, e.g. "2.0")

Function parameters take precedence over environment variables.

func Shutdown

func Shutdown() error

Shutdown stops the client and cleans up resources.

Types

type ClientState

type ClientState = generated.ClientState

ClientState represents the client state.

type Config

type Config struct {
	// Name is the connection name (default: "detrix-client-{pid}")
	Name string

	// ControlHost is the host for the control plane server (default: "127.0.0.1")
	ControlHost string

	// AdvertiseHost is the host sent to the detrix server for registration.
	// If set, this is used instead of ControlHost when registering with the detrix server.
	// Useful in Docker/cloud where bind address (0.0.0.0) differs from
	// the reachable address (container hostname).
	AdvertiseHost string

	// ControlPort is the port for the control plane (0 = auto-assign)
	ControlPort int

	// DebugPort is the port for the debug adapter (0 = auto-assign)
	DebugPort int

	// DaemonURL is the URL of the Detrix daemon (default: "http://127.0.0.1:8090")
	DaemonURL string

	// DelvePath is the path to the dlv binary (default: searches PATH)
	DelvePath string

	// DetrixHome is the path to the Detrix home directory (default: ~/detrix)
	DetrixHome string

	// HealthCheckTimeout is the timeout for daemon health checks (default: 2s)
	HealthCheckTimeout time.Duration

	// RegisterTimeout is the timeout for connection registration (default: 5s)
	RegisterTimeout time.Duration

	// UnregisterTimeout is the timeout for connection unregistration (default: 2s)
	UnregisterTimeout time.Duration

	// DelveStartTimeout is the timeout for Delve to start (default: 10s)
	DelveStartTimeout time.Duration

	// SafeMode enables production-safe mode: only logpoints (non-blocking) are allowed.
	// Disables operations that require breakpoints: function calls, stack traces, memory snapshots.
	// Recommended for production environments where execution pauses are unacceptable.
	SafeMode bool

	// WorkspaceRoot overrides the workspace root sent to the daemon.
	// Default: current working directory (os.Getwd).
	// Set this in Docker/cloud where the CWD doesn't match the build source path.
	WorkspaceRoot string

	// BuildCommit allows explicit override of build commit detection (optional)
	BuildCommit string

	// BuildTag allows explicit override of build tag detection (optional)
	BuildTag string
}

Config holds client configuration.

type SleepResponse

type SleepResponse = generated.SleepResponse

SleepResponse is the response from a sleep operation. Type alias to generated type for API compatibility.

func Sleep

func Sleep() (SleepResponse, error)

Sleep stops the debugger and unregisters from the daemon.

Unlike Python's debugpy, Delve can be fully stopped, providing cleaner resource management.

type SleepStatus

type SleepStatus = generated.SleepResponseStatus

SleepStatus represents the status field in SleepResponse.

type StatusResponse

type StatusResponse = generated.StatusResponse

StatusResponse contains the current client status. Type alias to generated type for API compatibility.

func Status

func Status() StatusResponse

Status returns the current client status.

type WakeResponse

type WakeResponse = generated.WakeResponse

WakeResponse is the response from a wake operation. Type alias to generated type for API compatibility.

func Wake

func Wake() (WakeResponse, error)

Wake starts the debugger and registers with the daemon.

This spawns a Delve process to attach to the current process, then registers the connection with the Detrix daemon.

func WakeWithURL

func WakeWithURL(daemonURL string) (WakeResponse, error)

WakeWithURL starts the debugger with a daemon URL override.

type WakeStatus

type WakeStatus = generated.WakeResponseStatus

WakeStatus represents the status field in WakeResponse.

Directories

Path Synopsis
examples
basic command
Example basic demonstrates the Detrix Go client usage.
Example basic demonstrates the Detrix Go client usage.
basic_usage command
Example basic_usage demonstrates the Detrix Go client usage.
Example basic_usage demonstrates the Detrix Go client usage.
test_dap_eval command
Test DAP evaluate with function calls directly against Delve
Test DAP evaluate with function calls directly against Delve
test_wake command
Agent simulation test - wake a running Go app and observe it.
Agent simulation test - wake a running Go app and observe it.
trade_bot command
Long-running trading bot with Detrix client - runs until Ctrl+C
Long-running trading bot with Detrix client - runs until Ctrl+C
internal
auth
Package auth provides authentication utilities for the Detrix client.
Package auth provides authentication utilities for the Detrix client.
control
Package control provides the HTTP control plane server for the Detrix client.
Package control provides the HTTP control plane server for the Detrix client.
daemon
Package daemon provides HTTP client for communicating with the Detrix daemon.
Package daemon provides HTTP client for communicating with the Detrix daemon.
delve
Package delve provides Delve process lifecycle management.
Package delve provides Delve process lifecycle management.
generated
Package generated provides primitives to interact with the openapi HTTP API.
Package generated provides primitives to interact with the openapi HTTP API.
state
Package state provides thread-safe state management for the Detrix client.
Package state provides thread-safe state management for the Detrix client.

Jump to

Keyboard shortcuts

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