Skip to content

Commit 54dc33f

Browse files
committed
commented problematic metrics
1 parent 27edcc6 commit 54dc33f

5 files changed

+130
-118
lines changed

composer.json

+3
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,8 @@
4040
"LaravelApm": "Middleware\\LaravelApm\\Facades\\LaravelApm"
4141
}
4242
}
43+
},
44+
"suggest": {
45+
"guzzlehttp/guzzle": "Required for OTLP HTTP transport if not using Laravel's HTTP client"
4346
}
4447
}

src/LaravelApm.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ public function getMeterProvider()
4949
public function exportMetrics()
5050
{
5151
try {
52-
return $this->exportingReader->collect();
52+
$result = $this->exportingReader->collect();
53+
\Log::info('Metrics exported', ['result' => $result]);
54+
return $result;
5355
} catch (\Exception $e) {
5456
Log::error('Error exporting metrics', [
5557
'error' => $e->getMessage(),

src/LaravelApmServiceProvider.php

+64-20
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
use OpenTelemetry\API\Trace\TracerProviderInterface;
99
use OpenTelemetry\API\Logs\LoggerProviderInterface;
1010
use OpenTelemetry\API\Metrics\MeterProviderInterface;
11+
use OpenTelemetry\SDK\Common\Export\Http\PsrTransportFactory;
1112
use OpenTelemetry\SDK\Trace\TracerProvider;
1213
use OpenTelemetry\SDK\Logs\LoggerProvider;
1314
use OpenTelemetry\SDK\Metrics\MeterProvider;
1415
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
1516
use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor as LogProcessor;
16-
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
1717
use OpenTelemetry\Contrib\Otlp\SpanExporter;
1818
use OpenTelemetry\Contrib\Otlp\LogsExporter;
1919
use OpenTelemetry\Contrib\Otlp\MetricExporter;
@@ -24,26 +24,36 @@
2424
use OpenTelemetry\SemConv\ResourceAttributes;
2525
use OpenTelemetry\SDK\Metrics\Data\Temporality;
2626
use Illuminate\Support\Facades\Log;
27+
use Illuminate\Http\Client\Factory as LaravelHttpFactory;
28+
use GuzzleHttp\Psr7\HttpFactory as GuzzleHttpFactory;
29+
use OpenTelemetry\SDK\Common\Export\TransportFactoryInterface;
30+
use Illuminate\Support\Facades\Http;
31+
use Psr\Http\Client\ClientInterface;
32+
use Psr\Http\Message\RequestFactoryInterface;
33+
use Psr\Http\Message\StreamFactoryInterface;
2734

2835
class LaravelApmServiceProvider extends ServiceProvider
2936
{
37+
38+
private $contentType;
39+
private $headers;
40+
41+
private $endpoint;
42+
3043
public function register()
3144
{
45+
$this->endpoint = config('laravel-apm.endpoint');
46+
$this->contentType = config('laravel-apm.content_type');
47+
$this->headers = config('laravel-apm.headers');
48+
3249
$this->mergeConfigFrom(__DIR__ . '/../config/laravel-apm.php', 'laravel-apm');
3350

3451
$this->app->singleton(ExportingReader::class, function ($app) {
35-
$endpoint = config('laravel-apm.endpoint') . '/v1/metrics';
36-
$contentType = config('laravel-apm.content_type');
37-
$headers = config('laravel-apm.headers');
52+
$transportFactory = $this->getTransportFactory();
3853

39-
$transport = (new OtlpHttpTransportFactory())->create($endpoint, $contentType, $headers);
54+
$transport = $transportFactory->create($this->endpoint . '/v1/metrics', $this->contentType, $this->headers);
4055

41-
$exporter = new MetricExporter($transport, [
42-
'counter' => Temporality::CUMULATIVE,
43-
'observable_counter' => Temporality::CUMULATIVE,
44-
'histogram' => Temporality::DELTA,
45-
'observable_gauge' => Temporality::DELTA,
46-
]);
56+
$exporter = new MetricExporter($transport, Temporality::CUMULATIVE);
4757

4858
return new ExportingReader($exporter);
4959
});
@@ -106,12 +116,12 @@ public function boot()
106116

107117
private function createTracerProvider()
108118
{
109-
$endpoint = config('laravel-apm.endpoint') . '/v1/traces';
110-
$contentType = config('laravel-apm.content_type');
111-
$headers = config('laravel-apm.headers');
119+
$transportFactory = $this->getTransportFactory();
120+
121+
$transport = $transportFactory->create($this->endpoint . '/v1/traces', $this->contentType, $this->headers);
112122

113-
$transport = (new OtlpHttpTransportFactory())->create($endpoint, $contentType, $headers);
114123
$exporter = new SpanExporter($transport);
124+
115125
$spanProcessor = new SimpleSpanProcessor($exporter);
116126

117127
return TracerProvider::builder()
@@ -124,12 +134,12 @@ private function createTracerProvider()
124134

125135
private function createLoggerProvider()
126136
{
127-
$transport = (new OtlpHttpTransportFactory())->create(
128-
config('laravel-apm.endpoint') . '/v1/logs',
129-
config('laravel-apm.content_type'),
130-
config('laravel-apm.headers')
131-
);
137+
$transportFactory = $this->getTransportFactory();
138+
139+
$transport = $transportFactory->create($this->endpoint . '/v1/logs', $this->contentType, $this->headers);
140+
132141
$exporter = new LogsExporter($transport);
142+
133143
return LoggerProvider::builder()
134144
->addLogRecordProcessor(new LogProcessor($exporter))
135145
->build();
@@ -156,4 +166,38 @@ private function configureLogging()
156166
$otelHandler = new \OpenTelemetry\Contrib\Logs\Monolog\Handler($loggerProvider, 'debug');
157167
Log::pushHandler($otelHandler);
158168
}
169+
170+
protected function createHttpFactories(): array
171+
{
172+
// if (class_exists(LaravelHttpFactory::class)) {
173+
// $factory = new LaravelHttpFactory();
174+
// return [
175+
// 'client' => $factory->buildClient(),
176+
// 'requestFactory' => $factory,
177+
// 'streamFactory' => $factory,
178+
// ];
179+
// }
180+
181+
if (class_exists(GuzzleHttpFactory::class)) {
182+
$factory = new GuzzleHttpFactory();
183+
return [
184+
'client' => new \GuzzleHttp\Client(),
185+
'requestFactory' => $factory,
186+
'streamFactory' => $factory,
187+
];
188+
}
189+
190+
throw new \RuntimeException('No suitable HTTP factories found. Please install Guzzle or use Laravel 8.0+');
191+
}
192+
193+
private function getTransportFactory(): TransportFactoryInterface
194+
{
195+
$factories = $this->createHttpFactories();
196+
197+
return new PsrTransportFactory(
198+
$factories['client'],
199+
$factories['requestFactory'],
200+
$factories['streamFactory']
201+
);
202+
}
159203
}

src/MetricsManager.php

+28-29
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,24 @@ private function initializeMetrics()
3333
'Total number of HTTP requests',
3434
);
3535

36-
// // Gauge (no temporality needed)
37-
$this->responseTimeGauge = $meter->createObservableGauge(
38-
'laravel.http.response.duration',
39-
'seconds',
40-
'HTTP response time',
41-
);
36+
// Gauge (no temporality needed)
37+
// $this->responseTimeGauge = $meter->createObservableGauge(
38+
// 'laravel.http.response.duration',
39+
// 'seconds',
40+
// 'HTTP response time',
41+
// );
4242

43-
// Gauge (Delta)
44-
$this->requestSizeGauge = $meter->createObservableGauge(
45-
'laravel.http.request.size',
46-
'bytes',
47-
'Size of HTTP requests',
48-
);
43+
// $this->requestSizeGauge = $meter->createObservableGauge(
44+
// 'laravel.http.request.size',
45+
// 'bytes',
46+
// 'Size of HTTP requests',
47+
// );
4948

50-
$this->responseSizeGauge = $meter->createObservableGauge(
51-
'laravel.http.response.size',
52-
'bytes',
53-
'Size of HTTP responses',
54-
);
49+
// $this->responseSizeGauge = $meter->createObservableGauge(
50+
// 'laravel.http.response.size',
51+
// 'bytes',
52+
// 'Size of HTTP responses',
53+
// );
5554

5655
// Counter (Cumulative)
5756
$this->statusCounter = $meter->createCounter(
@@ -66,20 +65,20 @@ public function getRequestsCounter(): CounterInterface
6665
return $this->requestsCounter;
6766
}
6867

69-
public function getResponseTimeGauge(): ObservableGaugeInterface
70-
{
71-
return $this->responseTimeGauge;
72-
}
68+
// public function getResponseTimeGauge(): ObservableGaugeInterface
69+
// {
70+
// return $this->responseTimeGauge;
71+
// }
7372

74-
public function getRequestSizeGauge(): ObservableGaugeInterface
75-
{
76-
return $this->requestSizeGauge;
77-
}
73+
// public function getRequestSizeGauge(): ObservableGaugeInterface
74+
// {
75+
// return $this->requestSizeGauge;
76+
// }
7877

79-
public function getResponseSizeGauge(): ObservableGaugeInterface
80-
{
81-
return $this->responseSizeGauge;
82-
}
78+
// public function getResponseSizeGauge(): ObservableGaugeInterface
79+
// {
80+
// return $this->responseSizeGauge;
81+
// }
8382

8483
public function getStatusCounter(): CounterInterface
8584
{

src/Middleware/MetricsMiddleware.php

+32-68
Original file line numberDiff line numberDiff line change
@@ -11,103 +11,67 @@
1111
class MetricsMiddleware
1212
{
1313
private $metricsManager;
14-
private static $responseTimes = [];
15-
private $totalDuration = 0;
16-
private $requestCount = 0;
17-
private $totalRequestSize = 0;
18-
private $totalResponseSize = 0;
14+
private $meterProvider;
15+
private $requestsCounter;
16+
private $responseTimeGauge;
17+
private $requestSizeGauge;
18+
private $responseSizeGauge;
19+
private $statusCounter;
20+
private static $lastResponseTime = 0;
21+
private static $lastRequestSize = 0;
22+
private static $lastResponseSize = 0;
23+
1924

2025
public function __construct(MetricsManager $metricsManager)
2126
{
2227
$this->metricsManager = $metricsManager;
2328

24-
// $this->metricsManager->getResponseSizeGauge()->observe(function (ObserverInterface $observer): void {
25-
// foreach (self::$responseTimes as $labels => $time) {
26-
// $observer->observe($time, json_decode($labels, true));
27-
// }
28-
// self::$responseTimes = [];
29+
// Set up callbacks for observable gauges
30+
// $this->metricsManager->getResponseTimeGauge()->observe(static function ($observer) {
31+
// $observer->observe(self::$lastResponseSize);
32+
// });
33+
34+
// $this->metricsManager->getRequestSizeGauge()->observe(static function ($observer) {
35+
// $observer->observe(self::$lastRequestSize);
36+
// });
37+
38+
// $this->metricsManager->getResponseSizeGauge()->observe(static function ($observer) {
39+
// $observer->observe(self::$lastResponseSize);
2940
// });
3041
}
3142

3243
public function handle(Request $request, Closure $next)
3344
{
3445
$startTime = microtime(true);
35-
3646
$response = $next($request);
37-
3847
$duration = microtime(true) - $startTime;
48+
3949
$route = $request->route() ? $request->route()->uri() : 'unknown';
4050

41-
// Only record metrics once per request
42-
if (!$request->attributes->has('metrics_recorded')) {
43-
$this->recordMetrics($request, $response, $duration, $route);
44-
$request->attributes->set('metrics_recorded', true);
45-
}
51+
$this->recordMetrics($request, $response, $duration, $route);
4652

4753
return $response;
4854
}
4955

5056
private function recordMetrics(Request $request, $response, $duration, $route)
5157
{
58+
// Update static properties
59+
self::$lastResponseTime = $duration;
60+
self::$lastRequestSize = strlen($request->getContent());
61+
self::$lastResponseSize = strlen($response->getContent());
62+
63+
// Record other metrics
5264
$this->metricsManager->getRequestsCounter()->add(1, [
5365
'method' => $request->method(),
5466
'route' => $route
5567
]);
5668

57-
// $labels = json_encode(['method' => $request->method(), 'route' => $route]);
58-
// self::$responseTimes[$labels] = $duration;
59-
60-
// $this->metricsManager->getStatusCounter()->add(1, [
61-
// 'status' => (string) $response->getStatusCode()
62-
// ]);
63-
64-
// $requestSize = $request->headers->get('Content-Length', 0);
65-
// $responseSize = $response->headers->get('Content-Length', 0);
66-
67-
// $this->metricsManager->getRequestSizeUpDownCounter()->add($requestSize, [
68-
// 'method' => $request->method()
69-
// ]);
70-
71-
// $this->metricsManager->getResponseSizeUpDownCounter()->add($responseSize, [
72-
// 'method' => $request->method()
73-
// ]);
74-
75-
$this->totalDuration += $duration;
76-
$this->requestCount++;
77-
$avgDuration = $this->totalDuration / $this->requestCount;
78-
79-
$this->metricsManager->getResponseTimeGauge()->observe(function ($observer) use ($avgDuration) {
80-
$observer->observe($avgDuration);
81-
});
82-
83-
$requestSize = strlen($request->getContent());
84-
$this->totalRequestSize += $requestSize;
85-
$avgRequestSize = $this->totalRequestSize / $this->requestCount;
86-
87-
$this->metricsManager->getRequestSizeGauge()->observe(function ($observer) use ($avgRequestSize) {
88-
$observer->observe($avgRequestSize);
89-
});
90-
91-
$responseSize = strlen($response->getContent());
92-
$this->totalResponseSize += $responseSize;
93-
$avgResponseSize = $this->totalResponseSize / $this->requestCount;
94-
95-
$this->metricsManager->getResponseSizeGauge()->observe(function ($observer) use ($avgResponseSize) {
96-
$observer->observe($avgResponseSize);
97-
});
98-
9969
$this->metricsManager->getStatusCounter()->add(1, [
10070
'status' => (string) $response->getStatusCode()
10171
]);
10272

103-
Log::info("Request metrics", [
104-
'method' => $request->method(),
105-
'route' => $route,
106-
'duration' => $duration,
107-
'avgDuration' => $avgDuration,
108-
'requestSize' => $requestSize,
109-
'responseSize' => $responseSize,
110-
'status' => $response->getStatusCode()
111-
]);
73+
return $response;
11274
}
75+
76+
11377
}

0 commit comments

Comments
 (0)