diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml new file mode 100644 index 00000000..d4a5437f --- /dev/null +++ b/.github/workflows/build-cli.yml @@ -0,0 +1,31 @@ +name: 📋 Build CLI + +on: + pull_request: + types: [ synchronize, opened, reopened, ready_for_review ] + +concurrency: + group: build-cli-${{ github.head_ref }} + cancel-in-progress: true + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + arch: amd64 + - os: ubuntu-24.04-arm + arch: arm64 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build and push + run: | + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:latest + docker build -t ${IMAGE}-${{matrix.arch}} -f tracing/cli/Dockerfile tracing diff --git a/.github/workflows/build.yml b/.github/workflows/build-extension.yml similarity index 84% rename from .github/workflows/build.yml rename to .github/workflows/build-extension.yml index 745f3d12..4164089b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build-extension.yml @@ -1,14 +1,11 @@ -name: 📋 Build +name: 📋 Build Extension on: pull_request: types: [ synchronize, opened, reopened, ready_for_review ] - push: - branches: - - 'patchy' concurrency: - group: build-test-${{ github.head_ref }} + group: build-extension-${{ github.head_ref }} cancel-in-progress: true env: @@ -31,4 +28,4 @@ jobs: - name: Build and push run: | IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:latest - docker build -t ${IMAGE}-${{matrix.arch}} --build-arg=PHP_VERSION=8.4 . + docker build -t ${IMAGE}-${{matrix.arch}} --build-arg=PHP_VERSION=8.4 extension diff --git a/.github/workflows/build-sidecar.yml b/.github/workflows/build-sidecar.yml new file mode 100644 index 00000000..be5488a9 --- /dev/null +++ b/.github/workflows/build-sidecar.yml @@ -0,0 +1,31 @@ +name: 📋 Build Sidecar + +on: + pull_request: + types: [ synchronize, opened, reopened, ready_for_review ] + +concurrency: + group: build-sidecar-${{ github.head_ref }} + cancel-in-progress: true + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + arch: amd64 + - os: ubuntu-24.04-arm + arch: arm64 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build and push + run: | + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:latest + docker build -t ${IMAGE}-${{matrix.arch}} -f tracing/sidecar/Dockerfile tracing diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index f3ccecf7..58c2d3fb 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -28,10 +28,6 @@ jobs: - name: ⬇️ Git clone the repository uses: actions/checkout@v4 - # Uncomment for CPU / Memory / IO statistics. - # - name: Collect Workflow Telemetry - # uses: catchpoint/workflow-telemetry-action@v2 - - name: 📁 Init run: | # Create performance testing results directory. @@ -40,11 +36,17 @@ jobs: - name: 📦 Build Images run: | + echo "Building base images" docker build -t localhost/compass:nginx-latest .github/workflows/performance/docker/compose/nginx docker build -t localhost/compass:php-fpm-latest .github/workflows/performance/docker/compose/php-fpm - docker build --no-cache --build-arg=PHP_VERSION=8.4 -t localhost/compass:latest . + + echo "Building extension" + docker build -t localhost/compass-extension:latest --build-arg=PHP_VERSION=8.4 extension docker build -t localhost/compass:php-fpm-ext-latest .github/workflows/performance/docker/compose/php-fpm-ext + echo "Building sidecar" + docker build -t localhost/compass-sidecar:latest -f tracing/sidecar/Dockerfile tracing + - name: 📦 Setup run: | cd .github/workflows/performance/matrix/${{ matrix.configuration }} diff --git a/.github/workflows/performance/docker/compose/php-fpm-ext/Dockerfile b/.github/workflows/performance/docker/compose/php-fpm-ext/Dockerfile index eeaa838f..16e21138 100644 --- a/.github/workflows/performance/docker/compose/php-fpm-ext/Dockerfile +++ b/.github/workflows/performance/docker/compose/php-fpm-ext/Dockerfile @@ -1,4 +1,4 @@ FROM localhost/compass:php-fpm-latest -COPY --from=localhost/compass:latest /etc/php/conf.d/00_compass.ini /etc/php/conf.d/00_compass.ini -COPY --from=localhost/compass:latest /usr/lib/php/modules/compass.so /usr/lib/php/modules/compass.so +COPY --from=localhost/compass-extension:latest /etc/php/conf.d/00_compass.ini /etc/php/conf.d/00_compass.ini +COPY --from=localhost/compass-extension:latest /usr/lib/php/modules/compass.so /usr/lib/php/modules/compass.so diff --git a/.github/workflows/performance/matrix/collector/docker-compose.yml b/.github/workflows/performance/matrix/collector/docker-compose.yml index 7142a736..3d58a1a1 100644 --- a/.github/workflows/performance/matrix/collector/docker-compose.yml +++ b/.github/workflows/performance/matrix/collector/docker-compose.yml @@ -31,7 +31,7 @@ services: retries: 60 compass: - image: localhost/compass:latest + image: localhost/compass-sidecar:latest network_mode: service:nginx privileged: true pid: "service:php-fpm" diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml new file mode 100644 index 00000000..45df478f --- /dev/null +++ b/.github/workflows/release-cli.yml @@ -0,0 +1,70 @@ +name: "📋 Release CLI" + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+[0-9A-Za-z]?' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + include: + - os: ubuntu-latest + arch: amd64 + - os: ubuntu-24.04-arm + arch: arm64 + + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: ⬇️ Git clone the repository + uses: actions/checkout@v4 + + - name: 🔐 Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: 📦 Build and Push + run: | + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:${{ github.ref_name }}-${{ matrix.arch }} + docker build --no-cache -t ${IMAGE} -f tracing/cli/Dockerfile tracing + docker push ${IMAGE} + + manifest: + name: Manifest + runs-on: ubuntu-latest + needs: build + + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: 🔐 Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: ☁️ Push + run: | + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:${{ github.ref_name }} + docker manifest create ${IMAGE} --amend ${IMAGE}-arm64 --amend ${IMAGE}-amd64 + docker manifest push ${IMAGE} diff --git a/.github/workflows/release.yml b/.github/workflows/release-extension.yml similarity index 87% rename from .github/workflows/release.yml rename to .github/workflows/release-extension.yml index 352bff32..c96bd9b5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release-extension.yml @@ -1,4 +1,4 @@ -name: "📋 Release" +name: "📋 Release Extension" on: push: @@ -7,7 +7,7 @@ on: env: REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} + IMAGE_NAME: ${{ github.repository }}-extension jobs: build: @@ -40,7 +40,8 @@ jobs: - name: 📦 Build run: | - IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:${{ github.ref_name }} + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}-extension:${{ github.ref_name }} + cd extension docker build --no-cache --build-arg=PHP_VERSION=8.4 -t ${IMAGE}-php8.4-${{ matrix.arch }} . docker build --no-cache --build-arg=PHP_VERSION=8.3 -t ${IMAGE}-php8.3-${{ matrix.arch }} . docker build --no-cache --build-arg=PHP_VERSION=8.2 -t ${IMAGE}-php8.2-${{ matrix.arch }} . @@ -48,7 +49,7 @@ jobs: - name: ☁️ Push run: | - IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:${{ github.ref_name }} + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}-extension:${{ github.ref_name }} docker push ${IMAGE}-php8.4-${{matrix.arch}} docker push ${IMAGE}-php8.3-${{matrix.arch}} docker push ${IMAGE}-php8.2-${{matrix.arch}} @@ -75,7 +76,7 @@ jobs: - name: ☁️ Push run: | - IMAGE=${{ env.REGISTRY }}/${{ github.repository }}:${{ github.ref_name }} + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}-extension:${{ github.ref_name }} docker manifest create ${IMAGE}-php8.4 --amend ${IMAGE}-php8.4-arm64 --amend ${IMAGE}-php8.4-amd64 docker manifest push ${IMAGE}-php8.4 docker manifest create ${IMAGE}-php8.3 --amend ${IMAGE}-php8.3-arm64 --amend ${IMAGE}-php8.3-amd64 diff --git a/.github/workflows/release-sidecar.yml b/.github/workflows/release-sidecar.yml new file mode 100644 index 00000000..c3ac3e78 --- /dev/null +++ b/.github/workflows/release-sidecar.yml @@ -0,0 +1,70 @@ +name: "📋 Release Sidecar" + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+[0-9A-Za-z]?' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + include: + - os: ubuntu-latest + arch: amd64 + - os: ubuntu-24.04-arm + arch: arm64 + + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: ⬇️ Git clone the repository + uses: actions/checkout@v4 + + - name: 🔐 Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: 📦 Build and Push + run: | + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}-sidecar:${{ github.ref_name }}-${{ matrix.arch }} + docker build --no-cache -t ${IMAGE} -f tracing/sidecar/Dockerfile tracing + docker push ${IMAGE} + + manifest: + name: Manifest + runs-on: ubuntu-latest + needs: build + + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: 🔐 Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: ☁️ Push + run: | + IMAGE=${{ env.REGISTRY }}/${{ github.repository }}-sidecar:${{ github.ref_name }} + docker manifest create ${IMAGE} --amend ${IMAGE}-arm64 --amend ${IMAGE}-amd64 + docker manifest push ${IMAGE} diff --git a/.gitignore b/.gitignore index 293431da..485dee64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1 @@ -/.idea -/.vscode -/vendor_output -/_output -/vendor +.idea diff --git a/README.md b/README.md index 0b7c0236..75f1dfd0 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ flowchart LR |-----------|---------|----------------------------| | Control | 49ms | | | Installed | 49ms | 0ms | -| Enabled | 50ms | 0ms | +| Enabled | 50ms | 1ms | | Collector | 57ms | 7ms | Performance data can be found in Github Actions for [this build](https://github.com/skpr/compass/pull/113). @@ -124,9 +124,16 @@ These images contain: * The collector (sidecar and CLI) ``` -ghcr.io/skpr/compass:extension-8.4-latest -ghcr.io/skpr/compass:extension-8.3-latest -ghcr.io/skpr/compass:extension-8.2-latest +# PHP extension +ghcr.io/skpr/compass-extension:VERSION-php8.4 +ghcr.io/skpr/compass-extension:VERSION-php8.3 +ghcr.io/skpr/compass-extension:VERSION-php8.2 + +# Sidecar +ghcr.io/skpr/compass-sidecar:VERSION + +# CLI +ghcr.io/skpr/compass:VERSION ``` ## How to test diff --git a/collector/scripts/bpftmpl/elf/notes.go b/collector/scripts/bpftmpl/elf/notes.go deleted file mode 100644 index bb18824c..00000000 --- a/collector/scripts/bpftmpl/elf/notes.go +++ /dev/null @@ -1,59 +0,0 @@ -// Package elf is used to handle elf output. -package elf - -import ( - "bufio" - "fmt" - "regexp" - "strings" -) - -// SystemTapNote represents a parsed SystemTap note with provider, name, and arguments -type SystemTapNote struct { - Provider string - Name string - Args []string -} - -// ReadNotes parses the output of "readelf -n" and extracts SystemTap probe arguments -func ReadNotes(input string) ([]SystemTapNote, error) { - scanner := bufio.NewScanner(strings.NewReader(input)) - var notes []SystemTapNote - - // Regex patterns to match relevant lines - providerPattern := regexp.MustCompile(`^\s*Provider:\s*(\S+)`) - namePattern := regexp.MustCompile(`^\s*Name:\s*(\S+)`) - argsPattern := regexp.MustCompile(`^\s*Arguments:\s*(.+)`) - - var currentNote *SystemTapNote - - for scanner.Scan() { - line := scanner.Text() - - if match := providerPattern.FindStringSubmatch(line); match != nil { - // If a new provider is found, finalize the previous note and start a new one - if currentNote != nil { - notes = append(notes, *currentNote) - } - currentNote = &SystemTapNote{ - Provider: match[1], - } - } else if match := namePattern.FindStringSubmatch(line); match != nil && currentNote != nil { - currentNote.Name = match[1] - } else if match := argsPattern.FindStringSubmatch(line); match != nil && currentNote != nil { - args := strings.Split(match[1], " ") - currentNote.Args = args - } - } - - // Add the last note if exists - if currentNote != nil { - notes = append(notes, *currentNote) - } - - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("error reading input: %w", err) - } - - return notes, nil -} diff --git a/collector/scripts/bpftmpl/elf/notes_test.go b/collector/scripts/bpftmpl/elf/notes_test.go deleted file mode 100644 index ad1d604f..00000000 --- a/collector/scripts/bpftmpl/elf/notes_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package elf - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestReadNotes(t *testing.T) { - input := `Displaying notes found in: .note.gnu.build-id - Owner Data size Description - GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) - Build ID: b7cd3dc63ad11bacdfbc7abe8d404b83d62b0b5c - -Displaying notes found in: .note.stapsdt - Owner Data size Description - stapsdt 0x00000044 NT_STAPSDT (SystemTap probe descriptors) - Provider: compass - Name: request_shutdown - Location: 0x000000000000c9f8, Base: 0x0000000000058393, Semaphore: 0x00000000000801c6 - Arguments: -8@x8 -8@x21 -8@x0 - stapsdt 0x00000041 NT_STAPSDT (SystemTap probe descriptors) - Provider: compass - Name: php_function - Location: 0x000000000000d8e8, Base: 0x0000000000058393, Semaphore: 0x00000000000801c8 - Arguments: -8@x20 -8@x0 -8@x21` - - have, err := ReadNotes(input) - assert.NoError(t, err) - - want := []SystemTapNote{ - { - Provider: "compass", - Name: "request_shutdown", - Args: []string{ - "-8@x8", - "-8@x21", - "-8@x0", - }, - }, - { - Provider: "compass", - Name: "php_function", - Args: []string{ - "-8@x20", - "-8@x0", - "-8@x21", - }, - }, - } - - assert.Equal(t, want, have) -} diff --git a/collector/scripts/bpftmpl/main.go b/collector/scripts/bpftmpl/main.go deleted file mode 100644 index 57f05196..00000000 --- a/collector/scripts/bpftmpl/main.go +++ /dev/null @@ -1,45 +0,0 @@ -// Package main is used to generate a multi arch bpf program. -package main - -import ( - "flag" - "fmt" - "io" - "os" - - "github.com/skpr/compass/collector/scripts/bpftmpl/elf" - "github.com/skpr/compass/collector/scripts/bpftmpl/replace" -) - -func main() { - var ( - flagArch = flag.String("arch", "", "architecture which we will build with") - flagTemplate = flag.String("template", "", "path to the bpf program template") - ) - - flag.Parse() - - extension, err := io.ReadAll(os.Stdin) - if err != nil { - panic(err) - } - - template, err := os.ReadFile(*flagTemplate) - if err != nil { - panic(err) - } - - // Parse the output - notes, err := elf.ReadNotes(string(extension)) - if err != nil { - panic(err) - } - - program, err := replace.UsingNotes(*flagArch, notes, string(template)) - if err != nil { - panic(err) - } - - // Write the file contents to stdout. - fmt.Print(program) -} diff --git a/collector/scripts/bpftmpl/replace/replace.go b/collector/scripts/bpftmpl/replace/replace.go deleted file mode 100644 index 4109b2ac..00000000 --- a/collector/scripts/bpftmpl/replace/replace.go +++ /dev/null @@ -1,99 +0,0 @@ -// Package replace is used to find and replace program values. -package replace - -import ( - "fmt" - "strings" - - "github.com/skpr/compass/collector/scripts/bpftmpl/elf" -) - -// UsingNotes replaces strings in the program based on provided notes. -func UsingNotes(arch string, notes []elf.SystemTapNote, program string) (string, error) { - replacements := make(map[string]string, 8) - - valueFunc, err := getValueFunc(arch) - if err != nil { - return "", err - } - - for _, note := range notes { - if note.Provider != "compass" { - return "", fmt.Errorf("found a note which is not provided by compass") - } - - switch note.Name { - case "request_init": - if len(note.Args) != 3 { - return "", fmt.Errorf("request_init does not have 3 args") - } - - replacements["REQUEST_INIT_ARG_REQUEST_ID"] = valueFunc(note.Args[0]) - replacements["REQUEST_INIT_ARG_URI"] = valueFunc(note.Args[1]) - replacements["REQUEST_INIT_ARG_METHOD"] = valueFunc(note.Args[2]) - - case "php_function": - if len(note.Args) != 3 { - return "", fmt.Errorf("php_fuction does not have 3 args") - } - - replacements["PHP_FUNCTION_ARG_REQUEST_ID"] = valueFunc(note.Args[0]) - replacements["PHP_FUNCTION_ARG_FUNCTION_NAME"] = valueFunc(note.Args[1]) - replacements["PHP_FUNCTION_ARG_ELAPSED"] = valueFunc(note.Args[2]) - - case "request_shutdown": - if len(note.Args) != 1 { - return "", fmt.Errorf("request_shutdown does not have 1 arg") - } - - replacements["REQUEST_SHUTDOWN_ARG_REQUEST_ID"] = valueFunc(note.Args[0]) - - // These probes don't have any args. - case "canary": - continue - - default: - return "", fmt.Errorf("found a note which is not on our replace list: %s", note) - } - } - - for key, value := range replacements { - program = strings.ReplaceAll(program, key, value) - } - - return program, nil -} - -func getValueFunc(arch string) (func(string) string, error) { - if arch == "arm64" { - return func(argument string) string { - return fmt.Sprintf("regs[%s]", strings.TrimPrefix(argument, "-8@x")) - }, nil - } - - if arch == "amd64" { - return func(argument string) string { - switch argument { - case "-8@%rax": - return "ax" - case "-8@%rdi": - return "di" - case "-8@%rsi": - return "ax" - case "-8@%rdx": - return "dx" - case "-8@%rbx": - return "bx" - case "-8@%rbp": - return "bp" - case "-8@%rcx": - return "cx" - default: - // Preserve the "r" in the remaining eg. r15. - return strings.TrimPrefix(argument, "-8@%") - } - }, nil - } - - return nil, fmt.Errorf("architecture not supported: %s", arch) -} diff --git a/collector/scripts/bpftmpl/replace/replace_test.go b/collector/scripts/bpftmpl/replace/replace_test.go deleted file mode 100644 index 45a827d7..00000000 --- a/collector/scripts/bpftmpl/replace/replace_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package replace - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/skpr/compass/collector/scripts/bpftmpl/elf" -) - -func TestUsingNotesAmd64(t *testing.T) { - notes := []elf.SystemTapNote{ - { - Provider: "compass", - Name: "request_init", - Args: []string{ - "-8@%rbx", - "-8@%r14", - "-8@%rdi", - }, - }, - { - Provider: "compass", - Name: "request_shutdown", - Args: []string{ - "-8@%rbx", - }, - }, - { - Provider: "compass", - Name: "php_function", - Args: []string{ - "-8@%rbx", - "-8@%rax", - "-8@%rbp", - }, - }, - } - - replacements := []string{ - "REQUEST_INIT_ARG_REQUEST_ID", - "REQUEST_INIT_ARG_URI", - "REQUEST_INIT_ARG_METHOD", - "PHP_FUNCTION_ARG_FUNCTION_NAME", - "PHP_FUNCTION_ARG_ELAPSED", - "REQUEST_SHUTDOWN_ARG_REQUEST_ID", - } - - program, err := UsingNotes("amd64", notes, strings.Join(replacements, ",")) - assert.NoError(t, err) - assert.Equal(t, "bx,r14,di,ax,bp,bx", program) -} - -func TestUsingNotesArm64(t *testing.T) { - notes := []elf.SystemTapNote{ - { - Provider: "compass", - Name: "request_init", - Args: []string{ - "-8@x19", - "-8@x20", - "-8@x0", - }, - }, - { - Provider: "compass", - Name: "request_shutdown", - Args: []string{ - "-8@x19", - }, - }, - { - Provider: "compass", - Name: "php_function", - Args: []string{ - "-8@x20", - "-8@x0", - "-8@x24", - }, - }, - } - - replacements := []string{ - "REQUEST_INIT_ARG_REQUEST_ID", - "REQUEST_INIT_ARG_URI", - "REQUEST_INIT_ARG_METHOD", - "PHP_FUNCTION_ARG_FUNCTION_NAME", - "PHP_FUNCTION_ARG_ELAPSED", - "REQUEST_SHUTDOWN_ARG_REQUEST_ID", - } - - program, err := UsingNotes("arm64", notes, strings.Join(replacements, ",")) - assert.NoError(t, err) - assert.Equal(t, "regs[19],regs[20],regs[0],regs[0],regs[24],regs[19]", program) -} diff --git a/docker-compose.yml b/docker-compose.yml index 36a1456d..f67bffcb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,14 +7,16 @@ services: - "28624:28624" php-fpm: - build: ./docker/compose + build: ./docker/compose/php-fpm network_mode: service:nginx environment: - COMPASS_ENABLED=true - RUST_BACKTRACE=1 # Debugging - compass: - image: local/compass:latest + sidecar: + build: + dockerfile: sidecar/Dockerfile + context: tracing # environment: # - COMPASS_SIDECAR_TOKEN=xxxyyyzzz network_mode: service:nginx @@ -24,21 +26,18 @@ services: depends_on: - php-fpm + compass: + build: + dockerfile: cli/Dockerfile + context: tracing + command: /bin/bash -c "sleep infinity" + network_mode: service:nginx + depends_on: + - sidecar + curl: image: alpine:latest network_mode: service:nginx command: sh -c "apk add --no-cache curl && curl -v http://localhost:28624/v1/traces" depends_on: - compass - - jaeger: - image: jaegertracing/all-in-one:1.63.0 - restart: always - environment: - - COLLECTOR_OTLP_ENABLED=true - ports: - - "16686:16686" - - "4317:4317" - - "4318:4318" - profiles: - - otel diff --git a/docker/compose/Dockerfile b/docker/compose/php-fpm/Dockerfile similarity index 75% rename from docker/compose/Dockerfile rename to docker/compose/php-fpm/Dockerfile index b3c55fb4..505aaa73 100644 --- a/docker/compose/Dockerfile +++ b/docker/compose/php-fpm/Dockerfile @@ -18,5 +18,5 @@ COPY drush /etc/drush RUN PHP_MEMORY_LIMIT=-1 vendor/bin/drush si demo_umami --db-url=sqlite://sites/default/files/.ht.sqlite -COPY --from=local/compass:latest /etc/php/conf.d/00_compass.ini /etc/php/conf.d/00_compass.ini -COPY --from=local/compass:latest /usr/lib/php/modules/compass.so /usr/lib/php/modules/compass.so \ No newline at end of file +COPY --from=localhost/compass-extension:latest /etc/php/conf.d/00_compass.ini /etc/php/conf.d/00_compass.ini +COPY --from=localhost/compass-extension:latest /usr/lib/php/modules/compass.so /usr/lib/php/modules/compass.so diff --git a/docker/compose/drush/drushrc.yml b/docker/compose/php-fpm/drush/drushrc.yml similarity index 100% rename from docker/compose/drush/drushrc.yml rename to docker/compose/php-fpm/drush/drushrc.yml diff --git a/docker/compose/services.yml b/docker/compose/php-fpm/services.yml similarity index 100% rename from docker/compose/services.yml rename to docker/compose/php-fpm/services.yml diff --git a/docker/compose/settings.php b/docker/compose/php-fpm/settings.php similarity index 100% rename from docker/compose/settings.php rename to docker/compose/php-fpm/settings.php diff --git a/extension/.devcontainer/Dockerfile b/extension/.devcontainer/Dockerfile new file mode 100644 index 00000000..12a86ab5 --- /dev/null +++ b/extension/.devcontainer/Dockerfile @@ -0,0 +1,21 @@ +FROM ghcr.io/skpr/php-cli:8.4-v2-stable + +USER root + +RUN apk add alpine-sdk \ + clang \ + clang-dev \ + git \ + php8.4-dev + +ENV MISE_DATA_DIR="/mise" +ENV MISE_CONFIG_DIR="/mise" +ENV MISE_CACHE_DIR="/mise/cache" +ENV MISE_INSTALL_PATH="/usr/local/bin/mise" +ENV PATH="/mise/shims:$PATH" + +RUN curl https://mise.run | sh + +ENV RUSTFLAGS="-C target-feature=-crt-static" + +ENV RUST_BACKTRACE=full diff --git a/extension/.devcontainer/devcontainer.json b/extension/.devcontainer/devcontainer.json new file mode 100644 index 00000000..d0b49b37 --- /dev/null +++ b/extension/.devcontainer/devcontainer.json @@ -0,0 +1,13 @@ +{ + "build": { + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "dustypomerleau.rust-syntax" + ] + } + } +} diff --git a/extension/.dockerignore b/extension/.dockerignore new file mode 100644 index 00000000..ee44a963 --- /dev/null +++ b/extension/.dockerignore @@ -0,0 +1,2 @@ +.idea +target diff --git a/extension/.gitignore b/extension/.gitignore index d81f12ed..06f5fec0 100644 --- a/extension/.gitignore +++ b/extension/.gitignore @@ -1,2 +1,3 @@ /target /.idea +/.vscode diff --git a/extension/Dockerfile b/extension/Dockerfile new file mode 100644 index 00000000..15a1801b --- /dev/null +++ b/extension/Dockerfile @@ -0,0 +1,31 @@ +ARG PHP_VERSION=8.3 +FROM ghcr.io/skpr/php-cli:${PHP_VERSION}-v2-stable AS build + +ARG PHP_VERSION=8.3 + +USER root + +RUN apk add alpine-sdk clang clang-dev php${PHP_VERSION}-dev + +ENV MISE_DATA_DIR="/mise" +ENV MISE_CONFIG_DIR="/mise" +ENV MISE_CACHE_DIR="/mise/cache" +ENV MISE_INSTALL_PATH="/usr/local/bin/mise" +ENV PATH="/mise/shims:$PATH" + +RUN curl https://mise.run | sh + +ENV RUSTFLAGS="-C target-feature=-crt-static" +ENV RUST_BACKTRACE=full + +ADD --chown=skpr:skpr . /data +RUN mise trust . + +RUN mise run lint +RUN mise run build +RUN mise run validate + +FROM ghcr.io/skpr/php-cli:${PHP_VERSION}-v2-stable + +COPY compass.ini /etc/php/conf.d/00_compass.ini +COPY --from=build /data/target/release/libcompass_extension.so /usr/lib/php/modules/compass.so diff --git a/extension/mise.toml b/extension/mise.toml new file mode 100644 index 00000000..e023ee1b --- /dev/null +++ b/extension/mise.toml @@ -0,0 +1,16 @@ +[tools] +rust = "1.91.1" +"ubi:nickschuch/noteutils" = { version = "0.0.1" } + +[tasks.lint] +description = "Run linting on all packages and crates" +run = "cargo fmt --all -- --check" + +[tasks.build] +description = "Build Compass binaries" +run = "cargo build --release" + +[tasks.validate] +description = "Validate notes for probing" +run = "noteutils validate --spec noteutils.yml target/release/libcompass_extension.so" +depends = ["build"] diff --git a/extension/noteutils.yml b/extension/noteutils.yml new file mode 100644 index 00000000..904c2bd2 --- /dev/null +++ b/extension/noteutils.yml @@ -0,0 +1,40 @@ +probes: + amd64: + - provider: compass + name: canary + - provider: compass + name: request_init + arguments: + - -8@%rcx + - -8@%r15 + - -8@%rax + - provider: compass + name: request_shutdown + arguments: + - -8@%rax + - provider: compass + name: php_function + arguments: + - -8@%r14 + - -8@%rax + - -8@%r15 + + arm64: + - provider: compass + name: canary + - provider: compass + name: request_init + arguments: + - -8@x8 + - -8@x21 + - -8@x0 + - provider: compass + name: request_shutdown + arguments: + - -8@x8 + - provider: compass + name: php_function + arguments: + - -8@x20 + - -8@x0 + - -8@x21 diff --git a/extension/validate.sh b/extension/validate.sh deleted file mode 100644 index dcffa49a..00000000 --- a/extension/validate.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -# A script for ensuring our arguments have not drifted. - -# # $ readelf -n /usr/lib/php/modules/compass.so -# -# Displaying notes found in: .note.gnu.build-id -# Owner Data size Description -# GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) -# Build ID: 683683921402ecea6a67b3665438f3fba7461e0e -# -# Displaying notes found in: .note.stapsdt -# Owner Data size Description -# stapsdt 0x00000049 NT_STAPSDT (SystemTap probe descriptors) -# Provider: compass -# Name: request_shutdown -# Location: 0x000000000000f0b8, Base: 0x0000000000063477, Semaphore: 0x0000000000000000 -# Arguments: -8@%rbx -8@%r14 -8@%rdi -# stapsdt 0x00000055 NT_STAPSDT (SystemTap probe descriptors) -# Provider: compass -# Name: php_function -# Location: 0x000000000001004e, Base: 0x0000000000063477, Semaphore: 0x0000000000000000 -# Arguments: -8@%rbx -8@%r14 -8@%rax -8@%r13 -8@%rbp - -FILE=$1 - -# Validate request_shutdown args. -if readelf -n ${FILE} | grep -q 'Arguments: -8@%rbx -8@%r14 -8@%rdi'; then - echo "request_shutdown args are correct" -else - echo "request_shutdown args are incorrect. We found:" - readelf -n ${FILE} - exit 1 -fi - -# Validate php_function args. -if readelf -n ${FILE} | grep -q 'Arguments: -8@%rbx -8@%r14 -8@%rax -8@%r13 -8@%rbp'; then - echo "php_function args are correct" -else - echo "php_function args are incorrect. We found:" - readelf -n ${FILE} - exit 1 -fi \ No newline at end of file diff --git a/mise.toml b/mise.toml index 5524f6f0..dcdd12f6 100644 --- a/mise.toml +++ b/mise.toml @@ -1,73 +1,23 @@ -[tools] -go = "1.24" -rust = "1.91.1" -"go:github.com/cilium/ebpf/cmd/bpf2go" = { version = "v0.19.0" } -"ubi:golangci/golangci-lint" = "2.6.2" - -[env] -CGO_ENABLED = 0 - -[tasks."go:vendor"] -description = "Vendor resets the main module's vendor directory to include all packages needed to build the application" -run = "go mod vendor" - [tasks.up] -description = "Build and start a local development stack" -run = [ - "docker build --progress=plain -t local/compass:latest .", - "docker compose build php-fpm", - "docker compose up" -] - -[tasks.down] -description = "Stop the local development stack" -run = "docker compose down" - -[tasks.lint] description = "Run linting on all packages and crates" -depends = [ - "lint:collector", - "lint:extension" -] - -[tasks."lint:collector"] -description = "Run linting on all collector components" -run = "golangci-lint run" -depends = ["generate", "go:vendor"] +run = ''' +#!/usr/bin/env bash -[tasks."lint:extension"] -description = "Run linting on the extension" -run = "cargo fmt --all -- --check" -dir = "extension" -depends = ["generate"] +echo "Building Extension" +docker build -t localhost/compass-extension:latest --build-arg=PHP_VERSION=8.3 extension -[tasks.test] -description = "Run tests for all components" -run = "go test ./cli/... ./collector/... ./trace/... ./sidecar/..." -depends = ["generate"] +echo "Building Docker Compose Service: php-fpm" +docker compose build php-fpm -[tasks.generate] -description = "Generate BPF artifacts" -file = "scripts/generate.sh" -depends = ["go:vendor"] +echo "Building Docker Compose Service: sidecar" +docker compose build sidecar -[tasks.build] -description = "Build Compass binaries" -depends = [ - "build:extension", - "build:collector", -] +echo "Building Docker Compose Service: compass" +docker compose build compass -[tasks."build:extension"] -description = "Build Compass extension" -run = "cargo build --release" -dir = "extension" -depends = ["generate", "go:vendor"] +docker compose up +''' -[tasks."build:collector"] -description = "Build Compass collector components" -run = [ - "go build -a -o _output/compass github.com/skpr/compass/cli", - "go build -a -o _output/compass-sidecar github.com/skpr/compass/sidecar" -] -depends = ["generate"] +[tasks.down] +description = "Build Compass binaries" +run = "docker compose down" diff --git a/scripts/generate.sh b/scripts/generate.sh deleted file mode 100755 index 7cf52b3a..00000000 --- a/scripts/generate.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -arch="$(uname -m)" - -case "$arch" in - x86_64) - ARCH="amd64" - ;; - arm64 | aarch64) - ARCH="arm64" - ;; - *) - echo "Unknown architecture: $arch" - ARCH="unknown" - ;; -esac - -cd collector - -bpftool btf dump file /sys/kernel/btf/vmlinux format c > ./includes/vmlinux.h -readelf -n /usr/lib/php/modules/compass.so | go run ./scripts/bpftmpl -arch="${ARCH}" -template=./template.bpf.c > ./program.bpf.c -GOPACKAGE=collector bpf2go -target "${ARCH}" -cflags "-O2 -g -Wall -Werror" -type event bpf program.bpf.c -- -I./includes diff --git a/.devcontainer/Dockerfile b/tracing/.devcontainer/Dockerfile similarity index 74% rename from .devcontainer/Dockerfile rename to tracing/.devcontainer/Dockerfile index df0d0de8..d32e43c4 100644 --- a/.devcontainer/Dockerfile +++ b/tracing/.devcontainer/Dockerfile @@ -1,16 +1,17 @@ -FROM ghcr.io/skpr/php-cli:8.4-v2-stable +FROM alpine:3.21 USER root RUN apk add alpine-sdk \ + bash \ bpftool \ clang \ clang-dev \ + curl \ git \ libbpf-dev \ linux-headers \ - llvm \ - php8.4-dev + llvm ENV MISE_DATA_DIR="/mise" ENV MISE_CONFIG_DIR="/mise" @@ -22,7 +23,3 @@ RUN curl https://mise.run | sh # Make libclang easy to find for bindgen ENV LIBCLANG_PATH=/usr/lib/llvm19/lib - -ENV RUSTFLAGS="-C target-feature=-crt-static" - -ENV RUST_BACKTRACE=full diff --git a/.devcontainer/devcontainer.json b/tracing/.devcontainer/devcontainer.json similarity index 72% rename from .devcontainer/devcontainer.json rename to tracing/.devcontainer/devcontainer.json index 3551ddbd..4000f595 100644 --- a/.devcontainer/devcontainer.json +++ b/tracing/.devcontainer/devcontainer.json @@ -5,8 +5,6 @@ "customizations": { "vscode": { "extensions": [ - "rust-lang.rust-analyzer", - "dustypomerleau.rust-syntax", "golang.go", "nicknickolaev.ebpf-assembly" ] diff --git a/.dockerignore b/tracing/.dockerignore similarity index 100% rename from .dockerignore rename to tracing/.dockerignore diff --git a/tracing/.gitignore b/tracing/.gitignore new file mode 100644 index 00000000..293431da --- /dev/null +++ b/tracing/.gitignore @@ -0,0 +1,5 @@ +/.idea +/.vscode +/vendor_output +/_output +/vendor diff --git a/.golangci.yml b/tracing/.golangci.yml similarity index 100% rename from .golangci.yml rename to tracing/.golangci.yml diff --git a/tracing/cli/Dockerfile b/tracing/cli/Dockerfile new file mode 100644 index 00000000..3b420b79 --- /dev/null +++ b/tracing/cli/Dockerfile @@ -0,0 +1,41 @@ +FROM alpine:3.21 AS build + +USER root + +RUN apk add alpine-sdk \ + bash \ + bpftool \ + clang \ + clang-dev \ + curl \ + git \ + libbpf-dev \ + linux-headers \ + llvm + +ENV MISE_DATA_DIR="/mise" +ENV MISE_CONFIG_DIR="/mise" +ENV MISE_CACHE_DIR="/mise/cache" +ENV MISE_INSTALL_PATH="/usr/local/bin/mise" +ENV PATH="/mise/shims:$PATH" + +RUN curl https://mise.run | sh + +# Make libclang easy to find for bindgen +ENV LIBCLANG_PATH=/usr/lib/llvm19/lib + +ENV GOFLAGS=-buildvcs=false + +WORKDIR /data +ADD --chown=skpr:skpr . /data + +# Check and build. +RUN mise trust . +RUN mise run lint +RUN mise run test +RUN mise run build:cli + +FROM alpine:3.21 +RUN apk add bash +COPY --from=build /data/_output/compass /usr/local/bin/compass +CMD ["compass"] diff --git a/cli/app/app.go b/tracing/cli/app/app.go similarity index 100% rename from cli/app/app.go rename to tracing/cli/app/app.go diff --git a/cli/app/color/color.go b/tracing/cli/app/color/color.go similarity index 100% rename from cli/app/color/color.go rename to tracing/cli/app/color/color.go diff --git a/cli/app/component/span/span.go b/tracing/cli/app/component/span/span.go similarity index 100% rename from cli/app/component/span/span.go rename to tracing/cli/app/component/span/span.go diff --git a/cli/app/component/span/utils.go b/tracing/cli/app/component/span/utils.go similarity index 100% rename from cli/app/component/span/utils.go rename to tracing/cli/app/component/span/utils.go diff --git a/cli/app/component/table/delegate.go b/tracing/cli/app/component/table/delegate.go similarity index 93% rename from cli/app/component/table/delegate.go rename to tracing/cli/app/component/table/delegate.go index abc9b195..6f041edb 100644 --- a/cli/app/component/table/delegate.go +++ b/tracing/cli/app/component/table/delegate.go @@ -5,7 +5,7 @@ import ( "github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" + "github.com/skpr/compass/tracing/cli/app/color" ) // GetItemDeletegate for formatting. diff --git a/cli/app/events/log.go b/tracing/cli/app/events/log.go similarity index 100% rename from cli/app/events/log.go rename to tracing/cli/app/events/log.go diff --git a/cli/app/events/trace.go b/tracing/cli/app/events/trace.go similarity index 86% rename from cli/app/events/trace.go rename to tracing/cli/app/events/trace.go index c2f9250b..8c0dfd23 100644 --- a/cli/app/events/trace.go +++ b/tracing/cli/app/events/trace.go @@ -4,8 +4,8 @@ import ( "fmt" "time" - skprtime "github.com/skpr/compass/cli/app/time" - "github.com/skpr/compass/trace" + skprtime "github.com/skpr/compass/tracing/cli/app/time" + "github.com/skpr/compass/tracing/trace" ) // Trace for review. diff --git a/cli/app/footer.go b/tracing/cli/app/footer.go similarity index 93% rename from cli/app/footer.go rename to tracing/cli/app/footer.go index 5ff8cbec..f953aadc 100644 --- a/cli/app/footer.go +++ b/tracing/cli/app/footer.go @@ -5,7 +5,7 @@ import ( "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" + "github.com/skpr/compass/tracing/cli/app/color" ) var ( diff --git a/cli/app/init.go b/tracing/cli/app/init.go similarity index 85% rename from cli/app/init.go rename to tracing/cli/app/init.go index 32bf1ac4..7f61b3db 100644 --- a/cli/app/init.go +++ b/tracing/cli/app/init.go @@ -3,7 +3,7 @@ package app import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" + "github.com/skpr/compass/tracing/cli/app/events" ) // Init initializes the model. diff --git a/cli/app/logger/logger.go b/tracing/cli/app/logger/logger.go similarity index 95% rename from cli/app/logger/logger.go rename to tracing/cli/app/logger/logger.go index f214944b..98430efc 100644 --- a/cli/app/logger/logger.go +++ b/tracing/cli/app/logger/logger.go @@ -7,7 +7,7 @@ import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" + "github.com/skpr/compass/tracing/cli/app/events" ) // Logger for sending events into the CLI application. diff --git a/cli/app/logs.go b/tracing/cli/app/logs.go similarity index 83% rename from cli/app/logs.go rename to tracing/cli/app/logs.go index 208aaa61..245a3980 100644 --- a/cli/app/logs.go +++ b/tracing/cli/app/logs.go @@ -4,8 +4,8 @@ import ( "github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" - "github.com/skpr/compass/cli/app/component/table" + "github.com/skpr/compass/tracing/cli/app/color" + "github.com/skpr/compass/tracing/cli/app/component/table" ) func (m *Model) logsInit() { diff --git a/cli/app/menu.go b/tracing/cli/app/menu.go similarity index 97% rename from cli/app/menu.go rename to tracing/cli/app/menu.go index 471e7ebc..29e28a78 100644 --- a/cli/app/menu.go +++ b/tracing/cli/app/menu.go @@ -6,7 +6,7 @@ import ( "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" + "github.com/skpr/compass/tracing/cli/app/color" ) var ( diff --git a/cli/app/metadata.go b/tracing/cli/app/metadata.go similarity index 94% rename from cli/app/metadata.go rename to tracing/cli/app/metadata.go index 59c2319a..7f2d0717 100644 --- a/cli/app/metadata.go +++ b/tracing/cli/app/metadata.go @@ -7,8 +7,8 @@ import ( "github.com/charmbracelet/bubbles/table" "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" - skprtime "github.com/skpr/compass/cli/app/time" + "github.com/skpr/compass/tracing/cli/app/color" + skprtime "github.com/skpr/compass/tracing/cli/app/time" ) func (m *Model) metadataInit() { diff --git a/cli/app/model.go b/tracing/cli/app/model.go similarity index 93% rename from cli/app/model.go rename to tracing/cli/app/model.go index db37440a..bfc05783 100644 --- a/cli/app/model.go +++ b/tracing/cli/app/model.go @@ -5,7 +5,7 @@ import ( "github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/table" - "github.com/skpr/compass/cli/app/events" + "github.com/skpr/compass/tracing/cli/app/events" ) // NewModel for executing this application. diff --git a/cli/app/search.go b/tracing/cli/app/search.go similarity index 83% rename from cli/app/search.go rename to tracing/cli/app/search.go index 8c88711f..7ba45338 100644 --- a/cli/app/search.go +++ b/tracing/cli/app/search.go @@ -4,8 +4,8 @@ import ( "github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" - "github.com/skpr/compass/cli/app/component/table" + "github.com/skpr/compass/tracing/cli/app/color" + "github.com/skpr/compass/tracing/cli/app/component/table" ) func (m *Model) searchInit() { diff --git a/cli/app/spans.go b/tracing/cli/app/spans.go similarity index 90% rename from cli/app/spans.go rename to tracing/cli/app/spans.go index a22abeac..4c11fc4b 100644 --- a/cli/app/spans.go +++ b/tracing/cli/app/spans.go @@ -6,9 +6,9 @@ import ( "github.com/charmbracelet/bubbles/table" "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" - "github.com/skpr/compass/cli/app/component/span" - "github.com/skpr/compass/trace/segmented" + "github.com/skpr/compass/tracing/cli/app/color" + "github.com/skpr/compass/tracing/cli/app/component/span" + "github.com/skpr/compass/tracing/trace/segmented" ) // SpanLength is how long a span component should be. diff --git a/cli/app/time/time.go b/tracing/cli/app/time/time.go similarity index 100% rename from cli/app/time/time.go rename to tracing/cli/app/time/time.go diff --git a/cli/app/totals.go b/tracing/cli/app/totals.go similarity index 93% rename from cli/app/totals.go rename to tracing/cli/app/totals.go index 73c6b723..77b171d9 100644 --- a/cli/app/totals.go +++ b/tracing/cli/app/totals.go @@ -6,8 +6,8 @@ import ( "github.com/charmbracelet/bubbles/table" "github.com/charmbracelet/lipgloss" - "github.com/skpr/compass/cli/app/color" - "github.com/skpr/compass/trace/count" + "github.com/skpr/compass/tracing/cli/app/color" + "github.com/skpr/compass/tracing/trace/count" ) func (m *Model) totalsInit() { diff --git a/cli/app/tracer/extension/extension.go b/tracing/cli/app/tracer/extension/extension.go similarity index 80% rename from cli/app/tracer/extension/extension.go rename to tracing/cli/app/tracer/extension/extension.go index 62ab0073..8f247990 100644 --- a/cli/app/tracer/extension/extension.go +++ b/tracing/cli/app/tracer/extension/extension.go @@ -6,10 +6,10 @@ import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" - applogger "github.com/skpr/compass/cli/app/logger" - "github.com/skpr/compass/collector" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/cli/app/events" + applogger "github.com/skpr/compass/tracing/cli/app/logger" + "github.com/skpr/compass/tracing/collector" + "github.com/skpr/compass/tracing/trace" ) // New for sending traces to the program. diff --git a/cli/app/tracer/http/http.go b/tracing/cli/app/tracer/http/http.go similarity index 88% rename from cli/app/tracer/http/http.go rename to tracing/cli/app/tracer/http/http.go index 823f6d44..ea7d0203 100644 --- a/cli/app/tracer/http/http.go +++ b/tracing/cli/app/tracer/http/http.go @@ -10,9 +10,9 @@ import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" - applogger "github.com/skpr/compass/cli/app/logger" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/cli/app/events" + applogger "github.com/skpr/compass/tracing/cli/app/logger" + "github.com/skpr/compass/tracing/trace" ) // Start tracing from a http URI endpoint and send traces to the program. diff --git a/cli/app/tracer/tracer.go b/tracing/cli/app/tracer/tracer.go similarity index 84% rename from cli/app/tracer/tracer.go rename to tracing/cli/app/tracer/tracer.go index 982a83e5..08c59f41 100644 --- a/cli/app/tracer/tracer.go +++ b/tracing/cli/app/tracer/tracer.go @@ -7,9 +7,9 @@ import ( tea "github.com/charmbracelet/bubbletea" - applogger "github.com/skpr/compass/cli/app/logger" - "github.com/skpr/compass/cli/app/tracer/extension" - "github.com/skpr/compass/cli/app/tracer/http" + applogger "github.com/skpr/compass/tracing/cli/app/logger" + "github.com/skpr/compass/tracing/cli/app/tracer/extension" + "github.com/skpr/compass/tracing/cli/app/tracer/http" ) // Protocol for connecting to Compass for traces. diff --git a/cli/app/update.go b/tracing/cli/app/update.go similarity index 95% rename from cli/app/update.go rename to tracing/cli/app/update.go index 26db1e18..bc40dd5e 100644 --- a/cli/app/update.go +++ b/tracing/cli/app/update.go @@ -3,7 +3,7 @@ package app import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" + "github.com/skpr/compass/tracing/cli/app/events" ) // Update triggers on messages and updates the model. diff --git a/cli/app/update_key_enter.go b/tracing/cli/app/update_key_enter.go similarity index 88% rename from cli/app/update_key_enter.go rename to tracing/cli/app/update_key_enter.go index 9e4e0fe0..c48787d0 100644 --- a/cli/app/update_key_enter.go +++ b/tracing/cli/app/update_key_enter.go @@ -3,7 +3,7 @@ package app import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" + "github.com/skpr/compass/tracing/cli/app/events" ) func (m *Model) updateKeyEnter() (tea.Model, tea.Cmd) { diff --git a/cli/app/update_key_left.go b/tracing/cli/app/update_key_left.go similarity index 100% rename from cli/app/update_key_left.go rename to tracing/cli/app/update_key_left.go diff --git a/cli/app/update_key_right.go b/tracing/cli/app/update_key_right.go similarity index 100% rename from cli/app/update_key_right.go rename to tracing/cli/app/update_key_right.go diff --git a/cli/app/update_log.go b/tracing/cli/app/update_log.go similarity index 77% rename from cli/app/update_log.go rename to tracing/cli/app/update_log.go index 827cca2e..29cbeda9 100644 --- a/cli/app/update_log.go +++ b/tracing/cli/app/update_log.go @@ -3,7 +3,7 @@ package app import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" + "github.com/skpr/compass/tracing/cli/app/events" ) func (m *Model) updateLog(log events.Log) (tea.Model, tea.Cmd) { diff --git a/cli/app/update_trace.go b/tracing/cli/app/update_trace.go similarity index 83% rename from cli/app/update_trace.go rename to tracing/cli/app/update_trace.go index 910c29ef..bbda1eda 100644 --- a/cli/app/update_trace.go +++ b/tracing/cli/app/update_trace.go @@ -3,7 +3,7 @@ package app import ( tea "github.com/charmbracelet/bubbletea" - "github.com/skpr/compass/cli/app/events" + "github.com/skpr/compass/tracing/cli/app/events" ) func (m *Model) updateTrace(trace events.Trace) (tea.Model, tea.Cmd) { diff --git a/cli/app/update_window_size.go b/tracing/cli/app/update_window_size.go similarity index 100% rename from cli/app/update_window_size.go rename to tracing/cli/app/update_window_size.go diff --git a/cli/app/view.go b/tracing/cli/app/view.go similarity index 100% rename from cli/app/view.go rename to tracing/cli/app/view.go diff --git a/cli/main.go b/tracing/cli/main.go similarity index 92% rename from cli/main.go rename to tracing/cli/main.go index 6d4b4fd0..7048881a 100644 --- a/cli/main.go +++ b/tracing/cli/main.go @@ -13,10 +13,10 @@ import ( "github.com/spf13/cobra" "golang.org/x/sync/errgroup" - "github.com/skpr/compass/cli/app" - "github.com/skpr/compass/cli/app/color" - applogger "github.com/skpr/compass/cli/app/logger" - "github.com/skpr/compass/cli/app/tracer" + "github.com/skpr/compass/tracing/cli/app" + "github.com/skpr/compass/tracing/cli/app/color" + applogger "github.com/skpr/compass/tracing/cli/app/logger" + "github.com/skpr/compass/tracing/cli/app/tracer" ) const cmdExample = ` diff --git a/collector/.gitignore b/tracing/collector/.gitignore similarity index 100% rename from collector/.gitignore rename to tracing/collector/.gitignore diff --git a/tracing/collector/bpf_bpfeb.go b/tracing/collector/bpf_bpfeb.go new file mode 100644 index 00000000..9816bac0 --- /dev/null +++ b/tracing/collector/bpf_bpfeb.go @@ -0,0 +1,156 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build mips || mips64 || ppc64 || s390x + +package collector + +import ( + "bytes" + _ "embed" + "fmt" + "io" + "structs" + + "github.com/cilium/ebpf" +) + +type bpfEvent struct { + _ structs.HostLayout + Type uint8 + RequestId [101]uint8 + Method [101]uint8 + FunctionName [101]uint8 + Uri [2000]uint8 + Timestamp uint64 + Elapsed uint64 +} + +// loadBpf returns the embedded CollectionSpec for bpf. +func loadBpf() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_BpfBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load bpf: %w", err) + } + + return spec, err +} + +// loadBpfObjects loads bpf and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *bpfObjects +// *bpfPrograms +// *bpfMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := loadBpf() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// bpfSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfSpecs struct { + bpfProgramSpecs + bpfMapSpecs + bpfVariableSpecs +} + +// bpfProgramSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfProgramSpecs struct { + UprobeCompassCanary *ebpf.ProgramSpec `ebpf:"uprobe_compass_canary"` + UprobeCompassPhpFunction *ebpf.ProgramSpec `ebpf:"uprobe_compass_php_function"` + UprobeCompassRequestInit *ebpf.ProgramSpec `ebpf:"uprobe_compass_request_init"` + UprobeCompassRequestShutdown *ebpf.ProgramSpec `ebpf:"uprobe_compass_request_shutdown"` +} + +// bpfMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfMapSpecs struct { + Events *ebpf.MapSpec `ebpf:"events"` +} + +// bpfVariableSpecs contains global variables before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfVariableSpecs struct { + UnusedEvent *ebpf.VariableSpec `ebpf:"unused_event"` +} + +// bpfObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfObjects struct { + bpfPrograms + bpfMaps + bpfVariables +} + +func (o *bpfObjects) Close() error { + return _BpfClose( + &o.bpfPrograms, + &o.bpfMaps, + ) +} + +// bpfMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfMaps struct { + Events *ebpf.Map `ebpf:"events"` +} + +func (m *bpfMaps) Close() error { + return _BpfClose( + m.Events, + ) +} + +// bpfVariables contains all global variables after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfVariables struct { + UnusedEvent *ebpf.Variable `ebpf:"unused_event"` +} + +// bpfPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfPrograms struct { + UprobeCompassCanary *ebpf.Program `ebpf:"uprobe_compass_canary"` + UprobeCompassPhpFunction *ebpf.Program `ebpf:"uprobe_compass_php_function"` + UprobeCompassRequestInit *ebpf.Program `ebpf:"uprobe_compass_request_init"` + UprobeCompassRequestShutdown *ebpf.Program `ebpf:"uprobe_compass_request_shutdown"` +} + +func (p *bpfPrograms) Close() error { + return _BpfClose( + p.UprobeCompassCanary, + p.UprobeCompassPhpFunction, + p.UprobeCompassRequestInit, + p.UprobeCompassRequestShutdown, + ) +} + +func _BpfClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed bpf_bpfeb.o +var _BpfBytes []byte diff --git a/tracing/collector/bpf_bpfeb.o b/tracing/collector/bpf_bpfeb.o new file mode 100644 index 00000000..0054c56c Binary files /dev/null and b/tracing/collector/bpf_bpfeb.o differ diff --git a/tracing/collector/bpf_bpfel.go b/tracing/collector/bpf_bpfel.go new file mode 100644 index 00000000..2d25ef7f --- /dev/null +++ b/tracing/collector/bpf_bpfel.go @@ -0,0 +1,156 @@ +// Code generated by bpf2go; DO NOT EDIT. +//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64 || wasm + +package collector + +import ( + "bytes" + _ "embed" + "fmt" + "io" + "structs" + + "github.com/cilium/ebpf" +) + +type bpfEvent struct { + _ structs.HostLayout + Type uint8 + RequestId [101]uint8 + Method [101]uint8 + FunctionName [101]uint8 + Uri [2000]uint8 + Timestamp uint64 + Elapsed uint64 +} + +// loadBpf returns the embedded CollectionSpec for bpf. +func loadBpf() (*ebpf.CollectionSpec, error) { + reader := bytes.NewReader(_BpfBytes) + spec, err := ebpf.LoadCollectionSpecFromReader(reader) + if err != nil { + return nil, fmt.Errorf("can't load bpf: %w", err) + } + + return spec, err +} + +// loadBpfObjects loads bpf and converts it into a struct. +// +// The following types are suitable as obj argument: +// +// *bpfObjects +// *bpfPrograms +// *bpfMaps +// +// See ebpf.CollectionSpec.LoadAndAssign documentation for details. +func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { + spec, err := loadBpf() + if err != nil { + return err + } + + return spec.LoadAndAssign(obj, opts) +} + +// bpfSpecs contains maps and programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfSpecs struct { + bpfProgramSpecs + bpfMapSpecs + bpfVariableSpecs +} + +// bpfProgramSpecs contains programs before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfProgramSpecs struct { + UprobeCompassCanary *ebpf.ProgramSpec `ebpf:"uprobe_compass_canary"` + UprobeCompassPhpFunction *ebpf.ProgramSpec `ebpf:"uprobe_compass_php_function"` + UprobeCompassRequestInit *ebpf.ProgramSpec `ebpf:"uprobe_compass_request_init"` + UprobeCompassRequestShutdown *ebpf.ProgramSpec `ebpf:"uprobe_compass_request_shutdown"` +} + +// bpfMapSpecs contains maps before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfMapSpecs struct { + Events *ebpf.MapSpec `ebpf:"events"` +} + +// bpfVariableSpecs contains global variables before they are loaded into the kernel. +// +// It can be passed ebpf.CollectionSpec.Assign. +type bpfVariableSpecs struct { + UnusedEvent *ebpf.VariableSpec `ebpf:"unused_event"` +} + +// bpfObjects contains all objects after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfObjects struct { + bpfPrograms + bpfMaps + bpfVariables +} + +func (o *bpfObjects) Close() error { + return _BpfClose( + &o.bpfPrograms, + &o.bpfMaps, + ) +} + +// bpfMaps contains all maps after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfMaps struct { + Events *ebpf.Map `ebpf:"events"` +} + +func (m *bpfMaps) Close() error { + return _BpfClose( + m.Events, + ) +} + +// bpfVariables contains all global variables after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfVariables struct { + UnusedEvent *ebpf.Variable `ebpf:"unused_event"` +} + +// bpfPrograms contains all programs after they have been loaded into the kernel. +// +// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. +type bpfPrograms struct { + UprobeCompassCanary *ebpf.Program `ebpf:"uprobe_compass_canary"` + UprobeCompassPhpFunction *ebpf.Program `ebpf:"uprobe_compass_php_function"` + UprobeCompassRequestInit *ebpf.Program `ebpf:"uprobe_compass_request_init"` + UprobeCompassRequestShutdown *ebpf.Program `ebpf:"uprobe_compass_request_shutdown"` +} + +func (p *bpfPrograms) Close() error { + return _BpfClose( + p.UprobeCompassCanary, + p.UprobeCompassPhpFunction, + p.UprobeCompassRequestInit, + p.UprobeCompassRequestShutdown, + ) +} + +func _BpfClose(closers ...io.Closer) error { + for _, closer := range closers { + if err := closer.Close(); err != nil { + return err + } + } + return nil +} + +// Do not access this directly. +// +//go:embed bpf_bpfel.o +var _BpfBytes []byte diff --git a/tracing/collector/bpf_bpfel.o b/tracing/collector/bpf_bpfel.o new file mode 100644 index 00000000..be9e89f0 Binary files /dev/null and b/tracing/collector/bpf_bpfel.o differ diff --git a/collector/collector.go b/tracing/collector/collector.go similarity index 97% rename from collector/collector.go rename to tracing/collector/collector.go index 93f554cd..df075097 100644 --- a/collector/collector.go +++ b/tracing/collector/collector.go @@ -15,8 +15,8 @@ import ( "github.com/cilium/ebpf/rlimit" "golang.org/x/sync/errgroup" - "github.com/skpr/compass/collector/sink" - "github.com/skpr/compass/collector/usdt" + "github.com/skpr/compass/tracing/collector/sink" + "github.com/skpr/compass/tracing/collector/usdt" ) const ( diff --git a/collector/extension/discovery/discovery.go b/tracing/collector/extension/discovery/discovery.go similarity index 100% rename from collector/extension/discovery/discovery.go rename to tracing/collector/extension/discovery/discovery.go diff --git a/collector/includes/.gitignore b/tracing/collector/includes/.gitignore similarity index 100% rename from collector/includes/.gitignore rename to tracing/collector/includes/.gitignore diff --git a/collector/logger.go b/tracing/collector/logger.go similarity index 100% rename from collector/logger.go rename to tracing/collector/logger.go diff --git a/collector/manager.go b/tracing/collector/manager.go similarity index 97% rename from collector/manager.go rename to tracing/collector/manager.go index 2e1bc024..b1ccc21a 100644 --- a/collector/manager.go +++ b/tracing/collector/manager.go @@ -8,8 +8,8 @@ import ( "github.com/patrickmn/go-cache" "golang.org/x/sys/unix" - "github.com/skpr/compass/collector/sink" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/collector/sink" + "github.com/skpr/compass/tracing/trace" ) const ( diff --git a/collector/manager_test.go b/tracing/collector/manager_test.go similarity index 98% rename from collector/manager_test.go rename to tracing/collector/manager_test.go index 7bc8a565..4d37ba9e 100644 --- a/collector/manager_test.go +++ b/tracing/collector/manager_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/trace" ) // TestSync for storing complete profile data for our tests. diff --git a/tracing/collector/program/aarch64.bpf.c b/tracing/collector/program/aarch64.bpf.c new file mode 120000 index 00000000..52295e53 --- /dev/null +++ b/tracing/collector/program/aarch64.bpf.c @@ -0,0 +1 @@ +arm64.bpf.c \ No newline at end of file diff --git a/collector/template.bpf.c b/tracing/collector/program/amd64.bpf.c similarity index 87% rename from collector/template.bpf.c rename to tracing/collector/program/amd64.bpf.c index 51e45dce..3862da52 100644 --- a/collector/template.bpf.c +++ b/tracing/collector/program/amd64.bpf.c @@ -45,9 +45,9 @@ int uprobe_compass_request_init(struct pt_regs *ctx) { return 0; event->type = EVENT_TYPE_REQUEST_INIT; - bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->REQUEST_INIT_ARG_REQUEST_ID); - bpf_core_read_user_str(&event->method, STRSZ, (void *)ctx->REQUEST_INIT_ARG_METHOD); - bpf_core_read_user_str(&event->uri, URI_MAX_LEN, (void *)ctx->REQUEST_INIT_ARG_URI); + bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->cx); + bpf_core_read_user_str(&event->method, STRSZ, (void *)ctx->r15); + bpf_core_read_user_str(&event->uri, URI_MAX_LEN, (void *)ctx->ax); event->timestamp = bpf_ktime_get_ns(); event->elapsed = 0; @@ -62,10 +62,10 @@ int uprobe_compass_php_function(struct pt_regs *ctx) { return 0; event->type = EVENT_TYPE_FUNCTION; - bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->PHP_FUNCTION_ARG_REQUEST_ID); - bpf_core_read_user_str(&event->function_name, STRSZ, (void *)ctx->PHP_FUNCTION_ARG_FUNCTION_NAME); + bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->r14); + bpf_core_read_user_str(&event->function_name, STRSZ, (void *)ctx->ax); event->timestamp = bpf_ktime_get_ns(); - event->elapsed = ctx->PHP_FUNCTION_ARG_ELAPSED; + event->elapsed = ctx->r15; bpf_ringbuf_submit(event, 0); return 0; @@ -78,7 +78,7 @@ int uprobe_compass_request_shutdown(struct pt_regs *ctx) { return 0; event->type = EVENT_TYPE_REQUEST_SHUTDOWN; - bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->REQUEST_SHUTDOWN_ARG_REQUEST_ID); + bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->ax); event->timestamp = bpf_ktime_get_ns(); event->elapsed = 0; diff --git a/tracing/collector/program/arm64.bpf.c b/tracing/collector/program/arm64.bpf.c new file mode 100644 index 00000000..c9fcf968 --- /dev/null +++ b/tracing/collector/program/arm64.bpf.c @@ -0,0 +1,87 @@ +//go:build ignore + +#define STRSZ 100 + 1 +#define URI_MAX_LEN 2000 + +#include "vmlinux.h" +#include +#include +#include + +char __license[] SEC("license") = "Dual MIT/GPL"; + +enum event_type : __u8 { + EVENT_TYPE_FUNCTION = 0, + EVENT_TYPE_REQUEST_INIT = 1, + EVENT_TYPE_REQUEST_SHUTDOWN = 2, +}; + +struct event { + __u8 type; + __u8 request_id[STRSZ]; + __u8 method[STRSZ]; + __u8 function_name[STRSZ]; + __u8 uri[URI_MAX_LEN]; + __u64 timestamp; + __u64 elapsed; +}; + +const struct event *unused_event __attribute__((unused)); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 4096); +} events SEC(".maps"); + +SEC("uprobe/compass_canary") +int uprobe_compass_canary(struct pt_regs *ctx) { + return 0; +} + +SEC("uprobe/compass_request_init") +int uprobe_compass_request_init(struct pt_regs *ctx) { + struct event *event = bpf_ringbuf_reserve(&events, sizeof(*event), 0); + if (!event) + return 0; + + event->type = EVENT_TYPE_REQUEST_INIT; + bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->regs[8]); + bpf_core_read_user_str(&event->method, STRSZ, (void *)ctx->regs[21]); + bpf_core_read_user_str(&event->uri, URI_MAX_LEN, (void *)ctx->regs[0]); + event->timestamp = bpf_ktime_get_ns(); + event->elapsed = 0; + + bpf_ringbuf_submit(event, 0); + return 0; +} + +SEC("uprobe/compass_php_function") +int uprobe_compass_php_function(struct pt_regs *ctx) { + struct event *event = bpf_ringbuf_reserve(&events, sizeof(*event), 0); + if (!event) + return 0; + + event->type = EVENT_TYPE_FUNCTION; + bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->regs[20]); + bpf_core_read_user_str(&event->function_name, STRSZ, (void *)ctx->regs[0]); + event->timestamp = bpf_ktime_get_ns(); + event->elapsed = ctx->regs[21]; + + bpf_ringbuf_submit(event, 0); + return 0; +} + +SEC("uprobe/compass_request_shutdown") +int uprobe_compass_request_shutdown(struct pt_regs *ctx) { + struct event *event = bpf_ringbuf_reserve(&events, sizeof(*event), 0); + if (!event) + return 0; + + event->type = EVENT_TYPE_REQUEST_SHUTDOWN; + bpf_core_read_user_str(&event->request_id, STRSZ, (void *)ctx->regs[8]); + event->timestamp = bpf_ktime_get_ns(); + event->elapsed = 0; + + bpf_ringbuf_submit(event, 0); + return 0; +} diff --git a/tracing/collector/program/x86_64.bpf.c b/tracing/collector/program/x86_64.bpf.c new file mode 120000 index 00000000..59155434 --- /dev/null +++ b/tracing/collector/program/x86_64.bpf.c @@ -0,0 +1 @@ +amd64.bpf.c \ No newline at end of file diff --git a/collector/sink/sink.go b/tracing/collector/sink/sink.go similarity index 88% rename from collector/sink/sink.go rename to tracing/collector/sink/sink.go index 6bfbad5b..cc431d07 100644 --- a/collector/sink/sink.go +++ b/tracing/collector/sink/sink.go @@ -4,7 +4,7 @@ package sink import ( "context" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/trace" ) // Interface for handling profile data. diff --git a/collector/usdt/usdt.go b/tracing/collector/usdt/usdt.go similarity index 100% rename from collector/usdt/usdt.go rename to tracing/collector/usdt/usdt.go diff --git a/collector/usdt/util.go b/tracing/collector/usdt/util.go similarity index 100% rename from collector/usdt/util.go rename to tracing/collector/usdt/util.go diff --git a/go.mod b/tracing/go.mod similarity index 82% rename from go.mod rename to tracing/go.mod index aa2067cc..a96d8e2c 100644 --- a/go.mod +++ b/tracing/go.mod @@ -1,6 +1,6 @@ -module github.com/skpr/compass +module github.com/skpr/compass/tracing -go 1.24.0 +go 1.25.1 require ( github.com/cenkalti/backoff/v4 v4.3.0 @@ -26,16 +26,16 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charmbracelet/colorprofile v0.3.1 // indirect + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/x/ansi v0.10.1 // indirect - github.com/charmbracelet/x/cellbuf v0.0.13 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/term v0.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/joho/godotenv v1.5.1 // indirect - github.com/jwalton/go-supportscolor v1.2.0 // indirect + github.com/jwalton/go-supportscolor v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect @@ -51,12 +51,12 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/sahilm/fuzzy v0.1.1 // indirect github.com/spf13/pflag v1.0.9 // indirect - github.com/tklauser/go-sysconf v0.3.15 // indirect - github.com/tklauser/numcpus v0.10.0 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/term v0.33.0 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.28.0 // indirect google.golang.org/protobuf v1.36.8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/tracing/go.sum similarity index 91% rename from go.sum rename to tracing/go.sum index 026f3452..19b404ed 100644 --- a/go.sum +++ b/tracing/go.sum @@ -16,14 +16,14 @@ github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= -github.com/charmbracelet/colorprofile v0.3.1 h1:k8dTHMd7fgw4bnFd7jXTLZrSU/CQrKnL3m+AxCzDz40= -github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= -github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= -github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= +github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= @@ -37,9 +37,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s= github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -56,9 +55,8 @@ github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCX github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= github.com/jwalton/gchalk v1.3.0 h1:uTfAaNexN8r0I9bioRTksuT8VGjrPs9YIXR1PQbtX/Q= github.com/jwalton/gchalk v1.3.0/go.mod h1:ytRlj60R9f7r53IAElbpq4lVuPOPNg2J4tJcCxtFqr8= +github.com/jwalton/go-supportscolor v1.1.0 h1:HsXFJdMPjRUAx8cIW6g30hVSFYaxh9yRQwEWgkAR7lQ= github.com/jwalton/go-supportscolor v1.1.0/go.mod h1:hFVUAZV2cWg+WFFC4v8pT2X/S2qUUBYMioBD9AINXGs= -github.com/jwalton/go-supportscolor v1.2.0 h1:g6Ha4u7Vm3LIsQ5wmeBpS4gazu0UP1DRDE8y6bre4H8= -github.com/jwalton/go-supportscolor v1.2.0/go.mod h1:hFVUAZV2cWg+WFFC4v8pT2X/S2qUUBYMioBD9AINXGs= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -115,10 +113,10 @@ github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= -github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= -github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= -github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -139,14 +137,12 @@ golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= diff --git a/tracing/mise.toml b/tracing/mise.toml new file mode 100644 index 00000000..f61202b5 --- /dev/null +++ b/tracing/mise.toml @@ -0,0 +1,48 @@ +[tools] +go = "1.24" +"go:github.com/cilium/ebpf/cmd/bpf2go" = { version = "v0.19.0" } +"ubi:golangci/golangci-lint" = "2.6.2" + +[env] +CGO_ENABLED = 0 + +[tasks.s] +run = "env" + +[tasks.vendor] +description = "Vendor resets the main module's vendor directory to include all packages needed to build the application" +run = "go mod vendor" + +[tasks.lint] +description = "Run linting on all tracer components" +run = "golangci-lint run" +depends = ["generate", "vendor"] + +[tasks.test] +description = "Run tests for all tracer components" +run = "go test ./cli/... ./collector/... ./trace/... ./sidecar/..." +depends = ["generate"] + +[tasks.generate] +description = "Generate BPF artifacts" +run = ''' +#!/usr/bin/env bash +cd collector +bpftool btf dump file /sys/kernel/btf/vmlinux format c > ./includes/vmlinux.h +GOPACKAGE=collector bpf2go -cflags '-O2 -g -Wall -Werror' -type event bpf program/$(uname -m).bpf.c -- -I./includes +''' +depends = ["vendor"] + +[tasks.build] +description = "Build all Compass tracing binaries" +depends = ["build:cli", "build:sidecar"] + +[tasks."build:cli"] +description = "Build Compass CLI" +run = "go build -a -o _output/compass github.com/skpr/compass/tracing/cli" +depends = ["generate"] + +[tasks."build:sidecar"] +description = "Build Compass tracing binaries" +run = "go build -a -o _output/compass-sidecar github.com/skpr/compass/tracing/sidecar" +depends = ["generate"] diff --git a/Dockerfile b/tracing/sidecar/Dockerfile similarity index 58% rename from Dockerfile rename to tracing/sidecar/Dockerfile index 8d20f91c..7e27637b 100644 --- a/Dockerfile +++ b/tracing/sidecar/Dockerfile @@ -1,19 +1,17 @@ -ARG PHP_VERSION=8.3 -FROM ghcr.io/skpr/php-cli:${PHP_VERSION}-v2-stable AS build - -ARG PHP_VERSION=8.3 +FROM alpine:3.21 AS build USER root RUN apk add alpine-sdk \ + bash \ bpftool \ clang \ clang-dev \ + curl \ git \ libbpf-dev \ linux-headers \ - llvm \ - php${PHP_VERSION}-dev + llvm ENV MISE_DATA_DIR="/mise" ENV MISE_CONFIG_DIR="/mise" @@ -28,28 +26,17 @@ ENV LIBCLANG_PATH=/usr/lib/llvm19/lib ENV GOFLAGS=-buildvcs=false -ENV RUSTFLAGS="-C target-feature=-crt-static" - -ENV RUST_BACKTRACE=full - +WORKDIR /data ADD --chown=skpr:skpr . /data # Check and build. RUN mise trust . RUN mise run lint RUN mise run test -RUN mise run build +RUN mise run build:sidecar FROM scratch -# Extension -COPY extension/compass.ini /etc/php/conf.d/00_compass.ini -COPY --from=build /data/extension/target/release/libcompass_extension.so /usr/lib/php/modules/compass.so - -# Collector -COPY --from=build /data/_output/compass /usr/local/bin/compass COPY --from=build /data/_output/compass-sidecar /usr/local/bin/compass-sidecar - -ENV COLORTERM=truecolor ENV COMPASS_SIDECAR_PROCESS_NAME=php-fpm CMD ["compass-sidecar"] diff --git a/sidecar/broadcaster/broadcaster.go b/tracing/sidecar/broadcaster/broadcaster.go similarity index 98% rename from sidecar/broadcaster/broadcaster.go rename to tracing/sidecar/broadcaster/broadcaster.go index e7f8286d..74047974 100644 --- a/sidecar/broadcaster/broadcaster.go +++ b/tracing/sidecar/broadcaster/broadcaster.go @@ -4,7 +4,7 @@ import ( "context" "sync" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/trace" ) type Broadcaster struct { diff --git a/sidecar/main.go b/tracing/sidecar/main.go similarity index 97% rename from sidecar/main.go rename to tracing/sidecar/main.go index 2fe87b26..ffefcc11 100644 --- a/sidecar/main.go +++ b/tracing/sidecar/main.go @@ -18,9 +18,9 @@ import ( "github.com/spf13/cobra" "golang.org/x/sync/errgroup" - "github.com/skpr/compass/collector" - "github.com/skpr/compass/collector/extension/discovery" - "github.com/skpr/compass/sidecar/broadcaster" + "github.com/skpr/compass/tracing/collector" + "github.com/skpr/compass/tracing/collector/extension/discovery" + "github.com/skpr/compass/tracing/sidecar/broadcaster" ) var cmdExample = ` diff --git a/trace/count/trace.go b/tracing/trace/count/trace.go similarity index 94% rename from trace/count/trace.go rename to tracing/trace/count/trace.go index b9415a65..af958d7d 100644 --- a/trace/count/trace.go +++ b/tracing/trace/count/trace.go @@ -4,8 +4,8 @@ package count import ( "sort" - "github.com/skpr/compass/trace" - "github.com/skpr/compass/trace/segmented" + "github.com/skpr/compass/tracing/trace" + "github.com/skpr/compass/tracing/trace/segmented" ) // Unmarshal a full trace into a counted trace. diff --git a/trace/count/types.go b/tracing/trace/count/types.go similarity index 94% rename from trace/count/types.go rename to tracing/trace/count/types.go index 76f8a9b2..c36239ad 100644 --- a/trace/count/types.go +++ b/tracing/trace/count/types.go @@ -1,7 +1,7 @@ package count import ( - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/trace" ) // Trace data collected for a request. diff --git a/trace/segmented/trace.go b/tracing/trace/segmented/trace.go similarity index 97% rename from trace/segmented/trace.go rename to tracing/trace/segmented/trace.go index 12fbf594..da1d5ef7 100644 --- a/trace/segmented/trace.go +++ b/tracing/trace/segmented/trace.go @@ -5,7 +5,7 @@ import ( "fmt" "sort" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/trace" ) // Unmarshal a full trace into a segmented trace. diff --git a/trace/segmented/types.go b/tracing/trace/segmented/types.go similarity index 96% rename from trace/segmented/types.go rename to tracing/trace/segmented/types.go index 5df731f4..6bc14280 100644 --- a/trace/segmented/types.go +++ b/tracing/trace/segmented/types.go @@ -3,7 +3,7 @@ package segmented import ( "fmt" - "github.com/skpr/compass/trace" + "github.com/skpr/compass/tracing/trace" ) // Trace data collected for a request. diff --git a/trace/trace.go b/tracing/trace/trace.go similarity index 100% rename from trace/trace.go rename to tracing/trace/trace.go