diff --git a/.env.example b/.env.example
index d073ac542..81c62d235 100644
--- a/.env.example
+++ b/.env.example
@@ -212,9 +212,40 @@ EMAIL_TEMPLATE_TICKET_BOTTOM_GRAPHIC=https://spaces.fnvirtual.app/emails/REGISTR
EMAIL_TEMPLATE_PRIMARY_COLOR="#000000"
EMAIL_TEMPLATE_SECONDARY_COLOR="#808080"
-#Open Telemetry vars
-OTEL_EXPORTER_OTLP_ENDPOINT=
+#Open Telemetry
+OTEL_SERVICE_ENABLED=true
+OTEL_SERVICE_NAME=summit-api
+OTEL_PROPAGATORS=tracecontext,baggage
+OTEL_EXPORTER_OTLP_PROTOCOL=http/json # Supported values: "grpc", "http/protobuf", "http/json"
+OTEL_EXPORTER_OTLP_MAX_RETRIES=3
+OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
TRACE_SPAN_PREFIX=SPAN
+OTEL_TRACES_SAMPLER_PARENT=false
+# OTEL_TRACES_SAMPLER_TYPE=always_on # Supported values: "always_on", "always_off", "traceidratio"
+# OTEL_TRACES_SAMPLER_TRACEIDRATIO_RATIO=0.05
+# OTEL_METRICS_EXPORTER=otlp
+# OTEL_TRACES_EXPORTER=otlp
+# OTEL_LOGS_EXPORTER=otlp
+# OTEL_EXPORTER_OTLP_TIMEOUT=10000
+# OTEL_EXPORTER_OTLP_HEADERS=
+# OTEL_EXPORTER_OTLP_TRACES_TIMEOUT=10000
+# OTEL_EXPORTER_OTLP_TRACES_HEADERS=
+# OTEL_EXPORTER_OTLP_METRICS_TIMEOUT=10000
+# OTEL_EXPORTER_OTLP_METRICS_HEADERS=
+# OTEL_EXPORTER_OTLP_LOGS_TIMEOUT=10000
+# OTEL_EXPORTER_OTLP_LOGS_HEADERS=
+# OTEL_EXPORTER_ZIPKIN_ENDPOINT=http://localhost:9411
+# OTEL_EXPORTER_ZIPKIN_TIMEOUT=10000
+# OTEL_EXPORTER_ZIPKIN_MAX_RETRIES=3
+# OTEL_INSTRUMENTATION_HTTP_SERVER=true
+# OTEL_INSTRUMENTATION_HTTP_CLIENT=true
+# OTEL_INSTRUMENTATION_QUERY=true
+# OTEL_INSTRUMENTATION_REDIS=true
+# OTEL_INSTRUMENTATION_QUEUE=true
+# OTEL_INSTRUMENTATION_CACHE=true
+# OTEL_INSTRUMENTATION_VIEW=true
+# OTEL_INSTRUMENTATION_LIVEWIRE=true
+# OTEL_INSTRUMENTATION_CONSOLE=true
# SWAGGER CONFIG
diff --git a/app/Http/Middleware/TrackRequestMiddleware.php b/app/Http/Middleware/TrackRequestMiddleware.php
index 1700460a8..dafa06632 100644
--- a/app/Http/Middleware/TrackRequestMiddleware.php
+++ b/app/Http/Middleware/TrackRequestMiddleware.php
@@ -2,99 +2,85 @@
namespace App\Http\Middleware;
-use Illuminate\Http\Request;
use Closure;
-use Illuminate\Support\Str;
-use \OpenTelemetry\API\Trace\SpanInterface;
+use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
-use Illuminate\Log\LogManager;
use Keepsuit\LaravelOpenTelemetry\Facades\Tracer;
-
+use Illuminate\Log\LogManager;
+use OpenTelemetry\API\Baggage\Baggage;
+use OpenTelemetry\Context\ScopeInterface;
class TrackRequestMiddleware
{
- /**
- * @var LogManager
- */
- protected LogManager $logger;
+ private const ATTRIBUTE_START_TIME = '_start_time';
+ private const EVENT_REQUEST_STARTED = 'request.started';
+ private const EVENT_REQUEST_FINISHED = 'request.finished';
- /**
- * @var float
- */
- protected float $startTime = 0;
-
- /**
- * @var SpanInterface
- */
- protected SpanInterface $span;
+ protected LogManager $logger;
+ private ?ScopeInterface $baggageScope = null;
+ private bool $shouldTrack;
- /**
- * Constructor del middleware.
- * Laravel inyectará el LogManager aquí.
- *
- * @param LogManager $logger
- */
public function __construct(LogManager $logger)
{
$this->logger = $logger;
+ $this->shouldTrack = env('OTEL_SERVICE_ENABLED', false);
}
- /**
- * @param \Illuminate\Http\Request $request
- * @param \Closure $next
- * @return mixed
- */
public function handle(Request $request, Closure $next)
{
- if(env('APP_ENV') === 'testing') {
- // Skip tracking in testing environment
+ if (!$this->shouldTrack) {
return $next($request);
}
+
try {
- // generating dynamic id for span with configurable prefix
- $spanId = env('TRACE_SPAN_PREFIX', 'SPAN') . '_' . Str::uuid();
- $this->startTime = microtime(true);
- $this->span = Tracer::newSpan($spanId)->start();
+ $request->attributes->set(self::ATTRIBUTE_START_TIME, microtime(true));
+ if ($span = Tracer::activeSpan()) {
+ if ($ray = $request->header('cf-ray')) {
+ $span->setAttribute('cloudflare.cf-ray', $ray);
+
+ $baggage = Baggage::getCurrent()
+ ->toBuilder()
+ ->set('cf-ray', $ray)
+ ->set('user_agent', substr($request->userAgent() ?? 'unknown', 0, 100))
+ ->build();
- $this->logger->channel('otlp')->info('Request started.', [
- 'endpoint' => $request->url(),
- 'method' => $request->method(),
- 'timestamp_utc' => now()->toIso8601String(),
- ]);
+ $this->baggageScope = $baggage->activate();
+ }
+
+ $span->addEvent(self::EVENT_REQUEST_STARTED, [
+ 'method' => $request->method(),
+ 'url' => $request->fullUrl(),
+ ]);
+ }
} catch (\Throwable $e) {
- // forcing 'single' channel in case otlp log fails
- $this->logger->channel('single')->error("Error on request tracking" . $e->getMessage());
+ $this->logger->channel('daily')->error("Error on request tracking: " . $e->getMessage());
}
- $response = $next($request);
- return $response;
+ return $next($request);
}
- /**
- * @param Request $request
- * @param Response $response
- * @return void
- */
public function terminate(Request $request, Response $response): void
{
- if(env('APP_ENV') === 'testing') {
- // Skip tracking in testing environment
+ if (!$this->shouldTrack) {
return;
}
+
try {
- $endTime = microtime(true);
- $responseTime = intval(($endTime - $this->startTime) * 1000);
- $this->logger->channel('otlp')->info('Request finished.', [
- 'response_time' => $responseTime,
- ]);
+ $start = (float) $request->attributes->get(self::ATTRIBUTE_START_TIME, microtime(true));
+ $ms = (int) ((microtime(true) - $start) * 1000);
- if (isset($this->span)) {
- $this->span->end();
+ if ($span = Tracer::activeSpan()) {
+ $span->setAttribute('app.response_ms', $ms);
+ $span->setAttribute('http.status_code', $response->getStatusCode());
+ $span->addEvent(self::EVENT_REQUEST_FINISHED, ['response_ms' => $ms]);
}
-
} catch (\Throwable $e) {
- // forcing 'single' channel in case otlp log fails
- $this->logger->channel('single')->error("Error on request tracking: " . $e->getMessage());
+ $this->logger->channel('daily')->error("Error on request tracking: " . $e->getMessage());
+ } finally {
+ if ($this->baggageScope) {
+ $this->baggageScope->detach();
+ $this->baggageScope = null;
+ }
}
}
-}
\ No newline at end of file
+}
diff --git a/app/Services/Apis/MailApi.php b/app/Services/Apis/MailApi.php
index c62fea1e6..2919b7885 100644
--- a/app/Services/Apis/MailApi.php
+++ b/app/Services/Apis/MailApi.php
@@ -19,6 +19,7 @@
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
+use Keepsuit\LaravelOpenTelemetry\Support\HttpClient\GuzzleTraceMiddleware;
use libs\utils\ICacheService;
use models\exceptions\ValidationException;
/**
@@ -58,6 +59,7 @@ public function __construct(ICacheService $cacheService)
parent::__construct($cacheService);
$stack = HandlerStack::create();
$stack->push(GuzzleRetryMiddleware::factory());
+ $stack->push(GuzzleTraceMiddleware::make());
$this->client = new Client([
'handler' => $stack,
diff --git a/app/Services/Utils/RedisCacheService.php b/app/Services/Utils/RedisCacheService.php
index ae2bb19b2..22b9122b6 100644
--- a/app/Services/Utils/RedisCacheService.php
+++ b/app/Services/Utils/RedisCacheService.php
@@ -64,19 +64,25 @@ public function __destruct()
if (is_resource($res)) $metadata = @stream_get_meta_data($res);
}
} catch (\Throwable $ignored) {}
- Log::error
- (
- sprintf
+ // Check if Laravel app is still available before logging
+ if (app()->bound('config')) {
+ Log::error
(
- "RedisCacheService::__destruct %s %s %s",
- $ex->getCode(),
- $ex->getMessage(),
- var_export($metadata, true)
- )
- );
+ sprintf
+ (
+ "RedisCacheService::__destruct %s %s %s",
+ $ex->getCode(),
+ $ex->getMessage(),
+ var_export($metadata, true)
+ )
+ );
+ }
}
catch(\Exception $ex){
- Log::warning($ex);
+ // Check if Laravel app is still available before logging
+ if (app()->bound('config')) {
+ Log::warning($ex);
+ }
}
}
@@ -325,7 +331,7 @@ public function ttl($key)
return (int)$conn->ttl($key);
}, 0);
}
-
+
/**
* @param string $cache_region_key
* @return void
diff --git a/composer.json b/composer.json
index d037f8fd1..9b23e1dd1 100644
--- a/composer.json
+++ b/composer.json
@@ -31,7 +31,7 @@
"google/apiclient": "^2.2",
"guzzlehttp/guzzle": "7.8.2",
"guzzlehttp/uri-template": "^1.0",
- "keepsuit/laravel-opentelemetry": "^1.6",
+ "keepsuit/laravel-opentelemetry": "^1.11.0",
"laminas/laminas-math": "^3.7",
"laravel-doctrine/extensions": "2.0.1",
"laravel-doctrine/migrations": "3.4.0",
@@ -66,10 +66,10 @@
"rector/rector": "*",
"spatie/laravel-ignition": "^2.8.0"
},
- "suggest":{
+ "suggest": {
"lib-openssl": "Required to use AES algorithms (except AES GCM)",
- "ext-json":"Required to use json algorithms",
- "ext-gd":"Required to use json algorithms"
+ "ext-json": "Required to use json algorithms",
+ "ext-gd": "Required to use json algorithms"
},
"autoload": {
"classmap": [
@@ -82,9 +82,15 @@
"vendor/affinipay/chargeio-php/lib"
],
"psr-4": {
- "App\\": "app/"
+ "App\\": "app/",
+ "OpenTelemetry\\SemConv\\Unstable\\Metrics\\": "vendor/open-telemetry/sem-conv/Incubating/Metrics/",
+ "OpenTelemetry\\" : "vendor/open-telemetry/",
+ "OpenTelemetry\\API\\": "vendor/open-telemetry/api/"
+
},
- "files": ["app/Utils/helpers.php"]
+ "files": [
+ "app/Utils/helpers.php"
+ ]
},
"autoload-dev": {
"psr-4": {
@@ -128,4 +134,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
-}
+}
\ No newline at end of file
diff --git a/composer.lock b/composer.lock
index 96b8bc574..e152f2f02 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "421f8844647bf58c468b08e83e30f2d8",
+ "content-hash": "0fe683ede6eab50b8e08f13b3e2791cf",
"packages": [
{
"name": "affinipay/chargeio-php",
@@ -621,16 +621,16 @@
},
{
"name": "composer/semver",
- "version": "3.4.3",
+ "version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
"shasum": ""
},
"require": {
@@ -682,7 +682,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
- "source": "https://github.com/composer/semver/tree/3.4.3"
+ "source": "https://github.com/composer/semver/tree/3.4.4"
},
"funding": [
{
@@ -692,13 +692,9 @@
{
"url": "https://github.com/composer",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
}
],
- "time": "2024-09-19T14:15:21+00:00"
+ "time": "2025-08-20T19:15:30+00:00"
},
{
"name": "darkaonline/l5-swagger",
@@ -1363,33 +1359,32 @@
},
{
"name": "doctrine/inflector",
- "version": "2.0.10",
+ "version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
- "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc"
+ "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc",
- "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc",
+ "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b",
+ "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
- "doctrine/coding-standard": "^11.0",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-phpunit": "^1.1",
- "phpstan/phpstan-strict-rules": "^1.3",
- "phpunit/phpunit": "^8.5 || ^9.5",
- "vimeo/psalm": "^4.25 || ^5.4"
+ "doctrine/coding-standard": "^12.0 || ^13.0",
+ "phpstan/phpstan": "^1.12 || ^2.0",
+ "phpstan/phpstan-phpunit": "^1.4 || ^2.0",
+ "phpstan/phpstan-strict-rules": "^1.6 || ^2.0",
+ "phpunit/phpunit": "^8.5 || ^12.2"
},
"type": "library",
"autoload": {
"psr-4": {
- "Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
+ "Doctrine\\Inflector\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1434,7 +1429,7 @@
],
"support": {
"issues": "https://github.com/doctrine/inflector/issues",
- "source": "https://github.com/doctrine/inflector/tree/2.0.10"
+ "source": "https://github.com/doctrine/inflector/tree/2.1.0"
},
"funding": [
{
@@ -1450,7 +1445,7 @@
"type": "tidelift"
}
],
- "time": "2024-02-18T20:23:39+00:00"
+ "time": "2025-08-10T19:31:58+00:00"
},
{
"name": "doctrine/instantiator",
@@ -2486,23 +2481,23 @@
},
{
"name": "google/protobuf",
- "version": "v4.31.1",
+ "version": "v4.32.1",
"source": {
"type": "git",
"url": "https://github.com/protocolbuffers/protobuf-php.git",
- "reference": "2b028ce8876254e2acbeceea7d9b573faad41864"
+ "reference": "c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/2b028ce8876254e2acbeceea7d9b573faad41864",
- "reference": "2b028ce8876254e2acbeceea7d9b573faad41864",
+ "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb",
+ "reference": "c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb",
"shasum": ""
},
"require": {
- "php": ">=7.0.0"
+ "php": ">=8.1.0"
},
"require-dev": {
- "phpunit/phpunit": ">=5.0.0"
+ "phpunit/phpunit": ">=5.0.0 <8.5.27"
},
"suggest": {
"ext-bcmath": "Need to support JSON deserialization"
@@ -2524,9 +2519,9 @@
"proto"
],
"support": {
- "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.31.1"
+ "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.32.1"
},
- "time": "2025-05-28T18:52:35+00:00"
+ "time": "2025-09-14T05:14:52+00:00"
},
{
"name": "graham-campbell/guzzle-factory",
@@ -2783,16 +2778,16 @@
},
{
"name": "guzzlehttp/promises",
- "version": "2.2.0",
+ "version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
- "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
+ "reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
- "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
+ "reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
@@ -2800,7 +2795,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
- "phpunit/phpunit": "^8.5.39 || ^9.6.20"
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"type": "library",
"extra": {
@@ -2846,7 +2841,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
- "source": "https://github.com/guzzle/promises/tree/2.2.0"
+ "source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
@@ -2862,20 +2857,20 @@
"type": "tidelift"
}
],
- "time": "2025-03-27T13:27:01+00:00"
+ "time": "2025-08-22T14:34:08+00:00"
},
{
"name": "guzzlehttp/psr7",
- "version": "2.7.1",
+ "version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
+ "reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
- "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
+ "reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
@@ -2891,7 +2886,7 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
- "phpunit/phpunit": "^8.5.39 || ^9.6.20"
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@@ -2962,7 +2957,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/2.7.1"
+ "source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
@@ -2978,20 +2973,20 @@
"type": "tidelift"
}
],
- "time": "2025-03-27T12:30:47+00:00"
+ "time": "2025-08-23T21:21:41+00:00"
},
{
"name": "guzzlehttp/uri-template",
- "version": "v1.0.4",
+ "version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/guzzle/uri-template.git",
- "reference": "30e286560c137526eccd4ce21b2de477ab0676d2"
+ "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2",
- "reference": "30e286560c137526eccd4ce21b2de477ab0676d2",
+ "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1",
+ "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1",
"shasum": ""
},
"require": {
@@ -3000,7 +2995,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
- "phpunit/phpunit": "^8.5.36 || ^9.6.15",
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25",
"uri-template/tests": "1.0.0"
},
"type": "library",
@@ -3048,7 +3043,7 @@
],
"support": {
"issues": "https://github.com/guzzle/uri-template/issues",
- "source": "https://github.com/guzzle/uri-template/tree/v1.0.4"
+ "source": "https://github.com/guzzle/uri-template/tree/v1.0.5"
},
"funding": [
{
@@ -3064,7 +3059,7 @@
"type": "tidelift"
}
],
- "time": "2025-02-03T10:55:03+00:00"
+ "time": "2025-08-22T14:27:06+00:00"
},
{
"name": "justinrainbow/json-schema",
@@ -3133,26 +3128,26 @@
},
{
"name": "keepsuit/laravel-opentelemetry",
- "version": "1.6.0",
+ "version": "1.11.0",
"source": {
"type": "git",
"url": "https://github.com/keepsuit/laravel-opentelemetry.git",
- "reference": "cfa03dbdfdb4b97152e19b20c989209caa8802b0"
+ "reference": "f37602e38801e598e805646e598d70679082abc1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/keepsuit/laravel-opentelemetry/zipball/cfa03dbdfdb4b97152e19b20c989209caa8802b0",
- "reference": "cfa03dbdfdb4b97152e19b20c989209caa8802b0",
+ "url": "https://api.github.com/repos/keepsuit/laravel-opentelemetry/zipball/f37602e38801e598e805646e598d70679082abc1",
+ "reference": "f37602e38801e598e805646e598d70679082abc1",
"shasum": ""
},
"require": {
- "illuminate/contracts": "^10.0 || ^11.0 || ^12.0",
- "illuminate/support": "^10.0 || ^11.0 || ^12.0",
- "open-telemetry/api": "^1.1",
- "open-telemetry/context": "^1.1",
- "open-telemetry/exporter-otlp": "^1.1",
- "open-telemetry/sdk": "^1.1",
- "open-telemetry/sem-conv": "^1.28.0",
+ "illuminate/contracts": "^10.14 || ^11.0 || ^12.0",
+ "illuminate/support": "^10.14 || ^11.0 || ^12.0",
+ "open-telemetry/api": "^1.4",
+ "open-telemetry/context": "^1.3",
+ "open-telemetry/exporter-otlp": "^1.3",
+ "open-telemetry/sdk": "^1.7",
+ "open-telemetry/sem-conv": "^1.37",
"php": "^8.1",
"spatie/laravel-package-tools": "^1.16",
"thecodingmachine/safe": "^2.0 || ^3.0"
@@ -3164,6 +3159,7 @@
},
"require-dev": {
"guzzlehttp/guzzle": "^7.3",
+ "guzzlehttp/psr7": "^2.0",
"guzzlehttp/test-server": "^0.1.0",
"larastan/larastan": "^2.9 || ^3.0",
"laravel/pint": "^1.18",
@@ -3224,9 +3220,9 @@
],
"support": {
"issues": "https://github.com/keepsuit/laravel-opentelemetry/issues",
- "source": "https://github.com/keepsuit/laravel-opentelemetry/tree/1.6.0"
+ "source": "https://github.com/keepsuit/laravel-opentelemetry/tree/1.11.0"
},
- "time": "2025-06-19T12:37:02+00:00"
+ "time": "2025-09-15T12:25:50+00:00"
},
{
"name": "laminas/laminas-math",
@@ -3811,16 +3807,16 @@
},
{
"name": "laravel/prompts",
- "version": "v0.3.5",
+ "version": "v0.3.6",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
- "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1"
+ "reference": "86a8b692e8661d0fb308cec64f3d176821323077"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1",
- "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1",
+ "url": "https://api.github.com/repos/laravel/prompts/zipball/86a8b692e8661d0fb308cec64f3d176821323077",
+ "reference": "86a8b692e8661d0fb308cec64f3d176821323077",
"shasum": ""
},
"require": {
@@ -3864,9 +3860,9 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
- "source": "https://github.com/laravel/prompts/tree/v0.3.5"
+ "source": "https://github.com/laravel/prompts/tree/v0.3.6"
},
- "time": "2025-02-11T13:34:40+00:00"
+ "time": "2025-07-07T14:17:42+00:00"
},
{
"name": "laravel/serializable-closure",
@@ -3997,16 +3993,16 @@
},
{
"name": "league/commonmark",
- "version": "2.7.0",
+ "version": "2.7.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
- "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405"
+ "reference": "10732241927d3971d28e7ea7b5712721fa2296ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
- "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
+ "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca",
+ "reference": "10732241927d3971d28e7ea7b5712721fa2296ca",
"shasum": ""
},
"require": {
@@ -4035,7 +4031,7 @@
"symfony/process": "^5.4 | ^6.0 | ^7.0",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0",
"unleashedtech/php-coding-standard": "^3.1.1",
- "vimeo/psalm": "^4.24.0 || ^5.0.0"
+ "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0"
},
"suggest": {
"symfony/yaml": "v2.3+ required if using the Front Matter extension"
@@ -4100,7 +4096,7 @@
"type": "tidelift"
}
],
- "time": "2025-05-05T12:20:28+00:00"
+ "time": "2025-07-20T12:47:49+00:00"
},
{
"name": "league/config",
@@ -4277,16 +4273,16 @@
},
{
"name": "league/flysystem",
- "version": "3.29.1",
+ "version": "3.30.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
- "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319"
+ "reference": "2203e3151755d874bb2943649dae1eb8533ac93e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319",
- "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e",
+ "reference": "2203e3151755d874bb2943649dae1eb8533ac93e",
"shasum": ""
},
"require": {
@@ -4310,13 +4306,13 @@
"composer/semver": "^3.0",
"ext-fileinfo": "*",
"ext-ftp": "*",
- "ext-mongodb": "^1.3",
+ "ext-mongodb": "^1.3|^2",
"ext-zip": "*",
"friendsofphp/php-cs-fixer": "^3.5",
"google/cloud-storage": "^1.23",
"guzzlehttp/psr7": "^2.6",
"microsoft/azure-storage-blob": "^1.1",
- "mongodb/mongodb": "^1.2",
+ "mongodb/mongodb": "^1.2|^2",
"phpseclib/phpseclib": "^3.0.36",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.5.11|^10.0",
@@ -4354,9 +4350,9 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
- "source": "https://github.com/thephpleague/flysystem/tree/3.29.1"
+ "source": "https://github.com/thephpleague/flysystem/tree/3.30.0"
},
- "time": "2024-10-08T08:58:34+00:00"
+ "time": "2025-06-25T13:29:59+00:00"
},
{
"name": "league/flysystem-aws-s3-v3",
@@ -4430,16 +4426,16 @@
},
{
"name": "league/flysystem-local",
- "version": "3.29.0",
+ "version": "3.30.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git",
- "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27"
+ "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27",
- "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27",
+ "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/6691915f77c7fb69adfb87dcd550052dc184ee10",
+ "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10",
"shasum": ""
},
"require": {
@@ -4473,9 +4469,9 @@
"local"
],
"support": {
- "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0"
+ "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.0"
},
- "time": "2024-08-09T21:24:39+00:00"
+ "time": "2025-05-21T10:34:19+00:00"
},
{
"name": "league/mime-type-detection",
@@ -5001,16 +4997,16 @@
},
{
"name": "nesbot/carbon",
- "version": "3.10.0",
+ "version": "3.10.3",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
- "reference": "c1397390dd0a7e0f11660f0ae20f753d88c1f3d9"
+ "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/c1397390dd0a7e0f11660f0ae20f753d88c1f3d9",
- "reference": "c1397390dd0a7e0f11660f0ae20f753d88c1f3d9",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
+ "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
"shasum": ""
},
"require": {
@@ -5028,13 +5024,13 @@
"require-dev": {
"doctrine/dbal": "^3.6.3 || ^4.0",
"doctrine/orm": "^2.15.2 || ^3.0",
- "friendsofphp/php-cs-fixer": "^3.75.0",
+ "friendsofphp/php-cs-fixer": "^v3.87.1",
"kylekatarnls/multi-tester": "^2.5.3",
"phpmd/phpmd": "^2.15.0",
"phpstan/extension-installer": "^1.4.3",
- "phpstan/phpstan": "^2.1.17",
- "phpunit/phpunit": "^10.5.46",
- "squizlabs/php_codesniffer": "^3.13.0"
+ "phpstan/phpstan": "^2.1.22",
+ "phpunit/phpunit": "^10.5.53",
+ "squizlabs/php_codesniffer": "^3.13.4"
},
"bin": [
"bin/carbon"
@@ -5102,7 +5098,7 @@
"type": "tidelift"
}
],
- "time": "2025-06-12T10:24:28+00:00"
+ "time": "2025-09-06T13:39:36+00:00"
},
{
"name": "nette/schema",
@@ -5168,29 +5164,29 @@
},
{
"name": "nette/utils",
- "version": "v4.0.7",
+ "version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
- "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2"
+ "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2",
- "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2",
+ "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede",
+ "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede",
"shasum": ""
},
"require": {
- "php": "8.0 - 8.4"
+ "php": "8.0 - 8.5"
},
"conflict": {
"nette/finder": "<3",
"nette/schema": "<1.2.2"
},
"require-dev": {
- "jetbrains/phpstorm-attributes": "dev-master",
+ "jetbrains/phpstorm-attributes": "^1.2",
"nette/tester": "^2.5",
- "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.9"
},
"suggest": {
@@ -5208,6 +5204,9 @@
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -5248,9 +5247,9 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
- "source": "https://github.com/nette/utils/tree/v4.0.7"
+ "source": "https://github.com/nette/utils/tree/v4.0.8"
},
- "time": "2025-06-03T04:55:08+00:00"
+ "time": "2025-08-06T21:43:34+00:00"
},
{
"name": "nikic/php-parser",
@@ -5465,16 +5464,16 @@
},
{
"name": "open-telemetry/api",
- "version": "1.3.0",
+ "version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/api.git",
- "reference": "4e3bb38e069876fb73c2ce85c89583bf2b28cd86"
+ "reference": "7692075f486c14d8cfd37fba98a08a5667f089e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/api/zipball/4e3bb38e069876fb73c2ce85c89583bf2b28cd86",
- "reference": "4e3bb38e069876fb73c2ce85c89583bf2b28cd86",
+ "url": "https://api.github.com/repos/opentelemetry-php/api/zipball/7692075f486c14d8cfd37fba98a08a5667f089e5",
+ "reference": "7692075f486c14d8cfd37fba98a08a5667f089e5",
"shasum": ""
},
"require": {
@@ -5494,7 +5493,7 @@
]
},
"branch-alias": {
- "dev-main": "1.1.x-dev"
+ "dev-main": "1.4.x-dev"
}
},
"autoload": {
@@ -5531,20 +5530,20 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-05-07T12:32:21+00:00"
+ "time": "2025-08-07T23:07:38+00:00"
},
{
"name": "open-telemetry/context",
- "version": "1.2.1",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/context.git",
- "reference": "1eb2b837ee9362db064a6b65d5ecce15a9f9f020"
+ "reference": "438f71812242db3f196fb4c717c6f92cbc819be6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/1eb2b837ee9362db064a6b65d5ecce15a9f9f020",
- "reference": "1eb2b837ee9362db064a6b65d5ecce15a9f9f020",
+ "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/438f71812242db3f196fb4c717c6f92cbc819be6",
+ "reference": "438f71812242db3f196fb4c717c6f92cbc819be6",
"shasum": ""
},
"require": {
@@ -5590,20 +5589,20 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-05-07T23:36:50+00:00"
+ "time": "2025-08-13T01:12:00+00:00"
},
{
"name": "open-telemetry/exporter-otlp",
- "version": "1.3.1",
+ "version": "1.3.2",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/exporter-otlp.git",
- "reference": "8b3ca1f86d01429c73b407bf1a2075d9c187001e"
+ "reference": "196f3a1dbce3b2c0f8110d164232c11ac00ddbb2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/8b3ca1f86d01429c73b407bf1a2075d9c187001e",
- "reference": "8b3ca1f86d01429c73b407bf1a2075d9c187001e",
+ "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/196f3a1dbce3b2c0f8110d164232c11ac00ddbb2",
+ "reference": "196f3a1dbce3b2c0f8110d164232c11ac00ddbb2",
"shasum": ""
},
"require": {
@@ -5654,7 +5653,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-05-21T12:02:20+00:00"
+ "time": "2025-06-16T00:24:51+00:00"
},
{
"name": "open-telemetry/gen-otlp-protobuf",
@@ -5721,22 +5720,22 @@
},
{
"name": "open-telemetry/sdk",
- "version": "1.5.0",
+ "version": "1.7.1",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sdk.git",
- "reference": "cd0d7367599717fc29e04eb8838ec061e6c2c657"
+ "reference": "52690d4b37ae4f091af773eef3c238ed2bc0aa06"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/cd0d7367599717fc29e04eb8838ec061e6c2c657",
- "reference": "cd0d7367599717fc29e04eb8838ec061e6c2c657",
+ "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/52690d4b37ae4f091af773eef3c238ed2bc0aa06",
+ "reference": "52690d4b37ae4f091af773eef3c238ed2bc0aa06",
"shasum": ""
},
"require": {
"ext-json": "*",
"nyholm/psr7-server": "^1.1",
- "open-telemetry/api": "~1.0 || ~1.1",
+ "open-telemetry/api": "^1.4",
"open-telemetry/context": "^1.0",
"open-telemetry/sem-conv": "^1.0",
"php": "^8.1",
@@ -5749,7 +5748,7 @@
"ramsey/uuid": "^3.0 || ^4.0",
"symfony/polyfill-mbstring": "^1.23",
"symfony/polyfill-php82": "^1.26",
- "tbachert/spi": "^1.0.1"
+ "tbachert/spi": "^1.0.5"
},
"suggest": {
"ext-gmp": "To support unlimited number of synchronous metric readers",
@@ -5759,6 +5758,13 @@
"type": "library",
"extra": {
"spi": {
+ "OpenTelemetry\\API\\Configuration\\ConfigEnv\\EnvComponentLoader": [
+ "OpenTelemetry\\API\\Instrumentation\\Configuration\\General\\ConfigEnv\\EnvComponentLoaderHttpConfig",
+ "OpenTelemetry\\API\\Instrumentation\\Configuration\\General\\ConfigEnv\\EnvComponentLoaderPeerConfig"
+ ],
+ "OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\ResolverInterface": [
+ "OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\SdkConfigurationResolver"
+ ],
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\HookManagerInterface": [
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\ExtensionHookManager"
]
@@ -5807,20 +5813,20 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-05-22T02:33:34+00:00"
+ "time": "2025-09-05T07:17:06+00:00"
},
{
"name": "open-telemetry/sem-conv",
- "version": "1.32.0",
+ "version": "1.37.0",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sem-conv.git",
- "reference": "16585cc0dbc3032a318e274043454679430d2ebf"
+ "reference": "8da7ec497c881e39afa6657d72586e27efbd29a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/16585cc0dbc3032a318e274043454679430d2ebf",
- "reference": "16585cc0dbc3032a318e274043454679430d2ebf",
+ "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/8da7ec497c881e39afa6657d72586e27efbd29a1",
+ "reference": "8da7ec497c881e39afa6657d72586e27efbd29a1",
"shasum": ""
},
"require": {
@@ -5864,7 +5870,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-05-05T03:58:53+00:00"
+ "time": "2025-09-03T12:08:10+00:00"
},
{
"name": "paragonie/constant_time_encoding",
@@ -6222,16 +6228,16 @@
},
{
"name": "phpoption/phpoption",
- "version": "1.9.3",
+ "version": "1.9.4",
"source": {
"type": "git",
"url": "https://github.com/schmittjoh/php-option.git",
- "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54"
+ "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54",
- "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54",
+ "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d",
+ "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d",
"shasum": ""
},
"require": {
@@ -6239,7 +6245,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
- "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
+ "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34"
},
"type": "library",
"extra": {
@@ -6281,7 +6287,7 @@
],
"support": {
"issues": "https://github.com/schmittjoh/php-option/issues",
- "source": "https://github.com/schmittjoh/php-option/tree/1.9.3"
+ "source": "https://github.com/schmittjoh/php-option/tree/1.9.4"
},
"funding": [
{
@@ -6293,7 +6299,7 @@
"type": "tidelift"
}
],
- "time": "2024-07-20T21:41:07+00:00"
+ "time": "2025-08-21T11:53:16+00:00"
},
{
"name": "phpseclib/phpseclib",
@@ -7194,21 +7200,20 @@
},
{
"name": "ramsey/uuid",
- "version": "4.8.1",
+ "version": "4.9.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
+ "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
- "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440",
+ "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440",
"shasum": ""
},
"require": {
- "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
- "ext-json": "*",
+ "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
},
@@ -7267,9 +7272,9 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.8.1"
+ "source": "https://github.com/ramsey/uuid/tree/4.9.1"
},
- "time": "2025-06-01T06:28:46+00:00"
+ "time": "2025-09-04T20:59:21+00:00"
},
{
"name": "s-ichikawa/laravel-sendgrid-driver",
@@ -7608,16 +7613,16 @@
},
{
"name": "spatie/laravel-package-tools",
- "version": "1.92.4",
+ "version": "1.92.7",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-package-tools.git",
- "reference": "d20b1969f836d210459b78683d85c9cd5c5f508c"
+ "reference": "f09a799850b1ed765103a4f0b4355006360c49a5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/d20b1969f836d210459b78683d85c9cd5c5f508c",
- "reference": "d20b1969f836d210459b78683d85c9cd5c5f508c",
+ "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/f09a799850b1ed765103a4f0b4355006360c49a5",
+ "reference": "f09a799850b1ed765103a4f0b4355006360c49a5",
"shasum": ""
},
"require": {
@@ -7657,7 +7662,7 @@
],
"support": {
"issues": "https://github.com/spatie/laravel-package-tools/issues",
- "source": "https://github.com/spatie/laravel-package-tools/tree/1.92.4"
+ "source": "https://github.com/spatie/laravel-package-tools/tree/1.92.7"
},
"funding": [
{
@@ -7665,7 +7670,7 @@
"type": "github"
}
],
- "time": "2025-04-11T15:27:14+00:00"
+ "time": "2025-07-17T15:46:43+00:00"
},
{
"name": "stripe/stripe-php",
@@ -8038,16 +8043,16 @@
},
{
"name": "symfony/console",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44"
+ "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44",
- "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44",
+ "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
+ "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
"shasum": ""
},
"require": {
@@ -8112,7 +8117,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.0"
+ "source": "https://github.com/symfony/console/tree/v7.3.3"
},
"funding": [
{
@@ -8123,12 +8128,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-05-24T10:34:04+00:00"
+ "time": "2025-08-25T06:35:40+00:00"
},
{
"name": "symfony/css-selector",
@@ -8264,16 +8273,16 @@
},
{
"name": "symfony/error-handler",
- "version": "v7.3.0",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
- "reference": "cf68d225bc43629de4ff54778029aee6dc191b83"
+ "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/error-handler/zipball/cf68d225bc43629de4ff54778029aee6dc191b83",
- "reference": "cf68d225bc43629de4ff54778029aee6dc191b83",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/0b31a944fcd8759ae294da4d2808cbc53aebd0c3",
+ "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3",
"shasum": ""
},
"require": {
@@ -8321,7 +8330,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/error-handler/tree/v7.3.0"
+ "source": "https://github.com/symfony/error-handler/tree/v7.3.2"
},
"funding": [
{
@@ -8332,25 +8341,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-05-29T07:19:49+00:00"
+ "time": "2025-07-07T08:17:57+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "497f73ac996a598c92409b44ac43b6690c4f666d"
+ "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d",
- "reference": "497f73ac996a598c92409b44ac43b6690c4f666d",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
+ "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
"shasum": ""
},
"require": {
@@ -8401,7 +8414,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0"
+ "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
},
"funding": [
{
@@ -8412,12 +8425,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-22T09:11:45+00:00"
+ "time": "2025-08-13T11:49:31+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@@ -8497,16 +8514,16 @@
},
{
"name": "symfony/finder",
- "version": "v7.3.0",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d"
+ "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d",
- "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
"shasum": ""
},
"require": {
@@ -8541,7 +8558,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.3.0"
+ "source": "https://github.com/symfony/finder/tree/v7.3.2"
},
"funding": [
{
@@ -8552,25 +8569,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-12-30T19:00:26+00:00"
+ "time": "2025-07-15T13:41:35+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "4236baf01609667d53b20371486228231eb135fd"
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/4236baf01609667d53b20371486228231eb135fd",
- "reference": "4236baf01609667d53b20371486228231eb135fd",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00",
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00",
"shasum": ""
},
"require": {
@@ -8620,7 +8641,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v7.3.0"
+ "source": "https://github.com/symfony/http-foundation/tree/v7.3.3"
},
"funding": [
{
@@ -8631,25 +8652,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-05-12T14:48:23+00:00"
+ "time": "2025-08-20T08:04:18+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f"
+ "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ac7b8e163e8c83dce3abcc055a502d4486051a9f",
- "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b",
+ "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b",
"shasum": ""
},
"require": {
@@ -8734,7 +8759,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-kernel/tree/v7.3.0"
+ "source": "https://github.com/symfony/http-kernel/tree/v7.3.3"
},
"funding": [
{
@@ -8745,25 +8770,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-05-29T07:47:32+00:00"
+ "time": "2025-08-29T08:23:45+00:00"
},
{
"name": "symfony/mailer",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
- "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c"
+ "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mailer/zipball/0f375bbbde96ae8c78e4aa3e63aabd486e33364c",
- "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c",
+ "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575",
+ "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575",
"shasum": ""
},
"require": {
@@ -8814,7 +8843,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/mailer/tree/v7.3.0"
+ "source": "https://github.com/symfony/mailer/tree/v7.3.3"
},
"funding": [
{
@@ -8825,25 +8854,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-04T09:51:09+00:00"
+ "time": "2025-08-13T11:49:31+00:00"
},
{
"name": "symfony/mime",
- "version": "v7.3.0",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9"
+ "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9",
- "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1",
+ "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1",
"shasum": ""
},
"require": {
@@ -8898,7 +8931,7 @@
"mime-type"
],
"support": {
- "source": "https://github.com/symfony/mime/tree/v7.3.0"
+ "source": "https://github.com/symfony/mime/tree/v7.3.2"
},
"funding": [
{
@@ -8909,16 +8942,20 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-02-19T08:51:26+00:00"
+ "time": "2025-07-15T13:41:35+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
@@ -8977,7 +9014,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
@@ -8988,6 +9025,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -8997,16 +9038,16 @@
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
"shasum": ""
},
"require": {
@@ -9055,7 +9096,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
},
"funding": [
{
@@ -9066,16 +9107,20 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2025-06-27T09:58:17+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
@@ -9138,7 +9183,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0"
},
"funding": [
{
@@ -9149,6 +9194,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -9158,7 +9207,7 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -9219,7 +9268,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
},
"funding": [
{
@@ -9230,6 +9279,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -9239,7 +9292,7 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
@@ -9300,7 +9353,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
@@ -9311,6 +9364,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -9320,7 +9377,7 @@
},
{
"name": "symfony/polyfill-php80",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
@@ -9380,7 +9437,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
},
"funding": [
{
@@ -9391,6 +9448,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -9400,7 +9461,7 @@
},
{
"name": "symfony/polyfill-php82",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php82.git",
@@ -9456,7 +9517,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php82/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php82/tree/v1.33.0"
},
"funding": [
{
@@ -9467,6 +9528,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -9476,16 +9541,16 @@
},
{
"name": "symfony/polyfill-php83",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php83.git",
- "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491"
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491",
- "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491",
+ "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
"shasum": ""
},
"require": {
@@ -9532,7 +9597,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0"
},
"funding": [
{
@@ -9543,25 +9608,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2025-07-08T02:45:35+00:00"
},
{
"name": "symfony/polyfill-php84",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php84.git",
- "reference": "000df7860439609837bbe28670b0be15783b7fbf"
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/000df7860439609837bbe28670b0be15783b7fbf",
- "reference": "000df7860439609837bbe28670b0be15783b7fbf",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
"shasum": ""
},
"require": {
@@ -9608,7 +9677,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php84/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0"
},
"funding": [
{
@@ -9619,16 +9688,20 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-02-20T12:04:08+00:00"
+ "time": "2025-06-24T13:30:11+00:00"
},
{
"name": "symfony/polyfill-uuid",
- "version": "v1.32.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-uuid.git",
@@ -9687,7 +9760,7 @@
"uuid"
],
"support": {
- "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0"
},
"funding": [
{
@@ -9698,6 +9771,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -9707,16 +9784,16 @@
},
{
"name": "symfony/process",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af"
+ "reference": "32241012d521e2e8a9d713adb0812bb773b907f1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
- "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
+ "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1",
+ "reference": "32241012d521e2e8a9d713adb0812bb773b907f1",
"shasum": ""
},
"require": {
@@ -9748,7 +9825,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.3.0"
+ "source": "https://github.com/symfony/process/tree/v7.3.3"
},
"funding": [
{
@@ -9759,25 +9836,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-17T09:11:12+00:00"
+ "time": "2025-08-18T09:42:54+00:00"
},
{
"name": "symfony/routing",
- "version": "v7.3.0",
+ "version": "v7.3.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "8e213820c5fea844ecea29203d2a308019007c15"
+ "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15",
- "reference": "8e213820c5fea844ecea29203d2a308019007c15",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/7614b8ca5fa89b9cd233e21b627bfc5774f586e4",
+ "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4",
"shasum": ""
},
"require": {
@@ -9829,7 +9910,7 @@
"url"
],
"support": {
- "source": "https://github.com/symfony/routing/tree/v7.3.0"
+ "source": "https://github.com/symfony/routing/tree/v7.3.2"
},
"funding": [
{
@@ -9840,31 +9921,36 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-05-24T20:43:28+00:00"
+ "time": "2025-07-15T11:36:08+00:00"
},
{
"name": "symfony/serializer",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/serializer.git",
- "reference": "2d86f81b1c506d7e1578789f93280dab4b8411bb"
+ "reference": "5608b04d8daaf29432d76ecc618b0fac169c2dfb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/serializer/zipball/2d86f81b1c506d7e1578789f93280dab4b8411bb",
- "reference": "2d86f81b1c506d7e1578789f93280dab4b8411bb",
+ "url": "https://api.github.com/repos/symfony/serializer/zipball/5608b04d8daaf29432d76ecc618b0fac169c2dfb",
+ "reference": "5608b04d8daaf29432d76ecc618b0fac169c2dfb",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
- "symfony/polyfill-ctype": "~1.8"
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-php84": "^1.30"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.2.2",
@@ -9894,7 +9980,7 @@
"symfony/property-access": "^6.4|^7.0",
"symfony/property-info": "^6.4|^7.0",
"symfony/translation-contracts": "^2.5|^3",
- "symfony/type-info": "^7.1",
+ "symfony/type-info": "^7.1.8",
"symfony/uid": "^6.4|^7.0",
"symfony/validator": "^6.4|^7.0",
"symfony/var-dumper": "^6.4|^7.0",
@@ -9927,7 +10013,7 @@
"description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/serializer/tree/v7.3.0"
+ "source": "https://github.com/symfony/serializer/tree/v7.3.3"
},
"funding": [
{
@@ -9938,12 +10024,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-05-12T14:48:23+00:00"
+ "time": "2025-08-27T11:34:33+00:00"
},
{
"name": "symfony/service-contracts",
@@ -10092,16 +10182,16 @@
},
{
"name": "symfony/string",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125"
+ "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125",
- "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125",
+ "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
+ "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"shasum": ""
},
"require": {
@@ -10159,7 +10249,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.3.0"
+ "source": "https://github.com/symfony/string/tree/v7.3.3"
},
"funding": [
{
@@ -10170,25 +10260,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-20T20:19:01+00:00"
+ "time": "2025-08-25T06:35:40+00:00"
},
{
"name": "symfony/translation",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "4aba29076a29a3aa667e09b791e5f868973a8667"
+ "reference": "e0837b4cbcef63c754d89a4806575cada743a38d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/4aba29076a29a3aa667e09b791e5f868973a8667",
- "reference": "4aba29076a29a3aa667e09b791e5f868973a8667",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d",
+ "reference": "e0837b4cbcef63c754d89a4806575cada743a38d",
"shasum": ""
},
"require": {
@@ -10255,7 +10349,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/translation/tree/v7.3.0"
+ "source": "https://github.com/symfony/translation/tree/v7.3.3"
},
"funding": [
{
@@ -10266,12 +10360,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-05-29T07:19:49+00:00"
+ "time": "2025-08-01T21:02:37+00:00"
},
{
"name": "symfony/translation-contracts",
@@ -10353,16 +10451,16 @@
},
{
"name": "symfony/uid",
- "version": "v7.3.0",
+ "version": "v7.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/uid.git",
- "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3"
+ "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/uid/zipball/7beeb2b885cd584cd01e126c5777206ae4c3c6a3",
- "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3",
+ "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb",
+ "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb",
"shasum": ""
},
"require": {
@@ -10407,7 +10505,7 @@
"uuid"
],
"support": {
- "source": "https://github.com/symfony/uid/tree/v7.3.0"
+ "source": "https://github.com/symfony/uid/tree/v7.3.1"
},
"funding": [
{
@@ -10423,20 +10521,20 @@
"type": "tidelift"
}
],
- "time": "2025-05-24T14:28:13+00:00"
+ "time": "2025-06-27T19:55:54+00:00"
},
{
"name": "symfony/var-dumper",
- "version": "v7.3.0",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e"
+ "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/548f6760c54197b1084e1e5c71f6d9d523f2f78e",
- "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f",
+ "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f",
"shasum": ""
},
"require": {
@@ -10448,7 +10546,6 @@
"symfony/console": "<6.4"
},
"require-dev": {
- "ext-iconv": "*",
"symfony/console": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
@@ -10491,7 +10588,7 @@
"dump"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v7.3.0"
+ "source": "https://github.com/symfony/var-dumper/tree/v7.3.3"
},
"funding": [
{
@@ -10502,12 +10599,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-27T18:39:23+00:00"
+ "time": "2025-08-13T11:49:31+00:00"
},
{
"name": "symfony/var-exporter",
@@ -10660,16 +10761,16 @@
},
{
"name": "tbachert/spi",
- "version": "v1.0.3",
+ "version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/Nevay/spi.git",
- "reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a"
+ "reference": "e7078767866d0a9e0f91d3f9d42a832df5e39002"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Nevay/spi/zipball/506a79c98e1a51522e76ee921ccb6c62d52faf3a",
- "reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a",
+ "url": "https://api.github.com/repos/Nevay/spi/zipball/e7078767866d0a9e0f91d3f9d42a832df5e39002",
+ "reference": "e7078767866d0a9e0f91d3f9d42a832df5e39002",
"shasum": ""
},
"require": {
@@ -10687,7 +10788,7 @@
"extra": {
"class": "Nevay\\SPI\\Composer\\Plugin",
"branch-alias": {
- "dev-main": "0.2.x-dev"
+ "dev-main": "1.0.x-dev"
},
"plugin-optional": true
},
@@ -10706,9 +10807,9 @@
],
"support": {
"issues": "https://github.com/Nevay/spi/issues",
- "source": "https://github.com/Nevay/spi/tree/v1.0.3"
+ "source": "https://github.com/Nevay/spi/tree/v1.0.5"
},
- "time": "2025-04-02T19:38:14+00:00"
+ "time": "2025-06-29T15:42:06+00:00"
},
{
"name": "tecnickcom/tcpdf",
@@ -13969,7 +14070,10 @@
"ext-json": "*",
"ext-openssl": "*",
"ext-pdo": "*",
- "ext-zlib": "*"
+ "ext-zlib": "*",
+ "ext-igbinary": "*",
+ "ext-redis": "*",
+ "ext-apcu": "*"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
diff --git a/config/opentelemetry.php b/config/opentelemetry.php
index 81de53dbb..d79d40af2 100644
--- a/config/opentelemetry.php
+++ b/config/opentelemetry.php
@@ -16,6 +16,18 @@
*/
'propagators' => env(Variables::OTEL_PROPAGATORS, 'tracecontext'),
+ /**
+ * OpenTelemetry Meter configuration
+ */
+ 'metrics' => [
+ /**
+ * Metrics exporter
+ * This should be the key of one of the exporters defined in the exporters section
+ * Supported drivers: "otlp", "console", "null"
+ */
+ 'exporter' => env(Variables::OTEL_METRICS_EXPORTER, 'otlp'),
+ ],
+
/**
* OpenTelemetry Traces configuration
*/
@@ -78,7 +90,7 @@
/**
* OpenTelemetry exporters
*
- * Here you can configure exports used by traces and logs.
+ * Here you can configure exports used by metrics, traces and logs.
* If you want to use the same protocol with different endpoints,
* you can copy the exporter with a different and change the endpoint
*
@@ -119,6 +131,7 @@
Instrumentation\HttpClientInstrumentation::class => [
'enabled' => env('OTEL_INSTRUMENTATION_HTTP_CLIENT', true),
+ 'manual' => false, // When set to true, you need to call `withTrace()` on the request to enable tracing
'allowed_headers' => [],
'sensitive_headers' => [],
],
@@ -139,5 +152,10 @@
Instrumentation\ViewInstrumentation::class => env('OTEL_INSTRUMENTATION_VIEW', true),
Instrumentation\LivewireInstrumentation::class => env('OTEL_INSTRUMENTATION_LIVEWIRE', true),
- ],
+
+ Instrumentation\ConsoleInstrumentation::class => [
+ 'enabled' => env('OTEL_INSTRUMENTATION_CONSOLE', true),
+ 'excluded' => [],
+ ],
+ ]
];
diff --git a/docker-compose.yml b/docker-compose.yml
index 68218bc6d..bc1e5b55f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -109,9 +109,49 @@ services:
env_file: ./.env
depends_on:
- app
+ otel-collector:
+ image: otel/opentelemetry-collector-contrib
+ volumes:
+ - ./docker-compose/opentelemetry/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
+ - ./docker-compose/opentelemetry/otel-traces.json:/tmp/otel-traces.json
+ ports:
+ - 1888:1888 # pprof extension
+ - 8888:8888 # Prometheus metrics exposed by the Collector
+ - 8889:8889 # Prometheus exporter metrics
+ - 13133:13133 # health_check extension
+ - 4317:4317 # OTLP gRPC receiver
+ - 4318:4318 # OTLP http receiver
+ - 55679:55679 # zpages extension
+ networks:
+ - summit-api-local-net
+ depends_on:
+ - elasticsearch
+
+ elasticsearch:
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
+ container_name: elasticsearch
+ environment:
+ - discovery.type=single-node
+ - xpack.security.enabled=false
+ - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
+ - cluster.name=summit-api-cluster
+ - node.name=summit-api-node
+ ports:
+ - "9200:9200"
+ - "9300:9300"
+ volumes:
+ - elasticsearch_data:/usr/share/elasticsearch/data
+ networks:
+ - summit-api-local-net
+ healthcheck:
+ test: [ "CMD-SHELL", "curl -f http://localhost:9200/_cluster/health || exit 1" ]
+ interval: 30s
+ timeout: 10s
+ retries: 5
networks:
summit-api-local-net:
driver: bridge
volumes:
mysql_summit_api_model:
- mysql_summit_api_config:
\ No newline at end of file
+ mysql_summit_api_config:
+ elasticsearch_data:
diff --git a/docker-compose/opentelemetry/.gitignore b/docker-compose/opentelemetry/.gitignore
new file mode 100644
index 000000000..e449bb5cb
--- /dev/null
+++ b/docker-compose/opentelemetry/.gitignore
@@ -0,0 +1,39 @@
+/vendor
+/node_modules
+composer.phar
+.DS_Storeapp/storage
+.idea/*
+app/config/dev/*
+app/config/testing/*
+app/config/local/*
+app/config/production/*
+app/config/staging/*
+app/config/packages/greggilbert/recaptcha/dev/*
+app/config/packages/greggilbert/recaptcha/local/*
+app/config/packages/greggilbert/recaptcha/production/*
+app/config/packages/greggilbert/recaptcha/staging/*
+/bootstrap/compiled.php
+/bootstrap/environment.php
+.tox
+AUTHORS
+ChangeLog
+doc/build
+*.egg
+*.egg-info
+.env.testing
+.env
+storage/*
+*.log
+routes.txt
+/storage/logs/
+/ss.sql
+phpunit.xml
+.phpunit.result.cache
+.phpunit.cache/
+docker-compose/mysql/config/*.sql
+docker-compose/mysql/model/*.sql
+package.xml
+.env.dev
+rector.php
+public/apc.php
+docker-compose/opentelemetry/otel-traces.json
\ No newline at end of file
diff --git a/docker-compose/opentelemetry/otel-collector-config.yaml b/docker-compose/opentelemetry/otel-collector-config.yaml
new file mode 100755
index 000000000..74d050717
--- /dev/null
+++ b/docker-compose/opentelemetry/otel-collector-config.yaml
@@ -0,0 +1,140 @@
+# OpenTelemetry Collector Configuration
+# This configuration sets up a basic collector pipeline for traces, metrics, and logs
+
+receivers:
+ # OTLP receiver for gRPC and HTTP protocols
+ otlp:
+ protocols:
+ grpc:
+ endpoint: 0.0.0.0:4317
+ http:
+ endpoint: 0.0.0.0:4318
+ cors:
+ allowed_origins:
+ - "http://localhost"
+ - "http://localhost:*"
+ - "https://localhost"
+ - "https://localhost:*"
+ allowed_headers:
+ - "*"
+
+ # Prometheus metrics receiver for scraping metrics
+ prometheus:
+ config:
+ scrape_configs:
+ - job_name: 'otel-collector'
+ scrape_interval: 10s
+ static_configs:
+ - targets: ['0.0.0.0:8888']
+
+processors:
+ # Batch processor to batch telemetry data before export
+ batch:
+ send_batch_size: 1024
+ timeout: 1s
+ send_batch_max_size: 2048
+
+ # Memory limiter to prevent out-of-memory issues
+ memory_limiter:
+ limit_mib: 400
+ spike_limit_mib: 100
+ check_interval: 1s
+
+ # Resource processor to add/modify resource attributes
+ resource:
+ attributes:
+ - key: service.name
+ value: summit-api
+ action: upsert
+ - key: service.version
+ value: 1.0.0
+ action: upsert
+ - key: deployment.environment
+ value: development
+ action: upsert
+
+ # Attributes processor to modify span/metric attributes
+ attributes:
+ actions:
+ - key: environment
+ value: development
+ action: upsert
+
+exporters:
+ # Debug exporter for debugging - outputs to stdout
+ debug:
+ verbosity: normal
+ sampling_initial: 5
+ sampling_thereafter: 200
+
+ # Prometheus exporter for metrics
+ prometheus:
+ endpoint: "0.0.0.0:8889"
+ namespace: summit_api
+ const_labels:
+ environment: development
+
+ # File exporter for traces (useful for debugging)
+ file:
+ path: /tmp/otel-traces.json
+
+ # Elasticsearch exporter for storing traces, metrics, and logs
+ elasticsearch:
+ endpoints: [http://elasticsearch:9200]
+ # Authentication (uncomment if needed)
+ # auth:
+ # authenticator: basicauth/elastic
+ logs_index: otel-logs
+ traces_index: otel-traces
+ metrics_index: otel-metrics
+ # Mapping settings for better performance
+ mapping:
+ mode: ecs # Use Elastic Common Schema
+
+extensions:
+ # Health check extension
+ health_check:
+ endpoint: 0.0.0.0:13133
+
+ # pprof extension for performance profiling
+ pprof:
+ endpoint: 0.0.0.0:1888
+
+ # ZPages extension for debugging
+ zpages:
+ endpoint: 0.0.0.0:55679
+
+ # Basic auth extension for Elasticsearch (uncomment if needed)
+ # basicauth/elastic:
+ # client_auth:
+ # username: elastic
+ # password: changeme
+
+service:
+ extensions: [health_check, pprof, zpages]
+
+ pipelines:
+ # Traces pipeline
+ traces:
+ receivers: [otlp]
+ processors: [memory_limiter, resource, attributes, batch]
+ exporters: [debug, file, elasticsearch]
+
+ # Metrics pipeline
+ metrics:
+ receivers: [otlp]
+ processors: [memory_limiter, resource, batch]
+ exporters: [debug]
+
+ # Logs pipeline
+ logs:
+ receivers: [otlp]
+ processors: [memory_limiter, resource, attributes, batch]
+ exporters: [debug, file]
+
+ # Telemetry configuration for the collector itself
+ telemetry:
+ logs:
+ level: "info"
+ metrics:
+ level: basic
diff --git a/docker-compose/opentelemetry/otel-traces.json b/docker-compose/opentelemetry/otel-traces.json
new file mode 100644
index 000000000..e69de29bb
diff --git a/phpunit.xml b/phpunit.xml
index 51f3bf8a1..a2b78a0b5 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -3,6 +3,12 @@
./tests/
+ ./tests/OpenTelemetry/
+ ./tests/TestCase.php
+
+
+ ./tests/OpenTelemetry/
+ ./tests/OpenTelemetry/ExampleTest.php
diff --git a/readme.md b/readme.md
index 9eddb4338..b31bc3a36 100644
--- a/readme.md
+++ b/readme.md
@@ -79,4 +79,22 @@ php artisan queue:work
php artisan audit:purge-log _SUMMIT_ID_ _DATE_BACKWARD_FROM_
- SUMMIT_ID: Summit id to clear audit log from
-- DATE_BACKWARD_FROM: Maximum date to delete starting from the beginning
\ No newline at end of file
+- DATE_BACKWARD_FROM: Maximum date to delete starting from the beginning
+
+## OpenTelemetry Observability
+
+This application includes OpenTelemetry instrumentation for distributed tracing and monitoring.
+
+### Quick Setup
+```bash
+# Enable in .env
+OTEL_SERVICE_ENABLED=true
+OTEL_SERVICE_NAME=summit-api
+OTEL_INSTRUMENTATION_GUZZLE=true
+
+# Start collector and Elasticsearch
+docker compose up -d otel-collector elasticsearch
+
+# View traces
+curl http://localhost:55679/debug/tracez
+```
\ No newline at end of file
diff --git a/tests/OpenTelemetry/.gitkeep b/tests/OpenTelemetry/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/OpenTelemetry/ExampleTest.php b/tests/OpenTelemetry/ExampleTest.php
new file mode 100644
index 000000000..6491fdc48
--- /dev/null
+++ b/tests/OpenTelemetry/ExampleTest.php
@@ -0,0 +1,17 @@
+assertTrue(true);
+ }
+}
diff --git a/tests/OpenTelemetry/GuzzleTracingTest.php b/tests/OpenTelemetry/GuzzleTracingTest.php
new file mode 100644
index 000000000..295236c7a
--- /dev/null
+++ b/tests/OpenTelemetry/GuzzleTracingTest.php
@@ -0,0 +1,374 @@
+capturedRequests = [];
+ }
+
+ protected function tearDown(): void
+ {
+ Mockery::close();
+ parent::tearDown();
+ }
+
+ /**
+ * Test that verifies the GuzzleTrace middleware works correctly
+ * Simulates real behavior without depending on global OpenTelemetry configuration
+ *
+ * @return void
+ */
+ public function testGuzzleTraceMiddlewareAddsHeaders(): void
+ {
+ // Configure baggage with cf-ray simulating the input middleware
+ $cfRayValue = '8a2e036cae2822-SJC';
+ $userAgent = 'TestUserAgent/1.0';
+
+ // Create an active span to have tracing context
+ $tracer = $this->app->make(TracerInterface::class);
+ $span = $tracer->spanBuilder('test-http-request')->startSpan();
+ $spanScope = $span->activate();
+
+ try {
+ // Configure baggage in the active span context
+ $baggage = Baggage::getCurrent()
+ ->toBuilder()
+ ->set('cf-ray', $cfRayValue)
+ ->set('user_agent', $userAgent)
+ ->build();
+
+ $baggageScope = $baggage->activate();
+
+ try {
+ // Create a mock handler to capture requests
+ $mockHandler = new MockHandler([
+ new Response(200, [], '{"success": true}')
+ ]);
+
+ // Middleware to capture sent headers
+ $historyMiddleware = Middleware::history($this->capturedRequests);
+
+ // Create handler stack with tracing middleware
+ $handlerStack = HandlerStack::create($mockHandler);
+
+ // IMPORTANT: First add tracing middleware, THEN history
+ // This ensures history captures the request after headers are added
+ $handlerStack->push(GuzzleTraceMiddleware::make());
+
+ // History middleware goes AFTER to capture the final request with headers
+ $handlerStack->push($historyMiddleware); // Create Guzzle client
+ $client = new Client(['handler' => $handlerStack]);
+
+ // Make the request
+ $response = $client->post('http://example.com/api/test', [
+ 'json' => ['test' => 'data'],
+ 'headers' => [
+ 'X-Custom-Header' => 'custom-value'
+ ]
+ ]);
+
+ // Verify the response was successful
+ $this->assertEquals(200, $response->getStatusCode());
+
+ // Verify exactly one request was captured
+ $this->assertCount(1, $this->capturedRequests);
+
+ $transaction = $this->capturedRequests[0];
+ $request = $transaction['request'];
+ $headers = [];
+
+ // Convert headers to associative array for easy verification
+ foreach ($request->getHeaders() as $name => $values) {
+ $headers[strtolower($name)] = $values;
+ }
+
+ // Verify tracing headers were added
+ $this->assertTrue(isset($headers['traceparent']), "Request must have traceparent header");
+ $this->assertTrue(isset($headers['baggage']), "Request must have baggage header");
+
+ // If there's baggage, verify it contains cf-ray
+ if (isset($headers['baggage'])) {
+ $baggageHeader = $headers['baggage'][0];
+ $this->assertStringContainsString(
+ "cf-ray=$cfRayValue",
+ $baggageHeader,
+ 'Baggage header must contain cf-ray value'
+ );
+ }
+
+ // Verify custom headers are also present
+ $this->assertArrayHasKey('x-custom-header', $headers);
+ $this->assertEquals('custom-value', $headers['x-custom-header'][0]);
+
+ } finally {
+ $baggageScope->detach();
+ }
+ } finally {
+ $span->end();
+ $spanScope->detach();
+ }
+ }
+
+ /**
+ * Test that verifies behavior when no baggage is configured
+ *
+ * @return void
+ */
+ public function testGuzzleWithoutBaggage(): void
+ {
+ // Create an active span but WITHOUT configured baggage
+ $tracer = $this->app->make(TracerInterface::class);
+ $span = $tracer->spanBuilder('test-without-baggage')->startSpan();
+ $spanScope = $span->activate();
+
+ try {
+ // Create a mock handler
+ $mockHandler = new MockHandler([
+ new Response(200, [], '{"success": true}')
+ ]);
+
+ // Middleware to capture sent headers
+ $historyMiddleware = Middleware::history($this->capturedRequests);
+
+ // Create handler stack
+ $handlerStack = HandlerStack::create($mockHandler);
+
+ // Important order: trace middleware first, then history
+ $handlerStack->push(GuzzleTraceMiddleware::make());
+ $handlerStack->push($historyMiddleware);
+
+ // Create Guzzle client
+ $client = new Client(['handler' => $handlerStack]);
+
+ // Make request without configured baggage
+ $response = $client->get('http://example.com/api/test');
+
+ // Verify response was successful
+ $this->assertEquals(200, $response->getStatusCode());
+
+ // Verify request was captured
+ $this->assertCount(1, $this->capturedRequests);
+
+ $transaction = $this->capturedRequests[0];
+ $request = $transaction['request'];
+ $headers = [];
+
+ foreach ($request->getHeaders() as $name => $values) {
+ $headers[strtolower($name)] = $values;
+ }
+
+ // Must have some tracing header
+ $this->assertTrue(isset($headers['traceparent']), "Request must have traceparent header");
+
+ // Should not have baggage with cf-ray if not configured
+ if (isset($headers['baggage'])) {
+ $baggageHeader = $headers['baggage'][0];
+ $this->assertStringNotContainsString('cf-ray=', $baggageHeader);
+ }
+ } finally {
+ $span->end();
+ $spanScope->detach();
+ }
+ }
+
+ /**
+ * Test that verifies behavior with different cf-ray values
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('cfRayProvider')]
+ public function testGuzzleWithDifferentCfRayValues(string $cfRayValue): void
+ {
+ // Create an active span with specific baggage for this cf-ray
+ $tracer = $this->app->make(TracerInterface::class);
+ $span = $tracer->spanBuilder('test-different-cfray')->startSpan();
+ $spanScope = $span->activate();
+
+ try {
+ // Configure baggage with specific cf-ray
+ $baggage = Baggage::getCurrent()
+ ->toBuilder()
+ ->set('cf-ray', $cfRayValue)
+ ->set('user_agent', 'test-agent')
+ ->build();
+
+ $baggageScope = $baggage->activate();
+
+ try {
+ $mockHandler = new MockHandler([
+ new Response(200, [], '{"success": true}')
+ ]);
+
+ $historyMiddleware = Middleware::history($this->capturedRequests);
+ $handlerStack = HandlerStack::create($mockHandler);
+
+ // Important order: trace middleware first, then history
+ $handlerStack->push(GuzzleTraceMiddleware::make());
+ $handlerStack->push($historyMiddleware);
+
+ $client = new Client(['handler' => $handlerStack]);
+
+ $response = $client->post('http://example.com/api/test', [
+ 'json' => ['cf_ray_test' => $cfRayValue]
+ ]);
+
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertCount(1, $this->capturedRequests);
+
+ $transaction = $this->capturedRequests[0];
+ $request = $transaction['request'];
+ $headers = [];
+
+ foreach ($request->getHeaders() as $name => $values) {
+ $headers[strtolower($name)] = $values;
+ }
+
+ // Verify tracing headers
+ $this->assertTrue(isset($headers['traceparent']), "Request must have traceparent header");
+ $this->assertTrue(isset($headers['baggage']), "Request must have baggage header");
+
+ // If there's baggage, verify it contains the correct cf-ray
+ if (isset($headers['baggage']) && !empty($cfRayValue)) {
+ $baggageHeader = $headers['baggage'][0];
+ $this->assertStringContainsString(
+ "cf-ray=$cfRayValue",
+ $baggageHeader,
+ "Baggage header must contain cf-ray value: $cfRayValue"
+ );
+ }
+ } finally {
+ $baggageScope->detach();
+ }
+ } finally {
+ $span->end();
+ $spanScope->detach();
+ }
+ }
+
+ /**
+ * Data provider for different cf-ray values
+ */
+ public static function cfRayProvider(): array
+ {
+ return [
+ 'cf-ray standard format' => ['8a2e036cae2822-SJC'],
+ 'cf-ray different datacenter' => ['7f1b025bdf1733-LAX'],
+ 'cf-ray another format' => ['9c3f047def3944-LHR'],
+ 'cf-ray with different hex' => ['ab4e158efg4055-CDG'],
+ ];
+ }
+
+ /**
+ * Test that verifies multiple requests maintain tracing context
+ */
+ public function testMultipleRequestsWithTracing(): void
+ {
+ $cfRayValue = '8a2e036cae2822-SJC';
+
+ // Create an active span with baggage for all requests
+ $tracer = $this->app->make(TracerInterface::class);
+ $span = $tracer->spanBuilder('test-multiple-requests')->startSpan();
+ $spanScope = $span->activate();
+
+ try {
+ // Configure baggage for multiple requests
+ $baggage = Baggage::getCurrent()
+ ->toBuilder()
+ ->set('cf-ray', $cfRayValue)
+ ->set('user_agent', 'test-agent')
+ ->build();
+
+ $baggageScope = $baggage->activate();
+
+ try {
+ // Configure mock for multiple responses
+ $mockHandler = new MockHandler([
+ new Response(200, [], '{"request": 1}'),
+ new Response(200, [], '{"request": 2}'),
+ new Response(200, [], '{"request": 3}')
+ ]);
+
+ $historyMiddleware = Middleware::history($this->capturedRequests);
+ $handlerStack = HandlerStack::create($mockHandler);
+
+ // Important order: trace middleware first, then history
+ $handlerStack->push(GuzzleTraceMiddleware::make());
+ $handlerStack->push($historyMiddleware);
+
+ $client = new Client(['handler' => $handlerStack]);
+
+ // Make multiple requests
+ for ($i = 1; $i <= 3; $i++) {
+ $response = $client->get("http://example.com/api/test/$i");
+ $this->assertEquals(200, $response->getStatusCode());
+ }
+
+ // Verify all requests were captured
+ $this->assertCount(3, $this->capturedRequests);
+
+ // Verify all requests have tracing headers
+ foreach ($this->capturedRequests as $index => $transaction) {
+ $request = $transaction['request'];
+ $headers = [];
+
+ foreach ($request->getHeaders() as $name => $values) {
+ $headers[strtolower($name)] = $values;
+ }
+
+ // All must have at least tracing headers
+ $this->assertTrue(isset($headers['traceparent']), "Request $index must have traceparent header");
+ $this->assertTrue(isset($headers['baggage']), "Request $index must have baggage header");
+
+ // Verify baggage contains cf-ray in all requests
+ if (isset($headers['baggage'])) {
+ $baggageHeader = $headers['baggage'][0];
+ $this->assertStringContainsString(
+ "cf-ray=$cfRayValue",
+ $baggageHeader,
+ "Request $index must have cf-ray in baggage"
+ );
+ }
+ }
+ } finally {
+ $baggageScope->detach();
+ }
+ } finally {
+ $span->end();
+ $spanScope->detach();
+ }
+ }
+
+ /**
+ * Creates a custom middleware for testing that simulates tracing middleware behavior
+ */
+ private function createCustomTraceMiddleware(string $cfRayValue, string $userAgent): callable
+ {
+ return function (callable $handler) use ($cfRayValue, $userAgent) {
+ return function ($request, array $options) use ($handler, $cfRayValue, $userAgent) {
+ // Simulate adding tracing headers
+ $request = $request->withHeader('traceparent', '00-' . str_repeat('0', 32) . '-' . str_repeat('0', 16) . '-01');
+ $request = $request->withHeader('baggage', "cf-ray=$cfRayValue,user_agent=" . urlencode($userAgent));
+
+ return $handler($request, $options);
+ };
+ };
+ }
+}
diff --git a/tests/OpenTelemetry/OpenTelemetryTestCase.php b/tests/OpenTelemetry/OpenTelemetryTestCase.php
new file mode 100644
index 000000000..bf9aff8ad
--- /dev/null
+++ b/tests/OpenTelemetry/OpenTelemetryTestCase.php
@@ -0,0 +1,86 @@
+setOpenTelemetryEnvironmentVariables();
+
+ parent::setUp();
+
+ // Register the OpenTelemetry testing ServiceProvider
+ $this->app->register(OpenTelemetryTestingServiceProvider::class);
+
+ // Enable OpenTelemetry in testing environment
+ config(['opentelemetry.enabled' => true]);
+
+ // Configure necessary instrumentations
+ config([
+ 'opentelemetry.instrumentation' => [
+ HttpClientInstrumentation::class => [
+ 'enabled' => true,
+ 'manual' => false,
+ 'allowed_headers' => [],
+ 'sensitive_headers' => [],
+ ],
+ ]
+ ]);
+ }
+
+ /**
+ * Set OpenTelemetry environment variables for testing
+ */
+ protected function setOpenTelemetryEnvironmentVariables(): void
+ {
+ putenv('OTEL_SERVICE_ENABLED=true');
+ putenv('OTEL_SERVICE_NAME=summit-api-test');
+ putenv('OTEL_PROPAGATORS=tracecontext,baggage');
+ putenv('OTEL_INSTRUMENTATION_HTTP_CLIENT=true');
+ putenv('OTEL_INSTRUMENTATION_REDIS=false');
+ putenv('OTEL_INSTRUMENTATION_QUERY=false');
+ putenv('OTEL_INSTRUMENTATION_QUEUE=false');
+ putenv('OTEL_INSTRUMENTATION_CACHE=false');
+ putenv('OTEL_INSTRUMENTATION_EVENT=false');
+ putenv('OTEL_INSTRUMENTATION_VIEW=false');
+ putenv('OTEL_INSTRUMENTATION_CONSOLE=false');
+ putenv('OTEL_TRACES_EXPORTER=none');
+ putenv('OTEL_METRICS_EXPORTER=none');
+ }
+
+ protected function tearDown(): void
+ {
+ // Clean up environment variables
+ $this->cleanupOpenTelemetryEnvironmentVariables();
+ parent::tearDown();
+ }
+
+ /**
+ * Clean up OpenTelemetry environment variables after testing
+ */
+ protected function cleanupOpenTelemetryEnvironmentVariables(): void
+ {
+ putenv('OTEL_SERVICE_ENABLED');
+ putenv('OTEL_SERVICE_NAME');
+ putenv('OTEL_PROPAGATORS');
+ putenv('OTEL_INSTRUMENTATION_HTTP_CLIENT');
+ putenv('OTEL_INSTRUMENTATION_REDIS');
+ putenv('OTEL_INSTRUMENTATION_QUERY');
+ putenv('OTEL_INSTRUMENTATION_QUEUE');
+ putenv('OTEL_INSTRUMENTATION_CACHE');
+ putenv('OTEL_INSTRUMENTATION_EVENT');
+ putenv('OTEL_INSTRUMENTATION_VIEW');
+ putenv('OTEL_INSTRUMENTATION_CONSOLE');
+ putenv('OTEL_TRACES_EXPORTER');
+ putenv('OTEL_METRICS_EXPORTER');
+ }
+}
diff --git a/tests/OpenTelemetry/README.md b/tests/OpenTelemetry/README.md
new file mode 100644
index 000000000..4706c151b
--- /dev/null
+++ b/tests/OpenTelemetry/README.md
@@ -0,0 +1,93 @@
+# OpenTelemetry Test Suite for Guzzle HTTP Client
+
+This test suite verifies that OpenTelemetry works correctly with the Guzzle HTTP client to propagate tracing headers, including Cloudflare's `Cf-Ray` header.
+
+## Overview
+
+The tests verify that the `GuzzleTraceMiddleware` works correctly by:
+1. **Adding OpenTelemetry tracing headers**: Verifies that `traceparent` and `baggage` headers are automatically added to outgoing HTTP requests.
+2. **Propagating baggage context**: When `baggage` contains `cf-ray` and `user-agent` values, they are correctly propagated in the `baggage` header of outgoing requests.
+3. **Handling requests without baggage**: Ensures the middleware still adds tracing headers (`traceparent`) even when no baggage is configured.
+4. **Supporting different `cf-ray` formats**: Tests with various `cf-ray` value formats to ensure compatibility.
+5. **Maintaining context across multiple requests**: Verifies that tracing context is preserved across sequential HTTP requests within the same span.
+
+## Created Files
+
+### Tests
+- `tests/OpenTelemetry/GuzzleTracingTest.php`: Unit tests that mock HTTP requests to verify middleware behavior
+
+### Support
+- `tests/OpenTelemetry/OpenTelemetryTestCase.php`: Base test case that sets up OpenTelemetry environment and registers the testing ServiceProvider
+- `tests/Support/OpenTelemetryTestingServiceProvider.php`: ServiceProvider to configure OpenTelemetry in testing environment
+- `tests/OpenTelemetry/Traits/SetsUpOpenTelemetryEnvironment.php`: Trait for environment setup in tests that don't extend the base case
+
+## Testing Environment Configuration
+
+### OpenTelemetryTestCase.php
+The base test case (`tests/OpenTelemetry/OpenTelemetryTestCase.php`) programmatically sets up OpenTelemetry environment variables:
+```php
+putenv('OTEL_SERVICE_ENABLED=true');
+putenv('OTEL_SERVICE_NAME=summit-api-test');
+putenv('OTEL_PROPAGATORS=tracecontext,baggage');
+putenv('OTEL_INSTRUMENTATION_HTTP_CLIENT=true');
+// ... more OTEL variables ...
+```
+
+### Alternative: SetsUpOpenTelemetryEnvironment Trait
+Available trait (`tests/OpenTelemetry/Traits/SetsUpOpenTelemetryEnvironment.php`) provides the same environment setup for tests that don't extend `OpenTelemetryTestCase`.
+
+### OpenTelemetryTestingServiceProvider
+The ServiceProvider (`tests/Support/OpenTelemetryTestingServiceProvider.php`) is automatically registered by `OpenTelemetryTestCase` and provides:
+- `TracerInterface` binding with NoopSpanProcessor for testing
+- Propagators configuration (TraceContext and Baggage)
+- Laravel OpenTelemetry `Tracer` facade integration
+
+The tests use `$this->app->make(TracerInterface::class)` to get the tracer instance configured by this ServiceProvider.
+
+## Running Tests
+
+```bash
+# Run entire OTEL test suite
+docker-compose exec app vendor/bin/phpunit --testsuite="OTEL"
+
+# Run only Guzzle tracing tests
+docker-compose exec app vendor/bin/phpunit tests/OpenTelemetry/GuzzleTracingTest.php
+
+# Run a specific test
+docker-compose exec app vendor/bin/phpunit --filter="testGuzzleTraceMiddlewareAddsHeaders"
+```
+
+## Included Tests
+
+1. **testGuzzleTraceMiddlewareAddsHeaders**: Main test that verifies the middleware adds both `traceparent` and `baggage` headers, and that baggage correctly contains `cf-ray` and `user-agent` values from the active baggage context.
+2. **testGuzzleWithoutBaggage**: Verifies that when no baggage is configured, the middleware still adds `traceparent` headers but doesn't include `cf-ray` in baggage.
+3. **testGuzzleWithDifferentCfRayValues**: Uses a data provider to test the middleware with various `cf-ray` value formats (different datacenters and hex values).
+4. **testMultipleRequestsWithTracing**: Verifies that tracing context and baggage are maintained across multiple sequential HTTP requests within the same span.
+
+## Test Implementation Details
+
+The tests use mocked HTTP handlers to simulate real HTTP requests:
+- **MockHandler**: Provides predefined responses without making actual HTTP calls
+- **History Middleware**: Captures outgoing requests with their headers for verification
+- **Active Spans**: Creates OpenTelemetry spans to provide the required tracing context
+- **Baggage Configuration**: Manually sets baggage values (`cf-ray`, `user-agent`) to simulate real middleware behavior
+
+## Test Verifications
+
+Each test performs the following verifications:
+- **Header Presence**: Confirms that `traceparent` headers are added to all outgoing requests
+- **Baggage Propagation**: When baggage is configured, verifies that `baggage` headers contain the expected `cf-ray` values
+- **Header Format**: Validates that baggage headers follow the correct format (`cf-ray`=value,`user-agent`=value)
+- **Context Isolation**: Ensures that tests without baggage don't leak `cf-ray` values into headers
+- **Custom Headers Preserved**: Verifies that existing request headers are maintained alongside tracing headers
+- **Mock Response Handling**: Confirms that mocked responses are properly returned
+
+## Technical Implementation Notes
+
+- **Middleware Order**: Critical that `GuzzleTraceMiddleware` is added BEFORE the History middleware to ensure headers are captured after being added by the trace middleware
+- **Active Span Requirement**: An active OpenTelemetry span must be present for the `GuzzleTraceMiddleware` to function properly
+- **Baggage Scope Management**: Baggage must be activated and properly scoped to ensure values are available during request processing
+- **MockHandler Setup**: Tests use `MockHandler` with predefined responses to avoid actual HTTP calls while testing middleware behavior
+- **ServiceProvider Integration**: The test suite uses `OpenTelemetryTestingServiceProvider` to configure TracerInterface and propagators in the test environment
+
+These tests verify that the `GuzzleTraceMiddleware` correctly integrates with OpenTelemetry's tracing system to add proper headers to outgoing HTTP requests.
diff --git a/tests/OpenTelemetry/Support/OpenTelemetryTestingServiceProvider.php b/tests/OpenTelemetry/Support/OpenTelemetryTestingServiceProvider.php
new file mode 100644
index 000000000..730a5c9e5
--- /dev/null
+++ b/tests/OpenTelemetry/Support/OpenTelemetryTestingServiceProvider.php
@@ -0,0 +1,94 @@
+registerTracerProvider();
+ $this->registerPropagators();
+ }
+
+ /**
+ * Bootstrap services.
+ */
+ public function boot(): void
+ {
+ $this->app->bind(TracerInterface::class, function ($app) {
+ /** @var TracerProvider $tracerProvider */
+ $tracerProvider = $app->make(TracerProvider::class);
+ return $tracerProvider->getTracer('test-tracer', '1.0.0');
+ });
+ }
+
+ /**
+ * Register the TraceProvider for testing
+ */
+ protected function registerTracerProvider(): void
+ {
+ $this->app->singleton(TracerProvider::class, function () {
+ $resource = ResourceInfoFactory::emptyResource();
+
+ return TracerProvider::builder()
+ ->addSpanProcessor(new NoopSpanProcessor())
+ ->setResource($resource)
+ ->build();
+ });
+
+ // Registrar el Tracer principal que usa el facade
+ $this->app->singleton(Tracer::class, function ($app) {
+ return new Tracer(
+ $app->make(TracerInterface::class),
+ $app->make(TextMapPropagatorInterface::class)
+ );
+ });
+ }
+
+ /**
+ * Register propagators for testing
+ */
+ protected function registerPropagators(): void
+ {
+ $this->app->singleton(TextMapPropagatorInterface::class, function () {
+ return new MultiTextMapPropagator([
+ new TraceContextPropagator(),
+ new BaggagePropagator(),
+ ]);
+ });
+ }
+
+ /**
+ * Get the services provided by the provider.
+ *
+ * @return array
+ */
+ public function provides()
+ {
+ return [
+ TracerProvider::class,
+ TracerInterface::class,
+ \Keepsuit\LaravelOpenTelemetry\Tracer::class,
+ TextMapPropagatorInterface::class,
+ ];
+ }
+}
diff --git a/tests/OpenTelemetry/Traits/SetsUpOpenTelemetryEnvironment.php b/tests/OpenTelemetry/Traits/SetsUpOpenTelemetryEnvironment.php
new file mode 100644
index 000000000..2abb66c12
--- /dev/null
+++ b/tests/OpenTelemetry/Traits/SetsUpOpenTelemetryEnvironment.php
@@ -0,0 +1,49 @@
+