Skip to content

Commit b40d1f4

Browse files
Pre release
1 parent 5d7a069 commit b40d1f4

File tree

7 files changed

+228
-129
lines changed

7 files changed

+228
-129
lines changed

.github/workflows/ci.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
env:
9+
REGISTRY: docker.io
10+
IMAGE_NAME: hiload/phpscope
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: write
17+
packages: write
18+
19+
steps:
20+
- uses: actions/checkout@v3
21+
22+
- name: Set up QEMU
23+
uses: docker/setup-qemu-action@v2
24+
25+
- name: Set up Docker Buildx
26+
uses: docker/setup-buildx-action@v2
27+
28+
- name: Log in to Docker Hub
29+
uses: docker/login-action@v2
30+
with:
31+
username: ${{ secrets.DOCKERHUB_USERNAME }}
32+
password: ${{ secrets.DOCKERHUB_TOKEN }}
33+
34+
- name: Extract metadata
35+
id: meta
36+
uses: docker/metadata-action@v4
37+
with:
38+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
39+
40+
- name: Build and push Docker image
41+
uses: docker/build-push-action@v4
42+
with:
43+
context: .
44+
platforms: linux/amd64,linux/arm64
45+
push: true
46+
tags: ${{ steps.meta.outputs.tags }}
47+
labels: ${{ steps.meta.outputs.labels }}
48+
49+
release:
50+
needs: build
51+
runs-on: ubuntu-latest
52+
permissions:
53+
contents: write
54+
packages: write
55+
56+
steps:
57+
- uses: actions/checkout@v3
58+
59+
- name: Set up Go
60+
uses: actions/setup-go@v4
61+
with:
62+
go-version: '1.23.3'
63+
64+
- name: Build binary
65+
run: |
66+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o build/app-linux-amd64
67+
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o build/app-darwin-amd64
68+
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o build/app-linux-arm64
69+
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o build/app-darwin-arm64
70+
71+
- name: Create Release
72+
uses: softprops/action-gh-release@v1
73+
env:
74+
GITHUB_TOKEN: ${{ github.token }}
75+
with:
76+
files: |
77+
build/app-linux-amd64
78+
build/app-darwin-amd64
79+
build/app-linux-arm64
80+
build/app-darwin-arm64

Dockerfile

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,35 @@
1-
# Етап збірки
21
FROM golang:1.23.3-alpine AS builder
32

4-
# Встановлюємо необхідні інструменти для збірки
53
RUN apk add --no-cache git
64

7-
# Встановлюємо робочу директорію
85
WORKDIR /app
96

10-
# Копіюємо файли go.mod та go.sum
117
COPY go.mod go.sum ./
128

13-
# Завантажуємо залежності
149
RUN go mod download
1510

16-
# Копіюємо весь код
11+
1712
COPY . .
1813

19-
# Збираємо додаток
14+
2015
RUN CGO_ENABLED=0 GOOS=linux go build -o phpscope .
2116

2217
FROM alpine:3.21 AS phpspy
18+
2319
# Install phpspy
2420
RUN apk add --no-cache git make gcc g++ libc-dev && \
2521
git clone https://github.com/adsr/phpspy.git && \
2622
cd phpspy && \
2723
make
2824

29-
# Фінальний етап
3025
FROM alpine:latest
3126

32-
# Встановлюємо часовий пояс
3327
RUN apk add --no-cache binutils
3428

35-
# Копіюємо бінарний файл з етапу збірки
3629
COPY --from=builder /app/phpscope /usr/local/bin/
3730

3831
COPY --from=phpspy /phpspy/phpspy /usr/bin/phpspy
3932

40-
# Встановлюємо точку входу
4133
ENTRYPOINT ["phpscope"]
4234

43-
# Встановлюємо параметри за замовчуванням
44-
# Їх можна перевизначити при запуску контейнера
4535
CMD ["--pyroscope", "http://localhost:4040", "--app", "local"]

README.md

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# PHPScope
2+
23
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine/)
34

