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
5 changes: 5 additions & 0 deletions .github/workflows/demo-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ on:
- '.github/workflows/demo-e2e.yml'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
demo-e2e:
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'no_run')
name: Demo E2E (Docker + Selenium)
runs-on: ubuntu-latest
timeout-minutes: 20
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/plugin-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ on:
- 'jetbrains-plugin/**'
- '.github/workflows/plugin-build.yml'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'no_run')
name: Build & Test Plugin
runs-on: ubuntu-latest

Expand Down
37 changes: 35 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,45 @@ jobs:
name: php_mariadb_profiler-php${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }}
path: dist\*.dll

# ---------------------------------------------------------------------------
# JetBrains Plugin build
# ---------------------------------------------------------------------------
build-plugin:
name: JetBrains Plugin
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Run tests
working-directory: jetbrains-plugin
run: ./gradlew test

- name: Build plugin
working-directory: jetbrains-plugin
run: ./gradlew buildPlugin

- uses: actions/upload-artifact@v4
with:
name: mariadb-profiler-viewer-plugin
path: jetbrains-plugin/build/distributions/*.zip
if-no-files-found: error

# ---------------------------------------------------------------------------
# Create GitHub Release
# ---------------------------------------------------------------------------
release:
name: Create Release
needs: [build-linux, build-windows]
needs: [build-linux, build-windows, build-plugin]
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -181,7 +214,7 @@ jobs:
- name: Collect release assets
run: |
mkdir -p release
find artifacts -type f \( -name "*.so" -o -name "*.dll" \) -exec cp {} release/ \;
find artifacts -type f \( -name "*.so" -o -name "*.dll" -o -name "*.zip" \) -exec cp {} release/ \;
echo "=== Release assets ==="
ls -lh release/

Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ on:
pull_request:
branches: ['**']

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test-cli:
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'no_run')
name: CLI Tests (PHP ${{ matrix.php-version }})
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -42,6 +47,7 @@ jobs:
run: php tests/test_integration.php

build-extension:
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'no_run')
name: Build Extension (PHP ${{ matrix.php-version }})
runs-on: ubuntu-latest
strategy:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/windows-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ on:
- 'ext/**'
- '.github/workflows/windows-build.yml'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-windows:
if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'no_run')
name: Windows - PHP ${{ matrix.php }} ${{ matrix.ts }} ${{ matrix.arch }}
runs-on: windows-${{ matrix.os }}
defaults:
Expand Down
147 changes: 147 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# MariaDB Profiler for PHP

A MariaDB/MySQL query profiler that runs as a PHP extension. It hooks into PHP's `mysqlnd` driver to intercept, record, and analyze all executed SQL queries.

Works with any database access method that uses mysqlnd, including PDO, mysqli, and Laravel Eloquent.

## IntelliJ Plugin Ready
<img width="4012" height="2800" alt="ss0" src="https://github.com/user-attachments/assets/a38dbc5f-69ee-4f48-9aa1-e3fb0eb07de8" /><BR>
<img width="3996" height="2436" alt="ss1" src="https://github.com/user-attachments/assets/460b75a9-996e-4c20-8e6f-818b4550f5d6" /><BR>
<img width="3996" height="2436" alt="ss2" src="https://github.com/user-attachments/assets/78388037-728d-477b-bfba-1c3f75e0e1b0" />



## Components

| Component | Description |
|---|---|
| `ext/mariadb_profiler/` | PHP extension (C) |
| `cli/` | CLI profiler management tool (PHP) |
| `demo/` | Docker-based web demo (Laravel + WebSocket) |
| `jetbrains-plugin/` | JetBrains IDE plugin (Kotlin) |

## Features

- **Query interception** — Captures all SQL queries at the mysqlnd level
- **Context tags** — Stack-based tags to group queries by business logic
- **PHP backtrace** — Records call stacks at configurable depth
- **Prepared statement support** — Logs bound parameters (PHP 7.0+)
- **SQL analysis** — Automatic extraction of table and column names
- **Job management** — Concurrent profiling sessions with parent-child relationships
- **Cross-platform** — Linux / macOS / Windows

## Requirements

| Component | Requirements |
|---|---|
| Extension | PHP 5.3 – 8.4+, mysqlnd |
| CLI tool | PHP 5.3+, Composer |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

CLIツールのPHPバージョン要件がCIと矛盾しています。

READMEでは「PHP 5.3+」と記載されていますが、tests.ymltest-cli ジョブでは PHP 7.4 以降のみテストされており、コメントにも greenlion/php-sql-parser が nullable type hints (?Type) を使用するため PHP 7.1+ が必要と明記されています。実際の最低要件に合わせて記載を修正してください。

📝 修正案
-| CLI tool | PHP 5.3+, Composer |
+| CLI tool | PHP 7.4+, Composer |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| CLI tool | PHP 5.3+, Composer |
| CLI tool | PHP 7.4+, Composer |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 31, README の CLI ツール欄が「PHP 5.3+」となっていますが実際の最低要件は依存パッケージの
nullable 型ヒントにより PHP 7.1+(CI のテストは PHP 7.4+ で回している)なので、README.md の該当テーブル行(現在
"CLI tool | PHP 5.3+, Composer" とある箇所)を "PHP 7.1+, Composer" に修正し、必要なら tests.yml
の test-cli ジョブコメントに greenlion/php-sql-parser が PHP 7.1+ を要求する旨を明記して整合させてください。

| Demo | Docker, Docker Compose |

## Installation

### Building the Extension

```bash
cd ext/mariadb_profiler
phpize
./configure --enable-mariadb_profiler
make
sudo make install
```

Add the following to php.ini:

```ini
extension=mariadb_profiler.so
mariadb_profiler.enabled=1
mariadb_profiler.log_dir=/var/log/mariadb_profiler
```

### CLI Tool

```bash
composer install
```

## Configuration (php.ini)

```ini
mariadb_profiler.enabled = 1 ; Enable the extension
mariadb_profiler.log_dir = /tmp/mariadb_profiler ; Log output directory
mariadb_profiler.raw_log = 1 ; Write raw text logs
mariadb_profiler.job_check_interval = 1 ; Interval to check jobs.json (seconds)
mariadb_profiler.trace_depth = 0 ; Backtrace depth (0 = disabled)
```

## Usage

### Managing Profiling Jobs

```bash
# Start a job
php cli/mariadb_profiler.php job start [<key>]

# End a job
php cli/mariadb_profiler.php job end <key>

# List jobs
php cli/mariadb_profiler.php job list

# Show parsed queries
php cli/mariadb_profiler.php job show <key> [--tag=<tag>]

# Show raw log
php cli/mariadb_profiler.php job raw <key>

# Export as JSON
php cli/mariadb_profiler.php job export <key>

# Show tag summary
php cli/mariadb_profiler.php job tags <key>

# Show caller summary
php cli/mariadb_profiler.php job callers <key>

# Purge completed jobs
php cli/mariadb_profiler.php job purge
```

### Tagging Queries in PHP

```php
// Push a tag
mariadb_profiler_tag('checkout_flow');

// Queries executed here are tagged with 'checkout_flow'
$db->query('SELECT * FROM orders WHERE user_id = ?');

// Get the current tag
$tag = mariadb_profiler_get_tag(); // 'checkout_flow'

// Pop the tag
mariadb_profiler_untag();
```

### Demo

```bash
cd demo
docker compose up --build
# Open http://localhost:8080
```

## PHP Function Reference

| Function | Description |
|---|---|
| `mariadb_profiler_tag(string $tag): void` | Push a context tag onto the stack |
| `mariadb_profiler_untag(?string $tag = null): ?string` | Pop a tag (optionally unwind to a specific tag) |
| `mariadb_profiler_get_tag(): ?string` | Get the current tag (null if none) |

## Log Formats

Two files are generated per job:

- `{job_key}.raw.log` — One query per line in text format (with timestamp, status, tag, and trace)
- `{job_key}.jsonl` — Parsed JSON format with extracted table and column names