httpwatcher

package module
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

README

httpwatcher is a Go library to trace outbound HTTP requests of running Go processes. It attaches Linux eBPF uprobes to net/http.(*Client).do. A subset of the original http.Request is returned.

The library and eBPF code are written by Claude Code and Claude Sonnet 4.6.

Library usage

import "github.com/jamessanford/httpwatcher"

ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()

snoop, err := httpwatcher.Init(ctx)
if err != nil {
    log.Fatal(err)
}
defer snoop.Close()

snoop.Attach(pid)
snoop.Attach(pid2)

for ev := range snoop.Events() {
    fmt.Printf("%d %s %s\n", ev.PID, ev.Method, ev.URL)
    for k, v := range ev.Headers {
        fmt.Printf("  %s: %s\n", k, v)
    }
}

Events() returns a channel that is closed when the context is cancelled or Close is called.

Requirements

  • Linux with eBPF support (kernel 5.8+)
  • Root or CAP_BPF + CAP_PERFMON capabilities
  • Target processes must be Go 1.17+ (register-based calling convention)

Example command

example/cmd/httpwatcher is a sample CLI that wraps the library.

go build -o httpwatcher ./example/cmd/httpwatcher

# You may also install it:
# go install github.com/jamessanford/httpwatcher/example/cmd/httpwatcher@latest
# Find running Go processes
sudo ./httpwatcher

# Scan running Go processes and trace their HTTP requests
sudo ./httpwatcher --bpf

# Trace a specific PID
sudo ./httpwatcher --bpf --pid 1234
Trace HTTP outgoing requests of running Go processes

Usage:
  httpwatcher [flags] [pid...]

Flags:
      --bpf       Attach eBPF http uprobes
  -p, --pid       Inspect PIDs (default true)
  -j, --json      Output JSON
  -s, --sort      Sort output by Go version
      --debug     Log process scans to stderr
      --verbose   Include build settings in JSON
  -h, --help      help for httpwatcher

Documentation

Overview

Package httpwatcher traces outbound HTTP requests made by Go processes. It attaches Linux uprobes to net/http.(*Client).do using eBPF. The events returned are a subset of the original http.Request, with truncated strings and headers.

Basic usage:

ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
snoop, err := httpwatcher.Init(ctx)
if err != nil { ... }
defer snoop.Close()
if err := snoop.Attach(pid); err != nil { ... }
for ev := range snoop.Events() {
    fmt.Printf("%d %s %s\n", ev.PID, ev.Method, ev.URL)
    for k, v := range ev.Headers {
           fmt.Printf("  %s: %s\n", k, v)
       }
}
Example

Example output for a process making requests:

1234 GET https://192.168.100.55:8888/v1/users
  Authorization: Bearer XXXX
  Accept: application/json
package main

import (
	"context"
	"fmt"
	"log"
	"os/signal"
	"syscall"

	"github.com/jamessanford/httpwatcher"
)

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	snoop, err := httpwatcher.Init(ctx)
	if err != nil {
		log.Fatal(err)
	}
	defer snoop.Close()

	pid := 1234
	if err := snoop.Attach(pid); err != nil {
		log.Fatal(err)
	}

	for ev := range snoop.Events() {
		fmt.Printf("%d %s %s\n", ev.PID, ev.Method, ev.URL)
		for k, v := range ev.Headers {
			fmt.Printf("  %s: %s\n", k, v)
		}
	}
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type HTTPEvent

type HTTPEvent struct {
	PID     int               // PID of the process that issued the request
	Method  string            // HTTP method (e.g. "GET", "POST")
	URL     string            // Reconstructed URL; each component truncated to 64 bytes
	Headers map[string]string // Request headers; at most 16 entries, keys ≤64 bytes, values ≤512 bytes
}

HTTPEvent is an outbound HTTP request captured from an instrumented process.

type Snooper

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

Snooper manages uprobe-based HTTP request interception for multiple processes.

func Init

func Init(ctx context.Context) (*Snooper, error)

Init loads the uprobe BPF program and starts the event loop. The returned Snooper delivers events until ctx is cancelled or Close() is called, after which the Events channel is closed and all uprobe links are released.

func (*Snooper) Attach

func (s *Snooper) Attach(pid int) error

Attach installs an HTTP uprobe on the process with the given PID. It reads the binary's build info to verify Go version compatibility and resolve struct field offsets.

func (*Snooper) Close

func (s *Snooper) Close()

Close stops the event loop, closes the ring buffer, and releases all uprobe links. It waits for the event loop to exit and the Events channel to be closed before returning. Safe to call multiple times.

func (*Snooper) Events

func (s *Snooper) Events() <-chan HTTPEvent

Events returns the channel on which captured HTTP events are delivered. The channel is closed when the context passed to Init is cancelled or when Close is called.

Directories

Path Synopsis
example
cmd/httpwatcher command

Jump to

Keyboard shortcuts

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