4-
PHPScope is a PHP profiling tool that integrates with Pyroscope to provide continuous profiling for PHP applications. It captures PHP-FPM and PHP CLI processes performance data and sends it to a Pyroscope server for visualization and analysis.
5+
PHPScope is a PHP profiling tool based on [phpspy](https://github.com/adsr/phpspy) that integrates with Pyroscope to provide continuous profiling for PHP applications. It captures trought [phpspy](https://github.com/adsr/phpspy) PHP-FPM and PHP CLI processes performance data and sends it to a Pyroscope server for visualization and analysis.
56

67
## Features
78

@@ -26,42 +27,27 @@ You can either run PHPScope using Docker Compose or build it from source.
2627

2728
### Using Docker Compose
2829

29-
1. Clone the repository:
3030
```bash
3131
git clone https://github.com/everythings-gonna-be-alright/phpscope
32-
```
33-
34-
2. Change to the project directory:
35-
```bash
3632
cd phpscope
37-
```
38-
39-
3. Start the application using Docker Compose:
40-
```bash
4133
docker-compose up -d
4234
```
4335

4436
### Building from Source
4537

46-
1. Clone the repository:
4738
```bash
4839
git clone https://github.com/everythings-gonna-be-alright/phpscope
49-
```
50-
51-
2. Change to the project directory:
52-
```bash
5340
cd phpscope
54-
```
55-
56-
3. Build the project:
57-
```bash
5841
go build
5942
```
6043

6144
## Usage
6245

6346
Basic usage example:
64-
./phpscope --pyroscopeUrl="http://pyroscope:4040" --appName="your-app-name"
47+
48+
```bash
49+
./phpscope --pyroscopeUrl="http://pyroscope:4040" --appName="your-app-name"
50+
```
6551

6652
### Command Line Options
6753

@@ -79,18 +65,21 @@ Basic usage example:
7965
| --phpspyBufferSize | 131072 | phpspy buffer size |
8066
| --phpspyMaxDepth | 50000 | phpspy max stack depth |
8167
| --phpspyThreads | 64 | phpspy threads count |
68+
| --debug | false | Enable debug logging |
8269

8370
## Example
8471

8572
Profile a PHP application with custom tags and exclusion pattern:
8673

87-
./phpscope \
88-
--pyroscopeUrl="http://pyroscope:4040" \
89-
--appName="my-php-app" \
90-
--tags="environment=production" \
91-
--tags="version=1.0" \
92-
--exclude="vendor/*" \
93-
--rateHz=100
74+
```bash
75+
./phpscope \
76+
--pyroscopeUrl="http://pyroscope:4040" \
77+
--appName="my-php-app" \
78+
--tags="environment=production" \
79+
--tags="version=1.0" \
80+
--exclude="vendor/*" \
81+
--rateHz=100
82+
```
9483

9584
## Contributing
9685

docker-compose.yaml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,22 @@ services:
22
pyroscope:
33
image: grafana/pyroscope:1.12.0
44
ports:
5-
- 4040:4040
5+
- 4040:4040
6+
command:
7+
- -usage-stats.enabled=false
8+
- -self-profiling.disable-push=true
9+
- -ingester.max-global-series-per-tenant=15000
610
phpscope:
711
image: hiload/phpscope:latest
812
command:
9-
- -pyroscopeUrl
10-
- http://pyroscope:4040
11-
- -appName
12-
- php
13-
- -exclude
14-
- "<main>.*"
13+
- -pyroscopeUrl
14+
- http://pyroscope:4040
15+
- -appName
16+
- php
17+
- -exclude
18+
- "<main>.*"
1519
depends_on:
16-
- pyroscope
20+
- pyroscope
1721
pid: "host"
1822
cap_add:
1923
- SYS_PTRACE

main.go

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"strings"
1010
)
1111

