Skip to content

Commit 83a3dea

Browse files
Fix: Histrogram Buckets (#15)
1 parent 5e3fc39 commit 83a3dea

13 files changed

Lines changed: 259 additions & 39 deletions

src/Aspect/Aws/DynamoDbClientAspect.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Hyperf\Di\Aop\ProceedingJoinPoint;
88
use Hyperf\Di\Exception\Exception;
99
use Hyperf\OpenTelemetry\Aspect\AbstractAspect;
10+
use Hyperf\OpenTelemetry\Support\MetricBoundaries;
1011
use OpenTelemetry\API\Trace\SpanKind;
1112
use OpenTelemetry\API\Trace\StatusCode;
1213
use OpenTelemetry\SemConv\Attributes\DbAttributes;
@@ -78,12 +79,17 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint)
7879
$scope?->end();
7980

8081
if ($this->isMetricsEnabled) {
81-
$duration = (microtime(true) - $start) * 1000;
82+
$durationInSeconds = microtime(true) - $start;
8283

8384
$this->instrumentation->meter()
84-
->createHistogram(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
85+
->createHistogram(
86+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
87+
's',
88+
'Duration of database client operations.',
89+
['ExplicitBucketBoundaries' => MetricBoundaries::DB_DURATION]
90+
)
8591
->record(
86-
$duration,
92+
$durationInSeconds,
8793
array_merge(
8894
$metricErrors,
8995
[

src/Aspect/GuzzleClientAspect.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Hyperf\Di\Aop\ProceedingJoinPoint;
1010
use Hyperf\Di\Exception\Exception;
1111
use Hyperf\OpenTelemetry\Propagator\HeadersPropagator;
12+
use Hyperf\OpenTelemetry\Support\MetricBoundaries;
1213
use Hyperf\OpenTelemetry\Support\SpanScope;
1314
use Hyperf\OpenTelemetry\Support\Uri;
1415
use Hyperf\Stringable\Str;
@@ -126,10 +127,15 @@ private function onFullFilled(?SpanScope $scope, RequestInterface $request, floa
126127
}
127128

128129
if ($this->isMetricsEnabled) {
129-
$duration = (microtime(true) - $start) * 1000;
130+
$durationInSeconds = microtime(true) - $start;
130131
$this->instrumentation->meter()
131-
->createHistogram('http.client.request.duration', 'ms')
132-
->record($duration, [
132+
->createHistogram(
133+
HttpMetrics::HTTP_CLIENT_REQUEST_DURATION,
134+
's',
135+
'Duration of HTTP client requests.',
136+
['ExplicitBucketBoundaries' => MetricBoundaries::HTTP_DURATION]
137+
)
138+
->record($durationInSeconds, [
133139
ServerAttributes::SERVER_ADDRESS => $request->getUri()->getHost(),
134140
HttpAttributes::HTTP_REQUEST_METHOD => $request->getMethod(),
135141
HttpAttributes::HTTP_RESPONSE_STATUS_CODE => $response->getStatusCode(),
@@ -153,11 +159,16 @@ private function onRejected(?SpanScope $scope, RequestInterface $request, float
153159
}
154160

155161
if ($this->isMetricsEnabled) {
156-
$duration = (microtime(true) - $start) * 1000;
162+
$durationInSeconds = microtime(true) - $start;
157163
$this->instrumentation->meter()
158-
->createHistogram(HttpMetrics::HTTP_CLIENT_REQUEST_DURATION, 'ms')
164+
->createHistogram(
165+
HttpMetrics::HTTP_CLIENT_REQUEST_DURATION,
166+
's',
167+
'Duration of HTTP client requests.',
168+
['ExplicitBucketBoundaries' => MetricBoundaries::HTTP_DURATION]
169+
)
159170
->record(
160-
$duration,
171+
$durationInSeconds,
161172
[
162173
ServerAttributes::SERVER_ADDRESS => $request->getUri()->getHost(),
163174
HttpAttributes::HTTP_REQUEST_METHOD => $request->getMethod(),

src/Aspect/MongoAspect.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Hyperf\OpenTelemetry\Aspect;
66

77
use Hyperf\Di\Aop\ProceedingJoinPoint;
8+
use Hyperf\OpenTelemetry\Support\MetricBoundaries;
89
use Hyperf\Stringable\Str;
910
use OpenTelemetry\API\Trace\SpanKind;
1011
use OpenTelemetry\API\Trace\StatusCode;
@@ -77,12 +78,17 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint)
7778
$scope?->end();
7879

7980
if ($this->isMetricsEnabled) {
80-
$duration = (microtime(true) - $start) * 1000;
81+
$durationInSeconds = microtime(true) - $start;
8182

8283
$this->instrumentation->meter()
83-
->createHistogram(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
84+
->createHistogram(
85+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
86+
's',
87+
'Duration of database client operations.',
88+
['ExplicitBucketBoundaries' => MetricBoundaries::DB_DURATION]
89+
)
8490
->record(
85-
$duration,
91+
$durationInSeconds,
8692
array_merge($metricErrors, [
8793
DbAttributes::DB_SYSTEM_NAME => DbIncubatingAttributes::DB_SYSTEM_NAME_VALUE_MONGODB,
8894
DbAttributes::DB_OPERATION_NAME => $operation,

src/Aspect/RedisAspect.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Hyperf\Di\Aop\ProceedingJoinPoint;
88
use Hyperf\Di\Exception\Exception;
9+
use Hyperf\OpenTelemetry\Support\MetricBoundaries;
910
use Hyperf\Stringable\Str;
1011
use OpenTelemetry\API\Trace\SpanKind;
1112
use OpenTelemetry\API\Trace\StatusCode;
@@ -71,12 +72,17 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint)
7172
$scope?->end();
7273

7374
if ($this->isMetricsEnabled) {
74-
$duration = (microtime(true) - $start) * 1000;
75+
$durationInSeconds = microtime(true) - $start;
7576

7677
$this->instrumentation->meter()
77-
->createHistogram(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
78+
->createHistogram(
79+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
80+
's',
81+
'Duration of database client operations.',
82+
['ExplicitBucketBoundaries' => MetricBoundaries::DB_DURATION]
83+
)
7884
->record(
79-
$duration,
85+
$durationInSeconds,
8086
array_merge(
8187
$metricErrors,
8288
[

src/Listener/DbQueryExecutedListener.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Hyperf\Database\Events\QueryExecuted;
99
use Hyperf\Event\Contract\ListenerInterface;
1010
use Hyperf\OpenTelemetry\Support\AbstractInstrumenter;
11+
use Hyperf\OpenTelemetry\Support\MetricBoundaries;
1112
use Hyperf\Stringable\Str;
1213
use OpenTelemetry\API\Trace\SpanKind;
1314
use OpenTelemetry\SemConv\Attributes\DbAttributes;
@@ -91,10 +92,17 @@ protected function onQueryExecuted(QueryExecuted $event): void
9192
];
9293
}
9394

95+
$durationInSeconds = $event->time / 1000;
96+
9497
$this->instrumentation->meter()
95-
->createHistogram(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
98+
->createHistogram(
99+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
100+
's',
101+
'Duration of database client operations.',
102+
['ExplicitBucketBoundaries' => MetricBoundaries::DB_DURATION]
103+
)
96104
->record(
97-
$event->time,
105+
$durationInSeconds,
98106
array_merge(
99107
$metricErrors,
100108
[

src/Middleware/MetricMiddleware.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Hyperf\OpenTelemetry\Middleware;
66

7+
use Hyperf\OpenTelemetry\Support\MetricBoundaries;
78
use Hyperf\OpenTelemetry\Support\Uri;
89
use OpenTelemetry\SemConv\Attributes\ErrorAttributes;
910
use OpenTelemetry\SemConv\Attributes\HttpAttributes;
@@ -49,11 +50,16 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
4950

5051
throw $exception;
5152
} finally {
52-
$duration = (microtime(true) - $startTime) * 1000;
53+
$durationInSeconds = microtime(true) - $startTime;
5354

5455
$this->instrumentation->meter()
55-
->createHistogram(HttpMetrics::HTTP_SERVER_REQUEST_DURATION, 'ms')
56-
->record($duration, $attributes);
56+
->createHistogram(
57+
HttpMetrics::HTTP_SERVER_REQUEST_DURATION,
58+
's',
59+
'Duration of HTTP server requests.',
60+
['ExplicitBucketBoundaries' => MetricBoundaries::HTTP_DURATION]
61+
)
62+
->record($durationInSeconds, $attributes);
5763
}
5864
}
5965

src/Support/MetricBoundaries.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hyperf\OpenTelemetry\Support;
6+
7+
/**
8+
* Explicit bucket boundaries for OpenTelemetry histograms.
9+
*
10+
* These boundaries follow OpenTelemetry semantic conventions.
11+
*
12+
* @see https://opentelemetry.io/docs/specs/semconv/http/http-metrics/
13+
* @see https://opentelemetry.io/docs/specs/semconv/db/database-metrics/
14+
*/
15+
final class MetricBoundaries
16+
{
17+
/**
18+
* Explicit bucket boundaries for HTTP duration histograms.
19+
* Values are in seconds as per OpenTelemetry semantic conventions.
20+
*
21+
* Used for:
22+
* - http.server.request.duration
23+
* - http.client.request.duration
24+
*
25+
* @see https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpserverrequestduration
26+
* @see https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpclientrequestduration
27+
*/
28+
public const HTTP_DURATION = [
29+
0.005,
30+
0.01,
31+
0.025,
32+
0.05,
33+
0.075,
34+
0.1,
35+
0.25,
36+
0.5,
37+
0.75,
38+
1,
39+
2.5,
40+
5,
41+
7.5,
42+
10,
43+
];
44+
45+
/**
46+
* Explicit bucket boundaries for database operation duration histograms.
47+
* Values are in seconds as per OpenTelemetry semantic conventions.
48+
*
49+
* Used for:
50+
* - db.client.operation.duration
51+
*
52+
* @see https://opentelemetry.io/docs/specs/semconv/db/database-metrics/#metric-dbclientoperationduration
53+
*/
54+
public const DB_DURATION = [
55+
0.001,
56+
0.005,
57+
0.01,
58+
0.05,
59+
0.1,
60+
0.5,
61+
1,
62+
5,
63+
10,
64+
];
65+
}

tests/Unit/Aspect/Aws/DynamoDbClientAspectTest.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,14 @@ public function testProcess(): void
173173
// Metric
174174
$this->meter->expects($this->once())
175175
->method('createHistogram')
176-
->with(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
176+
->with(
177+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
178+
's',
179+
'Duration of database client operations.',
180+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
181+
&& is_array($advisory['ExplicitBucketBoundaries'])
182+
&& count($advisory['ExplicitBucketBoundaries']) === 9)
183+
)
177184
->willReturn($this->histogram);
178185

179186
$this->histogram->expects($this->once())
@@ -220,7 +227,14 @@ public function testProcessWithException(): void
220227
// Metric
221228
$this->meter->expects($this->once())
222229
->method('createHistogram')
223-
->with(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
230+
->with(
231+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
232+
's',
233+
'Duration of database client operations.',
234+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
235+
&& is_array($advisory['ExplicitBucketBoundaries'])
236+
&& count($advisory['ExplicitBucketBoundaries']) === 9)
237+
)
224238
->willReturn($this->histogram);
225239

226240
$this->histogram->expects($this->once())

tests/Unit/Aspect/GuzzleClientAspectTest.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,14 @@ public function testProcessWithSuccessRequest(): void
198198
// Metric
199199
$this->meter->expects($this->once())
200200
->method('createHistogram')
201-
->with('http.client.request.duration', 'ms')
201+
->with(
202+
'http.client.request.duration',
203+
's',
204+
'Duration of HTTP client requests.',
205+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
206+
&& is_array($advisory['ExplicitBucketBoundaries'])
207+
&& count($advisory['ExplicitBucketBoundaries']) === 14)
208+
)
202209
->willReturn($this->histogram);
203210

204211
$this->histogram->expects($this->once())
@@ -288,7 +295,14 @@ public function testProcessWithUriMaskAndSuccessRequest(): void
288295
// Metric
289296
$this->meter->expects($this->once())
290297
->method('createHistogram')
291-
->with('http.client.request.duration', 'ms')
298+
->with(
299+
'http.client.request.duration',
300+
's',
301+
'Duration of HTTP client requests.',
302+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
303+
&& is_array($advisory['ExplicitBucketBoundaries'])
304+
&& count($advisory['ExplicitBucketBoundaries']) === 14)
305+
)
292306
->willReturn($this->histogram);
293307

294308
$this->histogram->expects($this->once())
@@ -378,7 +392,14 @@ public function testProcessWithBadRequest(): void
378392
// Metric
379393
$this->meter->expects($this->once())
380394
->method('createHistogram')
381-
->with('http.client.request.duration', 'ms')
395+
->with(
396+
'http.client.request.duration',
397+
's',
398+
'Duration of HTTP client requests.',
399+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
400+
&& is_array($advisory['ExplicitBucketBoundaries'])
401+
&& count($advisory['ExplicitBucketBoundaries']) === 14)
402+
)
382403
->willReturn($this->histogram);
383404

384405
$this->histogram->expects($this->once())
@@ -458,7 +479,14 @@ public function testProcessWithRejectedRequest(): void
458479

459480
$this->meter->expects($this->once())
460481
->method('createHistogram')
461-
->with('http.client.request.duration', 'ms')
482+
->with(
483+
'http.client.request.duration',
484+
's',
485+
'Duration of HTTP client requests.',
486+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
487+
&& is_array($advisory['ExplicitBucketBoundaries'])
488+
&& count($advisory['ExplicitBucketBoundaries']) === 14)
489+
)
462490
->willReturn($this->histogram);
463491

464492
$this->histogram->expects($this->once())

tests/Unit/Aspect/MongoAspectTest.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,14 @@ public function testProcess(): void
166166

167167
$this->meter->expects($this->once())
168168
->method('createHistogram')
169-
->with(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
169+
->with(
170+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
171+
's',
172+
'Duration of database client operations.',
173+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
174+
&& is_array($advisory['ExplicitBucketBoundaries'])
175+
&& count($advisory['ExplicitBucketBoundaries']) === 9)
176+
)
170177
->willReturn($this->histogram);
171178

172179
$this->histogram->expects($this->once())
@@ -251,7 +258,14 @@ public function testProcessWithException(): void
251258

252259
$this->meter->expects($this->once())
253260
->method('createHistogram')
254-
->with(DbMetrics::DB_CLIENT_OPERATION_DURATION, 'ms')
261+
->with(
262+
DbMetrics::DB_CLIENT_OPERATION_DURATION,
263+
's',
264+
'Duration of database client operations.',
265+
$this->callback(fn (array $advisory) => isset($advisory['ExplicitBucketBoundaries'])
266+
&& is_array($advisory['ExplicitBucketBoundaries'])
267+
&& count($advisory['ExplicitBucketBoundaries']) === 9)
268+
)
255269
->willReturn($this->histogram);
256270

257271
$this->histogram->expects($this->once())

0 commit comments

Comments
 (0)