Skip to content

Commit 903fe5c

Browse files
authored
refactor: phpuint telemetry bridge (#2329)
- allow to configure transport - unify parameter names - add support for env vars - deprecated otel collector specific options
1 parent 8d742ba commit 903fe5c

16 files changed

Lines changed: 1177 additions & 109 deletions

File tree

documentation/components/bridges/phpunit-telemetry-bridge.md

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# PHPUnit Telemetry Bridge
22

3-
PHPUnit extension allowing to collect test suite telemetry and export to OTEL collector.
3+
PHPUnit extension allowing to collect test suite telemetry and export it to any OTLP-compatible backend (OpenTelemetry
4+
Collector, Grafana Alloy, Honeycomb, Datadog, Jaeger, etc.).
45

56
- [Back](/documentation/introduction.md)
67
- [Packagist](https://packagist.org/packages/flow-php/phpunit-telemetry-bridge)
@@ -12,47 +13,148 @@ PHPUnit extension allowing to collect test suite telemetry and export to OTEL co
1213

1314
## Installation
1415

15-
For detailed installation instructions, see the [installation page](/documentation/installation/packages/phpunit-telemetry-bridge.md).
16+
For detailed installation instructions, see
17+
the [installation page](/documentation/installation/packages/phpunit-telemetry-bridge.md).
1618

1719
## Configuration
1820

1921
Add the extension to your `phpunit.xml.dist`:
2022

2123
```xml
24+
2225
<extensions>
2326
<bootstrap class="Flow\Bridge\PHPUnit\Telemetry\TelemetryExtension">
2427
<parameter name="service_name" value="my-test-suite"/>
25-
<parameter name="otel_collector_url" value="http://localhost:4318"/>
28+
<parameter name="endpoint" value="http://localhost:4318"/>
2629
<parameter name="emit_traces" value="true"/>
2730
<parameter name="emit_metrics" value="true"/>
28-
<parameter name="emit_test_spans" value="false"/>
29-
<parameter name="emit_test_case_spans" value="false"/>
31+
<parameter name="emit_test_spans" value="true"/>
32+
<parameter name="emit_test_case_spans" value="true"/>
3033
</bootstrap>
3134
</extensions>
3235
```
3336

3437
## Configuration Parameters
3538

36-
| Parameter | Default | Description |
37-
|-----------|---------|-------------|
38-
| `service_name` | `phpunit` | Service name used in telemetry data |
39-
| `otel_collector_url` | `http://localhost:4318` | OTLP HTTP endpoint URL |
40-
| `emit_traces` | `true` | Enable/disable trace emission |
41-
| `emit_metrics` | `true` | Enable/disable metric emission |
42-
| `emit_test_spans` | `true` | Create individual spans for each test |
43-
| `emit_test_case_spans` | `true` | Create spans for test case classes |
39+
### Shared
40+
41+
| Parameter | Environment variable | Default | Description |
42+
|------------------------|------------------------------------------|-------------------------|----------------------------------------------------------------|
43+
| `service_name` | `FLOW_PHPUNIT_OTEL_SERVICE_NAME` | `phpunit` | Service name reported in telemetry data |
44+
| `transport` | `FLOW_PHPUNIT_OTEL_TRANSPORT` | `curl` | Transport type: `curl` or `grpc` |
45+
| `endpoint` | `FLOW_PHPUNIT_OTEL_ENDPOINT` | `http://localhost:4318` | OTLP endpoint URL (for `grpc` use host:port, e.g. `otel:4317`) |
46+
| `headers` | `FLOW_PHPUNIT_OTEL_HEADERS` || Additional headers (see [Authentication](#authentication)) |
47+
| `emit_traces` | `FLOW_PHPUNIT_OTEL_EMIT_TRACES` | `true` | Enable/disable trace emission |
48+
| `emit_metrics` | `FLOW_PHPUNIT_OTEL_EMIT_METRICS` | `true` | Enable/disable metric emission |
49+
| `emit_test_spans` | `FLOW_PHPUNIT_OTEL_EMIT_TEST_SPANS` | `true` | Create individual spans for each test |
50+
| `emit_test_case_spans` | `FLOW_PHPUNIT_OTEL_EMIT_TEST_CASE_SPANS` | `true` | Create spans for test case classes |
51+
52+
### Curl transport (`transport=curl`)
53+
54+
| Parameter | Environment variable | Default | Description |
55+
|-------------------------|-------------------------------------------|---------|---------------------------------------------|
56+
| `curl_timeout` | `FLOW_PHPUNIT_OTEL_CURL_TIMEOUT` | `30` | Request timeout in seconds |
57+
| `curl_connect_timeout` | `FLOW_PHPUNIT_OTEL_CURL_CONNECT_TIMEOUT` | `10` | Connection timeout in seconds |
58+
| `curl_compression` | `FLOW_PHPUNIT_OTEL_CURL_COMPRESSION` | `false` | Enable automatic response decompression |
59+
| `curl_follow_redirects` | `FLOW_PHPUNIT_OTEL_CURL_FOLLOW_REDIRECTS` | `true` | Follow HTTP redirects |
60+
| `curl_max_redirects` | `FLOW_PHPUNIT_OTEL_CURL_MAX_REDIRECTS` | `3` | Maximum number of redirects to follow |
61+
| `curl_proxy` | `FLOW_PHPUNIT_OTEL_CURL_PROXY` || Proxy server URL (e.g. `http://proxy:8080`) |
62+
| `curl_ssl_verify_peer` | `FLOW_PHPUNIT_OTEL_CURL_SSL_VERIFY_PEER` | `true` | Verify SSL peer certificate |
63+
| `curl_ssl_verify_host` | `FLOW_PHPUNIT_OTEL_CURL_SSL_VERIFY_HOST` | `true` | Verify SSL host name |
64+
| `curl_ssl_cert_path` | `FLOW_PHPUNIT_OTEL_CURL_SSL_CERT_PATH` || Path to client SSL certificate |
65+
| `curl_ssl_key_path` | `FLOW_PHPUNIT_OTEL_CURL_SSL_KEY_PATH` || Path to client SSL private key |
66+
| `curl_ca_info_path` | `FLOW_PHPUNIT_OTEL_CURL_CA_INFO_PATH` || Path to CA certificate bundle |
67+
| `curl_serializer` | `FLOW_PHPUNIT_OTEL_CURL_SERIALIZER` | `json` | Payload serializer: `json` or `protobuf` |
68+
69+
### gRPC transport (`transport=grpc`)
70+
71+
Requires the `grpc` PHP extension and the `google/protobuf` + `open-telemetry/gen-otlp-protobuf` packages. Payload is
72+
always protobuf (per OTLP/gRPC spec).
73+
74+
| Parameter | Environment variable | Default | Description |
75+
|-----------------|-----------------------------------|---------|----------------------------------|
76+
| `grpc_insecure` | `FLOW_PHPUNIT_OTEL_GRPC_INSECURE` | `true` | Use insecure channel credentials |
77+
78+
## Authentication
79+
80+
OTLP endpoints that require authentication (Grafana Alloy with Bearer auth, Honeycomb with `x-honeycomb-team`, vendor
81+
tenant headers, etc.) are configured through the `headers` parameter.
82+
83+
Headers use the OpenTelemetry spec format: comma-separated `name=value` pairs, with values URL-encoded (so commas,
84+
spaces and equal signs inside values don't collide with the delimiter):
85+
86+
```xml
87+
88+
<parameter name="endpoint" value="https://alloy.example.com:4318"/>
89+
<parameter name="headers" value="Authorization=Bearer%20xxx,X-Scope-OrgID=tenant-1"/>
90+
```
91+
92+
Invalid header format (missing `=`, empty name) will throw `InvalidArgumentException` when PHPUnit boots the extension.
93+
94+
## gRPC Transport
95+
96+
```xml
97+
98+
<extensions>
99+
<bootstrap class="Flow\Bridge\PHPUnit\Telemetry\TelemetryExtension">
100+
<parameter name="transport" value="grpc"/>
101+
<parameter name="endpoint" value="otel.example.com:4317"/>
102+
<parameter name="headers" value="api-key=xxx"/>
103+
<parameter name="grpc_insecure" value="false"/>
104+
</bootstrap>
105+
</extensions>
106+
```
107+
108+
## Environment Variables
109+
110+
Every parameter has an env var counterpart (see the tables above).
111+
112+
**Precedence:** environment variable > `<parameter>` in `phpunit.xml` > default. Empty-string env vars are treated as unset.
113+
114+
**Lookup order:** `$_ENV``$_SERVER``getenv()`. Values loaded by Symfony DotEnv or `vlucas/phpdotenv`
115+
(which populate `$_ENV` / `$_SERVER` but don't always call `putenv()`) are picked up the same as shell env vars.
116+
117+
> [!IMPORTANT]
118+
> When setting boolean env vars through PHPUnit's `<env>` directive in `phpunit.xml.dist`, add `verbatim="true"` — otherwise
119+
> PHPUnit casts the bare strings `"true"` / `"false"` to PHP booleans, which `putenv()` then stringifies to `"1"` / `""`, and
120+
> the empty string is treated as unset by the resolver (falling back to the default).
121+
>
122+
> ```xml
123+
> <env name="FLOW_PHPUNIT_OTEL_EMIT_TEST_SPANS" value="false" verbatim="true"/>
124+
> ```
125+
>
126+
> This only applies to `<env>` in PHPUnit XML; real shell env vars and `.env` entries are already plain strings.
127+
128+
Typical usage — credentials stay out of version control:
129+
130+
```bash
131+
export FLOW_PHPUNIT_OTEL_ENDPOINT="https://alloy.example.com:4318"
132+
export FLOW_PHPUNIT_OTEL_HEADERS="Authorization=Bearer%20${ALLOY_TOKEN}"
133+
134+
./vendor/bin/phpunit
135+
```
136+
137+
## Deprecation: `otel_collector_url`
138+
139+
The `otel_collector_url` parameter and its `FLOW_PHPUNIT_OTEL_COLLECTOR_URL` environment variable are deprecated and
140+
trigger `E_USER_DEPRECATED`. They remain functional as an alias for `endpoint` with `transport=curl`.
141+
142+
Mixing the deprecated parameter with any of the new-shape parameters (`transport`, `endpoint`, `headers`, `curl_*`,
143+
`grpc_*`) throws `InvalidArgumentException` — migrate fully when you switch.
44144

45145
## Features
46146

47147
### Traces
48148

49149
When enabled, the extension creates spans for:
150+
50151
- Test suite runs (root span)
51152
- Individual test suites
52153
- Test case classes (optional)
53154
- Individual tests (optional)
54155

55156
Each span includes attributes like:
157+
56158
- `test.suite` - Test suite name
57159
- `test.id` - Test identifier
58160
- `test.name` - Test name
@@ -63,6 +165,7 @@ Each span includes attributes like:
63165
### Metrics
64166

65167
When enabled, the extension records:
168+
66169
- `phpunit.suite.duration` - Histogram of suite execution time
67170
- `phpunit.suite.test_count` - Counter of tests per suite
68171
- `phpunit.test.duration` - Histogram of individual test execution time

documentation/components/bridges/symfony-telemetry-bundle.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,20 +440,18 @@ otlp:
440440

441441
#### grpc
442442

443-
gRPC transport.
443+
gRPC transport
444444

445445
| Option | Type | Default | Description |
446446
|------------|---------|---------|------------------------------|
447447
| `endpoint` | string | - | OTLP endpoint URL (required) |
448-
| `timeout` | integer | `30` | Request timeout in seconds |
449448
| `insecure` | boolean | `false` | Allow insecure connections |
450449

451450
```yaml
452451
otlp:
453452
transport:
454453
type: grpc
455454
endpoint: 'http://otel-collector:4317'
456-
timeout: 30
457455
insecure: true
458456
```
459457

documentation/installation/packages/phpunit-telemetry-bridge.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,16 @@ composer require flow-php/phpunit-telemetry-bridge:~--FLOW_PHP_VERSION--
2121
## Core Dependencies
2222

2323
- [phpunit/phpunit](https://packagist.org/packages/phpunit/phpunit)
24+
25+
## Optional Dependencies
26+
27+
The default `curl` transport works with the core dependencies only. To use the `grpc` transport, install:
28+
29+
- PHP extension [ext-grpc](https://github.com/grpc/grpc/tree/master/src/php)
30+
- [grpc/grpc](https://packagist.org/packages/grpc/grpc)
31+
- [google/protobuf](https://packagist.org/packages/google/protobuf)
32+
- [open-telemetry/gen-otlp-protobuf](https://packagist.org/packages/open-telemetry/gen-otlp-protobuf)
33+
34+
```bash
35+
composer require --dev grpc/grpc google/protobuf open-telemetry/gen-otlp-protobuf
36+
```

phpunit.xml.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@
310310
<extensions>
311311
<bootstrap class="Flow\Bridge\PHPUnit\Telemetry\TelemetryExtension">
312312
<parameter name="service_name" value="flow-php-test-suite"/>
313-
<parameter name="otel_collector_url" value="http://localhost:4318"/>
313+
<parameter name="endpoint" value="http://localhost:4318"/>
314314
<parameter name="emit_traces" value="true"/>
315315
<parameter name="emit_metrics" value="true"/>
316316
<parameter name="emit_test_spans" value="false"/>

src/bridge/phpunit/telemetry/composer.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@
1919
"flow-php/telemetry-otlp-bridge": "self.version",
2020
"phpunit/phpunit": "^11"
2121
},
22+
"require-dev": {
23+
"google/protobuf": "^4.0 || ^5.0",
24+
"grpc/grpc": "^1.74",
25+
"open-telemetry/gen-otlp-protobuf": "^1.8"
26+
},
27+
"suggest": {
28+
"ext-grpc": "Required for the gRPC transport",
29+
"google/protobuf": "Required for the gRPC transport and for curl transport with protobuf serializer",
30+
"open-telemetry/gen-otlp-protobuf": "Generated PHP classes for OTLP protobuf messages (required for gRPC transport)"
31+
},
2232
"autoload": {
2333
"psr-4": {
2434
"Flow\\": [

0 commit comments

Comments
 (0)