12-
func printWelcomeBanner(pyroscopeURL, appName string, rateHz int, interval float64, batchLimit int, concurrentLimit int, tags map[string]string, excludePattern string) {
12+
func printWelcomeBanner(pyroscopeURL, appName string, rateHz int, interval float64, batchLimit int, concurrentLimit int, tags map[string]string, excludePattern string, debug bool) {
1313

1414
bannerLines := []string{
1515
" ____ __ ______ _____ ",
@@ -22,10 +22,10 @@ func printWelcomeBanner(pyroscopeURL, appName string, rateHz int, interval float
2222

2323
// Print banner in orange color
2424
for _, line := range bannerLines {
25-
fmt.Println(line)
25+
fmt.Println("\033[0;33m" + line + "\033[0m")
2626
}
2727

28-
fmt.Println("https://github.com/everythings-gonna-be-alright\n")
28+
fmt.Print("https://github.com/everythings-gonna-be-alright\n\n")
2929

3030
fmt.Println("🚀 Starting phpScope with configuration:")
3131
fmt.Printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")
@@ -44,25 +44,32 @@ func printWelcomeBanner(pyroscopeURL, appName string, rateHz int, interval float
4444
fmt.Printf(" ├─ %s: %s\n", k, v)
4545
}
4646
}
47+
fmt.Printf("🐛 Debug Mode: %v\n", debug)
4748
fmt.Printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n")
4849
}
4950

5051
func main() {
51-
pyroscopeURL := flag.String("pyroscopeUrl", "", "Url of the pyroscope server")
52-
authToken := flag.String("auth", "", "Pyroscope Auth Token")
53-
appName := flag.String("appName", "", "Name of app")
54-
rateHz := flag.Int("rateHz", 400, "Sample rate in Hz")
55-
// If you change interval, you broke time per sample!
56-
interval := flag.Float64("interval", 0.1, "Maximum time between requests to pyroscope server")
57-
batchLimit := flag.Int("batch", 50000, "Maximum number of traces in request")
58-
concurrentLimit := flag.Int("concurrent", 1, "Concurrent request limit")
52+
// Command line flags configuration
53+
// Core settings
54+
pyroscopeURL := flag.String("pyroscopeUrl", "", "URL of the Pyroscope server")
55+
authToken := flag.String("auth", "", "Authentication token for Pyroscope")
56+
appName := flag.String("appName", "", "Application name for profiling data")
5957
excludeRegex := flag.String("exclude", "", "Regex pattern to exclude functions")
6058
var tags multiFlag
6159
flag.Var(&tags, "tags", "Tags in format key=value")
62-
// Adding new parameters for phpspy
63-
phpspyBufferSize := flag.Int("phpspyBufferSize", 131072, "phpspy buffer size")
64-
phpspyMaxDepth := flag.Int("phpspyMaxDepth", 50000, "phpspy max stack depth")
65-
phpspyThreads := flag.Int("phpspyThreads", 64, "phpspy threads count")
60+
61+
// Profiling settings
62+
rateHz := flag.Int("rateHz", 400, "Sampling rate in Hz")
63+
interval := flag.Float64("interval", 0.1, "Time between data sends (seconds)")
64+
batchLimit := flag.Int("batch", 50000, "Maximum traces per batch")
65+
concurrentLimit := flag.Int("concurrent", 1, "Maximum concurrent requests")
66+
67+
// PHP-specific settings
68+
phpspyBufferSize := flag.Int("phpspyBufferSize", 131072, "Size of phpspy's internal buffer")
69+
phpspyMaxDepth := flag.Int("phpspyMaxDepth", 50000, "Maximum stack trace depth")
70+
phpspyThreads := flag.Int("phpspyThreads", 64, "Number of phpspy worker threads")
71+
72+
debug := flag.Bool("debug", false, "Enable debug logging")
6673

6774
flag.Parse()
6875

@@ -84,7 +91,7 @@ func main() {
8491
}
8592

8693
// Print welcome banner with configuration
87-
printWelcomeBanner(*pyroscopeURL, *appName, *rateHz, *interval, *batchLimit, *concurrentLimit, tagMap, *excludeRegex)
94+
printWelcomeBanner(*pyroscopeURL, *appName, *rateHz, *interval, *batchLimit, *concurrentLimit, tagMap, *excludeRegex, *debug)
8895

8996
// Initialize sender with new configuration
9097
s := sender.New(sender.Config{
@@ -94,7 +101,10 @@ func main() {
94101
RateHz: *rateHz,
95102
})
96103

97-
// Initialize processor with new parameters
104+
// Set global debug flag
105+
processor.Debug = *debug
106+
107+
// Initialize processor without debug in config
98108
p := processor.New(processor.Config{
99109
Interval: *interval,
100110
BatchLimit: *batchLimit,
@@ -114,7 +124,8 @@ func main() {
114124
}
115125
}
116126

117-
// multiFlag implements flag.Value interface for multiple flag values
127+
// multiFlag implements flag.Value interface to support multiple flag values
128+
// for the same flag (e.g., multiple -tags flags)
118129
type multiFlag []string
119130

120131
func (f *multiFlag) String() string {
@@ -126,6 +137,8 @@ func (f *multiFlag) Set(value string) error {
126137
return nil
127138
}
128139

140+
// parseTag splits a "key=value" string into separate key and value.
141+
// Returns empty strings if the format is invalid.
129142
func parseTag(tag string) (string, string) {
130143
parts := strings.Split(tag, "=")
131144
if len(parts) != 2 {

0 commit comments

Comments
 (0)