Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,26 @@ jobs:

- name: Vet
run: go vet ./...

bpf-smoke:
name: BPF object smoke build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"

- name: Install BPF toolchain
run: |
sudo apt-get update
sudo apt-get install -y clang llvm linux-tools-generic libbpf-dev
sudo ln -sf $(ls /usr/lib/linux-tools/*/bpftool | head -n1) /usr/local/bin/bpftool

- name: Generate embedded BPF objects
run: make generate

- name: Build with embedded objects
run: go build -v ./...
11 changes: 11 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ jobs:
with:
go-version: "1.24"

- name: Install BPF toolchain
run: |
sudo apt-get update
sudo apt-get install -y clang llvm linux-tools-generic libbpf-dev
# linux-tools-generic installs bpftool under a kernel-versioned path;
# expose it on PATH for `make generate`.
sudo ln -sf $(ls /usr/lib/linux-tools/*/bpftool | head -n1) /usr/local/bin/bpftool

- name: Generate embedded BPF objects
run: make generate

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ coverage.out
dist/
demo.tape

# Generated BPF artifacts (produced by `make generate`)
internal/ebpf/bpf/*.o
internal/ebpf/c/vmlinux.h

# IDE
.idea/
.vscode/
Expand Down
26 changes: 21 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@ all: build
build:
go build -o melisai cmd/melisai/main.go

# Compile BPF programs
# Requires clang and llvm
# Ensure internal/ebpf/bpf directory exists
# Compile BPF programs into internal/ebpf/bpf/*.o for embedding via //go:embed.
# Requires (on the host running this target):
# - clang, llvm (apt: clang llvm)
# - bpftool (apt: linux-tools-generic, then ln -s to /usr/local/bin)
# - libbpf headers (apt: libbpf-dev)
# - kernel BTF (/sys/kernel/btf/vmlinux — kernel built with CONFIG_DEBUG_INFO_BTF=y)
#
# The generated vmlinux.h is host-kernel specific but the resulting .o is CO-RE
# (BPF Type Format-relocatable) and will run on any kernel with BTF support.
# macOS/dev machines without these tools should skip `make generate` — the
# build will then rely on the on-disk fallback in loader.go.
generate:
@command -v clang >/dev/null || { echo "ERROR: clang not found (install clang/llvm)"; exit 1; }
@command -v bpftool >/dev/null || { echo "ERROR: bpftool not found (install linux-tools-generic)"; exit 1; }
@test -f /sys/kernel/btf/vmlinux || { echo "ERROR: /sys/kernel/btf/vmlinux not present (kernel needs CONFIG_DEBUG_INFO_BTF=y)"; exit 1; }
mkdir -p internal/ebpf/bpf
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -I/usr/include/x86_64-linux-gnu \
-c internal/ebpf/c/tcpretrans.bpf.c -o internal/ebpf/bpf/tcpretrans.o
bpftool btf dump file /sys/kernel/btf/vmlinux format c > internal/ebpf/c/vmlinux.h
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 \
-I/usr/include/x86_64-linux-gnu \
-I internal/ebpf/c \
-c internal/ebpf/c/tcpretrans.bpf.c \
-o internal/ebpf/bpf/tcpretrans.o

test:
go test -race -count=1 -timeout 120s ./...
Expand All @@ -33,3 +48,4 @@ test-validation:
clean:
rm -f melisai
rm -f internal/ebpf/bpf/*.o
rm -f internal/ebpf/c/vmlinux.h
16 changes: 16 additions & 0 deletions cmd/melisai/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"os"
"runtime/pprof"
"strings"
"time"

Expand Down Expand Up @@ -82,6 +83,7 @@ Schema v1.1.0 with structured sub-objects for network, memory, GPU data.`,
collectMaxEvents int
collectQuiet bool
collectVerbose bool
collectPprof string
)

collectCmd := &cobra.Command{
Expand All @@ -104,6 +106,19 @@ Examples:
melisai collect --profile standard --focus network -o net.json
melisai collect --profile deep --pid 12345 -o app.json`,
RunE: func(cmd *cobra.Command, args []string) error {
// CPU profiling for performance analysis of melisai itself.
if collectPprof != "" {
f, err := os.Create(collectPprof)
if err != nil {
return fmt.Errorf("create pprof file: %w", err)
}
defer f.Close()
if err := pprof.StartCPUProfile(f); err != nil {
return fmt.Errorf("start cpu profile: %w", err)
}
defer pprof.StopCPUProfile()
}

cfg := collector.DefaultConfig()
cfg.Profile = collectProfile
cfg.Version = version
Expand Down Expand Up @@ -169,6 +184,7 @@ Examples:
collectCmd.Flags().IntVar(&collectMaxEvents, "max-events", 1000, "Max events per collector")
collectCmd.Flags().BoolVarP(&collectQuiet, "quiet", "q", false, "Suppress progress output")
collectCmd.Flags().BoolVarP(&collectVerbose, "verbose", "v", false, "Enable debug logging")
collectCmd.Flags().StringVar(&collectPprof, "pprof", "", "Write CPU profile to file (e.g. melisai_cpu.prof)")

// --- install command ---
var installDryRun bool
Expand Down
Loading
Loading