@@ -478,7 +478,8 @@ <h1 class="hidden lg:block">
478478 </div>
479479
480480 <h1><a id="phpunit-telemetry-bridge" href="#phpunit-telemetry-bridge" class="mr-2" aria-hidden="true" title="Permalink">#</a>PHPUnit Telemetry Bridge</h1>
481- <p>PHPUnit extension allowing to collect test suite telemetry and export to OTEL collector.</p>
481+ <p>PHPUnit extension allowing to collect test suite telemetry and export it to any OTLP-compatible backend (OpenTelemetry
482+ Collector, Grafana Alloy, Honeycomb, Datadog, Jaeger, etc.).</p>
482483<ul>
483484<li><a href="/documentation/introduction">Back</a></li>
484485<li><a rel="noopener noreferrer" target="_blank" href="https://packagist.org/packages/flow-php/phpunit-telemetry-bridge">Packagist</a></li>
@@ -488,7 +489,17 @@ <h1><a id="phpunit-telemetry-bridge" href="#phpunit-telemetry-bridge" class="mr-
488489</ul>
489490<div class="toc-wrapper" data-controller="toc"><div class="toc-header" data-action="click->toc#toggle"><span>Table of Contents</span><svg class="toc-arrow" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9" /></svg></div><div class="toc-content"><ul class="table-of-contents"><li><a href="#installation">Installation</a></li>
490491<li><a href="#configuration">Configuration</a></li>
491- <li><a href="#configuration-parameters">Configuration Parameters</a></li>
492+ <li><a href="#configuration-parameters">Configuration Parameters</a>
493+ <ul>
494+ <li><a href="#shared">Shared</a></li>
495+ <li><a href="#curl-transport-transportcurl">Curl transport (transport=curl)</a></li>
496+ <li><a href="#grpc-transport-transportgrpc">gRPC transport (transport=grpc)</a></li>
497+ </ul>
498+ </li>
499+ <li><a href="#authentication">Authentication</a></li>
500+ <li><a href="#grpc-transport">gRPC Transport</a></li>
501+ <li><a href="#environment-variables">Environment Variables</a></li>
502+ <li><a href="#deprecation-otelcollectorurl">Deprecation: otel_collector_url</a></li>
492503<li><a href="#features">Features</a>
493504<ul>
494505<li><a href="#traces">Traces</a></li>
@@ -497,62 +508,236 @@ <h1><a id="phpunit-telemetry-bridge" href="#phpunit-telemetry-bridge" class="mr-
497508</li>
498509<li><a href="#running-with-docker-compose">Running with Docker Compose</a></li></ul></div></div>
499510<h2><a id="installation" href="#installation" class="mr-2" aria-hidden="true" title="Permalink">#</a>Installation</h2>
500- <p>For detailed installation instructions, see the <a href="/documentation/installation/packages/phpunit-telemetry-bridge">installation page</a>.</p>
511+ <p>For detailed installation instructions, see
512+ the <a href="/documentation/installation/packages/phpunit-telemetry-bridge">installation page</a>.</p>
501513<h2><a id="configuration" href="#configuration" class="mr-2" aria-hidden="true" title="Permalink">#</a>Configuration</h2>
502514<p>Add the extension to your <code>phpunit.xml.dist</code>:</p>
503- <pre class="language-xml" data-controller="syntax-highlight"><code class="language-xml"><extensions>
515+ <pre class="language-xml" data-controller="syntax-highlight"><code class="language-xml">
516+ <extensions>
504517 <bootstrap class="Flow\Bridge\PHPUnit\Telemetry\TelemetryExtension">
505518 <parameter name="service_name" value="my-test-suite"/>
506- <parameter name="otel_collector_url " value="http://localhost:4318"/>
519+ <parameter name="endpoint " value="http://localhost:4318"/>
507520 <parameter name="emit_traces" value="true"/>
508521 <parameter name="emit_metrics" value="true"/>
509- <parameter name="emit_test_spans" value="false "/>
510- <parameter name="emit_test_case_spans" value="false "/>
522+ <parameter name="emit_test_spans" value="true "/>
523+ <parameter name="emit_test_case_spans" value="true "/>
511524 </bootstrap>
512525</extensions>
513526</code></pre>
514527<h2><a id="configuration-parameters" href="#configuration-parameters" class="mr-2" aria-hidden="true" title="Permalink">#</a>Configuration Parameters</h2>
528+ <h3><a id="shared" href="#shared" class="mr-2" aria-hidden="true" title="Permalink">#</a>Shared</h3>
515529<table>
516530<thead>
517531<tr>
518532<th>Parameter</th>
533+ <th>Environment variable</th>
519534<th>Default</th>
520535<th>Description</th>
521536</tr>
522537</thead>
523538<tbody>
524539<tr>
525540<td><code>service_name</code></td>
541+ <td><code>FLOW_PHPUNIT_OTEL_SERVICE_NAME</code></td>
526542<td><code>phpunit</code></td>
527- <td>Service name used in telemetry data</td>
543+ <td>Service name reported in telemetry data</td>
544+ </tr>
545+ <tr>
546+ <td><code>transport</code></td>
547+ <td><code>FLOW_PHPUNIT_OTEL_TRANSPORT</code></td>
548+ <td><code>curl</code></td>
549+ <td>Transport type: <code>curl</code> or <code>grpc</code></td>
528550</tr>
529551<tr>
530- <td><code>otel_collector_url</code></td>
552+ <td><code>endpoint</code></td>
553+ <td><code>FLOW_PHPUNIT_OTEL_ENDPOINT</code></td>
531554<td><code>http://localhost:4318</code></td>
532- <td>OTLP HTTP endpoint URL</td>
555+ <td>OTLP endpoint URL (for <code>grpc</code> use host:port, e.g. <code>otel:4317</code>)</td>
556+ </tr>
557+ <tr>
558+ <td><code>headers</code></td>
559+ <td><code>FLOW_PHPUNIT_OTEL_HEADERS</code></td>
560+ <td>—</td>
561+ <td>Additional headers (see <a href="#authentication">Authentication</a>)</td>
533562</tr>
534563<tr>
535564<td><code>emit_traces</code></td>
565+ <td><code>FLOW_PHPUNIT_OTEL_EMIT_TRACES</code></td>
536566<td><code>true</code></td>
537567<td>Enable/disable trace emission</td>
538568</tr>
539569<tr>
540570<td><code>emit_metrics</code></td>
571+ <td><code>FLOW_PHPUNIT_OTEL_EMIT_METRICS</code></td>
541572<td><code>true</code></td>
542573<td>Enable/disable metric emission</td>
543574</tr>
544575<tr>
545576<td><code>emit_test_spans</code></td>
577+ <td><code>FLOW_PHPUNIT_OTEL_EMIT_TEST_SPANS</code></td>
546578<td><code>true</code></td>
547579<td>Create individual spans for each test</td>
548580</tr>
549581<tr>
550582<td><code>emit_test_case_spans</code></td>
583+ <td><code>FLOW_PHPUNIT_OTEL_EMIT_TEST_CASE_SPANS</code></td>
551584<td><code>true</code></td>
552585<td>Create spans for test case classes</td>
553586</tr>
554587</tbody>
555588</table>
589+ <h3><a id="curl-transport-transportcurl" href="#curl-transport-transportcurl" class="mr-2" aria-hidden="true" title="Permalink">#</a>Curl transport (<code>transport=curl</code>)</h3>
590+ <table>
591+ <thead>
592+ <tr>
593+ <th>Parameter</th>
594+ <th>Environment variable</th>
595+ <th>Default</th>
596+ <th>Description</th>
597+ </tr>
598+ </thead>
599+ <tbody>
600+ <tr>
601+ <td><code>curl_timeout</code></td>
602+ <td><code>FLOW_PHPUNIT_OTEL_CURL_TIMEOUT</code></td>
603+ <td><code>30</code></td>
604+ <td>Request timeout in seconds</td>
605+ </tr>
606+ <tr>
607+ <td><code>curl_connect_timeout</code></td>
608+ <td><code>FLOW_PHPUNIT_OTEL_CURL_CONNECT_TIMEOUT</code></td>
609+ <td><code>10</code></td>
610+ <td>Connection timeout in seconds</td>
611+ </tr>
612+ <tr>
613+ <td><code>curl_compression</code></td>
614+ <td><code>FLOW_PHPUNIT_OTEL_CURL_COMPRESSION</code></td>
615+ <td><code>false</code></td>
616+ <td>Enable automatic response decompression</td>
617+ </tr>
618+ <tr>
619+ <td><code>curl_follow_redirects</code></td>
620+ <td><code>FLOW_PHPUNIT_OTEL_CURL_FOLLOW_REDIRECTS</code></td>
621+ <td><code>true</code></td>
622+ <td>Follow HTTP redirects</td>
623+ </tr>
624+ <tr>
625+ <td><code>curl_max_redirects</code></td>
626+ <td><code>FLOW_PHPUNIT_OTEL_CURL_MAX_REDIRECTS</code></td>
627+ <td><code>3</code></td>
628+ <td>Maximum number of redirects to follow</td>
629+ </tr>
630+ <tr>
631+ <td><code>curl_proxy</code></td>
632+ <td><code>FLOW_PHPUNIT_OTEL_CURL_PROXY</code></td>
633+ <td>—</td>
634+ <td>Proxy server URL (e.g. <code>http://proxy:8080</code>)</td>
635+ </tr>
636+ <tr>
637+ <td><code>curl_ssl_verify_peer</code></td>
638+ <td><code>FLOW_PHPUNIT_OTEL_CURL_SSL_VERIFY_PEER</code></td>
639+ <td><code>true</code></td>
640+ <td>Verify SSL peer certificate</td>
641+ </tr>
642+ <tr>
643+ <td><code>curl_ssl_verify_host</code></td>
644+ <td><code>FLOW_PHPUNIT_OTEL_CURL_SSL_VERIFY_HOST</code></td>
645+ <td><code>true</code></td>
646+ <td>Verify SSL host name</td>
647+ </tr>
648+ <tr>
649+ <td><code>curl_ssl_cert_path</code></td>
650+ <td><code>FLOW_PHPUNIT_OTEL_CURL_SSL_CERT_PATH</code></td>
651+ <td>—</td>
652+ <td>Path to client SSL certificate</td>
653+ </tr>
654+ <tr>
655+ <td><code>curl_ssl_key_path</code></td>
656+ <td><code>FLOW_PHPUNIT_OTEL_CURL_SSL_KEY_PATH</code></td>
657+ <td>—</td>
658+ <td>Path to client SSL private key</td>
659+ </tr>
660+ <tr>
661+ <td><code>curl_ca_info_path</code></td>
662+ <td><code>FLOW_PHPUNIT_OTEL_CURL_CA_INFO_PATH</code></td>
663+ <td>—</td>
664+ <td>Path to CA certificate bundle</td>
665+ </tr>
666+ <tr>
667+ <td><code>curl_serializer</code></td>
668+ <td><code>FLOW_PHPUNIT_OTEL_CURL_SERIALIZER</code></td>
669+ <td><code>json</code></td>
670+ <td>Payload serializer: <code>json</code> or <code>protobuf</code></td>
671+ </tr>
672+ </tbody>
673+ </table>
674+ <h3><a id="grpc-transport-transportgrpc" href="#grpc-transport-transportgrpc" class="mr-2" aria-hidden="true" title="Permalink">#</a>gRPC transport (<code>transport=grpc</code>)</h3>
675+ <p>Requires the <code>grpc</code> PHP extension and the <code>google/protobuf</code> + <code>open-telemetry/gen-otlp-protobuf</code> packages. Payload is
676+ always protobuf (per OTLP/gRPC spec).</p>
677+ <table>
678+ <thead>
679+ <tr>
680+ <th>Parameter</th>
681+ <th>Environment variable</th>
682+ <th>Default</th>
683+ <th>Description</th>
684+ </tr>
685+ </thead>
686+ <tbody>
687+ <tr>
688+ <td><code>grpc_insecure</code></td>
689+ <td><code>FLOW_PHPUNIT_OTEL_GRPC_INSECURE</code></td>
690+ <td><code>true</code></td>
691+ <td>Use insecure channel credentials</td>
692+ </tr>
693+ </tbody>
694+ </table>
695+ <h2><a id="authentication" href="#authentication" class="mr-2" aria-hidden="true" title="Permalink">#</a>Authentication</h2>
696+ <p>OTLP endpoints that require authentication (Grafana Alloy with Bearer auth, Honeycomb with <code>x-honeycomb-team</code>, vendor
697+ tenant headers, etc.) are configured through the <code>headers</code> parameter.</p>
698+ <p>Headers use the OpenTelemetry spec format: comma-separated <code>name=value</code> pairs, with values URL-encoded (so commas,
699+ spaces and equal signs inside values don't collide with the delimiter):</p>
700+ <pre class="language-xml" data-controller="syntax-highlight"><code class="language-xml">
701+ <parameter name="endpoint" value="https://alloy.example.com:4318"/>
702+ <parameter name="headers" value="Authorization=Bearer%20xxx,X-Scope-OrgID=tenant-1"/>
703+ </code></pre>
704+ <p>Invalid header format (missing <code>=</code>, empty name) will throw <code>InvalidArgumentException</code> when PHPUnit boots the extension.</p>
705+ <h2><a id="grpc-transport" href="#grpc-transport" class="mr-2" aria-hidden="true" title="Permalink">#</a>gRPC Transport</h2>
706+ <pre class="language-xml" data-controller="syntax-highlight"><code class="language-xml">
707+ <extensions>
708+ <bootstrap class="Flow\Bridge\PHPUnit\Telemetry\TelemetryExtension">
709+ <parameter name="transport" value="grpc"/>
710+ <parameter name="endpoint" value="otel.example.com:4317"/>
711+ <parameter name="headers" value="api-key=xxx"/>
712+ <parameter name="grpc_insecure" value="false"/>
713+ </bootstrap>
714+ </extensions>
715+ </code></pre>
716+ <h2><a id="environment-variables" href="#environment-variables" class="mr-2" aria-hidden="true" title="Permalink">#</a>Environment Variables</h2>
717+ <p>Every parameter has an env var counterpart (see the tables above).</p>
718+ <p><strong>Precedence:</strong> environment variable > <code><parameter></code> in <code>phpunit.xml</code> > default. Empty-string env vars are treated as unset.</p>
719+ <p><strong>Lookup order:</strong> <code>$_ENV</code> → <code>$_SERVER</code> → <code>getenv()</code>. Values loaded by Symfony DotEnv or <code>vlucas/phpdotenv</code>
720+ (which populate <code>$_ENV</code> / <code>$_SERVER</code> but don't always call <code>putenv()</code>) are picked up the same as shell env vars.</p>
721+ <blockquote>
722+ <p>[!IMPORTANT]
723+ When setting boolean env vars through PHPUnit's <code><env></code> directive in <code>phpunit.xml.dist</code>, add <code>verbatim="true"</code> — otherwise
724+ PHPUnit casts the bare strings <code>"true"</code> / <code>"false"</code> to PHP booleans, which <code>putenv()</code> then stringifies to <code>"1"</code> / <code>""</code>, and
725+ the empty string is treated as unset by the resolver (falling back to the default).</p>
726+ <pre class="language-xml" data-controller="syntax-highlight"><code class="language-xml"><env name="FLOW_PHPUNIT_OTEL_EMIT_TEST_SPANS" value="false" verbatim="true"/>
727+ </code></pre>
728+ <p>This only applies to <code><env></code> in PHPUnit XML; real shell env vars and <code>.env</code> entries are already plain strings.</p>
729+ </blockquote>
730+ <p>Typical usage — credentials stay out of version control:</p>
731+ <pre class="language-bash" data-controller="syntax-highlight"><code class="language-bash">export FLOW_PHPUNIT_OTEL_ENDPOINT="https://alloy.example.com:4318"
732+ export FLOW_PHPUNIT_OTEL_HEADERS="Authorization=Bearer%20${ALLOY_TOKEN}"
733+
734+ ./vendor/bin/phpunit
735+ </code></pre>
736+ <h2><a id="deprecation-otelcollectorurl" href="#deprecation-otelcollectorurl" class="mr-2" aria-hidden="true" title="Permalink">#</a>Deprecation: <code>otel_collector_url</code></h2>
737+ <p>The <code>otel_collector_url</code> parameter and its <code>FLOW_PHPUNIT_OTEL_COLLECTOR_URL</code> environment variable are deprecated and
738+ trigger <code>E_USER_DEPRECATED</code>. They remain functional as an alias for <code>endpoint</code> with <code>transport=curl</code>.</p>
739+ <p>Mixing the deprecated parameter with any of the new-shape parameters (<code>transport</code>, <code>endpoint</code>, <code>headers</code>, <code>curl_*</code>,
740+ <code>grpc_*</code>) throws <code>InvalidArgumentException</code> — migrate fully when you switch.</p>
556741<h2><a id="features" href="#features" class="mr-2" aria-hidden="true" title="Permalink">#</a>Features</h2>
557742<h3><a id="traces" href="#traces" class="mr-2" aria-hidden="true" title="Permalink">#</a>Traces</h3>
558743<p>When enabled, the extension creates spans for:</p>
0 commit comments