Skip to content

Commit 8314270

Browse files
authored
Merge pull request #34 from LordSimal/3.next
merge 3.next => 3.x
2 parents 9956106 + de9640a commit 8314270

13 files changed

+179
-106
lines changed

.github/workflows/ci.yml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- '3.x'
7+
- '3.next'
78
pull_request:
89
branches:
910
- '*'

composer.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,25 @@
44
"type": "cakephp-plugin",
55
"require": {
66
"php": "^8.1",
7-
"cakephp/cakephp": "^5.0.0",
7+
"cakephp/cakephp": "^5.1.0",
88
"sentry/sentry": "^4.0"
99
},
1010
"require-dev": {
1111
"cakephp/cakephp-codesniffer": "^5.0",
12-
"phpunit/phpunit": "^10.1"
12+
"mockery/mockery": "^1.6",
13+
"phpunit/phpunit": "^10.5.5 || ^11.1.3"
1314
},
1415
"license": "MIT",
1516
"autoload": {
1617
"psr-4": {
1718
"CakeSentry\\": "src/"
1819
}
1920
},
21+
"autoload-dev": {
22+
"psr-4": {
23+
"CakeSentry\\Test\\": "tests/"
24+
}
25+
},
2026
"scripts": {
2127
"test": "phpunit",
2228
"cs-check": "phpcs --colors -p",

psalm-baseline.xml

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
<code><![CDATA[getContext]]></code>
1010
<code><![CDATA[jsonSerialize]]></code>
1111
</InternalMethod>
12+
<PossiblyFalseArgument>
13+
<code><![CDATA[$querystring]]></code>
14+
<code><![CDATA[$querystring]]></code>
15+
<code><![CDATA[$querystring]]></code>
16+
<code><![CDATA[$querystring]]></code>
17+
<code><![CDATA[$querystring]]></code>
18+
<code><![CDATA[$querystring]]></code>
19+
</PossiblyFalseArgument>
1220
</file>
1321
<file src="src/Http/SentryClient.php">
1422
<InternalMethod>

src/Database/Log/CakeSentryLog.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ public function log($level, string|Stringable $message, array $context = []): vo
198198
protected function isSchemaQuery(LoggedQuery $query): bool
199199
{
200200
$context = $query->getContext();
201-
$querystring = $context['query'] ?? '';
201+
$querystring = $context['query'] ?? false;
202202

203203
if ($querystring === '') {
204204
$querystring = $query->jsonSerialize()['query'] ?? '';

src/Event/HttpEventListener.php

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace CakeSentry\Event;
5+
6+
use Cake\Event\EventListenerInterface;
7+
use Cake\Http\Client\ClientEvent;
8+
use CakeSentry\SpanStackTrait;
9+
use Sentry\SentrySdk;
10+
use Sentry\Tracing\SpanContext;
11+
12+
class HttpEventListener implements EventListenerInterface
13+
{
14+
use SpanStackTrait;
15+
16+
/**
17+
* @inheritDoc
18+
*/
19+
public function implementedEvents(): array
20+
{
21+
return [
22+
'HttpClient.beforeSend' => 'handleBeforeSend',
23+
'HttpClient.afterSend' => 'handleAfterSend',
24+
];
25+
}
26+
27+
/**
28+
* @param \Cake\Http\Client\ClientEvent $event
29+
* @return void
30+
*/
31+
public function handlebeforeSend(ClientEvent $event): void
32+
{
33+
/** @var \Cake\Http\Client\Request $request */
34+
$request = $event->getRequest();
35+
$parentSpan = SentrySdk::getCurrentHub()->getSpan();
36+
37+
if ($parentSpan !== null) {
38+
$span = SpanContext::make()
39+
->setOp('http.client');
40+
41+
$uri = $request->getUri();
42+
$fullUrl = sprintf('%s://%s%s/', $uri->getScheme(), $uri->getHost(), $uri->getPath());
43+
$span
44+
->setDescription(sprintf('%s %s', $request->getMethod(), $fullUrl))
45+
->setData([
46+
'url' => $fullUrl,
47+
'http.query' => $uri->getQuery(),
48+
'http.fragment' => $uri->getFragment(),
49+
'http.request.method' => $request->getMethod(),
50+
'http.request.body.size' => $request->getBody()->getSize(),
51+
]);
52+
53+
$this->pushSpan($parentSpan->startChild($span));
54+
}
55+
}
56+
57+
/**
58+
* @param \Cake\Http\Client\ClientEvent $event
59+
* @return void
60+
*/
61+
public function handleAfterSend(ClientEvent $event): void
62+
{
63+
$response = $event->getResult();
64+
$span = $this->popSpan();
65+
66+
if ($span !== null) {
67+
$span
68+
->setHttpStatus($response?->getStatusCode() ?? 0)
69+
->setData([
70+
'http.response.body.size' => $response?->getBody()?->getSize(),
71+
'http.response.status_code' => $response?->getStatusCode() ?? 0,
72+
])
73+
->finish();
74+
}
75+
}
76+
}

src/Middleware/CakeSentryPerformanceMiddleware.php

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Cake\Event\EventManager;
1919
use Cake\Http\Server;
2020
use CakeSentry\Database\Log\CakeSentryLog;
21+
use CakeSentry\Event\HttpEventListener;
2122
use CakeSentry\EventListener;
2223
use CakeSentry\QuerySpanTrait;
2324
use Psr\Http\Message\ResponseInterface;
@@ -78,6 +79,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
7879
$this->addQueryData();
7980
$listener = new EventListener();
8081
EventManager::instance()->on($listener);
82+
EventManager::instance()->on(new HttpEventListener());
8183

8284
$response = $handler->handle($request);
8385

src/QuerySpanTrait.php

+1-36
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,12 @@
1010
use Cake\Database\Schema\SqlserverSchemaDialect;
1111
use Cake\Datasource\ConnectionManager;
1212
use Sentry\SentrySdk;
13-
use Sentry\Tracing\Span;
1413
use Sentry\Tracing\SpanContext;
1514
use Sentry\Tracing\SpanStatus;
1615

1716
trait QuerySpanTrait
1817
{
19-
/**
20-
* @var array
21-
*/
22-
protected array $parentSpanStack = [];
23-
24-
/**
25-
* @var array
26-
*/
27-
protected array $currentSpanStack = [];
18+
use SpanStackTrait;
2819

2920
/**
3021
* @param \Cake\Database\Log\LoggedQuery $query
@@ -81,30 +72,4 @@ public function addTransactionSpan(LoggedQuery $query, ?string $connectionName =
8172
$spanContext->setEndTimestamp($spanContext->getStartTimestamp() + $context['took'] / 1000);
8273
$parentSpan->startChild($spanContext);
8374
}
84-
85-
/**
86-
* @param \Sentry\Tracing\Span $span The span.
87-
* @return void
88-
*/
89-
protected function pushSpan(Span $span): void
90-
{
91-
$this->parentSpanStack[] = SentrySdk::getCurrentHub()->getSpan();
92-
SentrySdk::getCurrentHub()->setSpan($span);
93-
$this->currentSpanStack[] = $span;
94-
}
95-
96-
/**
97-
* @return \Sentry\Tracing\Span|null
98-
*/
99-
protected function popSpan(): ?Span
100-
{
101-
if (count($this->currentSpanStack) === 0) {
102-
return null;
103-
}
104-
105-
$parent = array_pop($this->parentSpanStack);
106-
SentrySdk::getCurrentHub()->setSpan($parent);
107-
108-
return array_pop($this->currentSpanStack);
109-
}
11075
}

src/SpanStackTrait.php

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace CakeSentry;
5+
6+
use Sentry\SentrySdk;
7+
use Sentry\Tracing\Span;
8+
9+
trait SpanStackTrait
10+
{
11+
/**
12+
* @var array
13+
*/
14+
protected array $parentSpanStack = [];
15+
16+
/**
17+
* @var array
18+
*/
19+
protected array $currentSpanStack = [];
20+
21+
/**
22+
* @param \Sentry\Tracing\Span $span The span.
23+
* @return void
24+
*/
25+
protected function pushSpan(Span $span): void
26+
{
27+
$this->parentSpanStack[] = SentrySdk::getCurrentHub()->getSpan();
28+
SentrySdk::getCurrentHub()->setSpan($span);
29+
$this->currentSpanStack[] = $span;
30+
}
31+
32+
/**
33+
* @return \Sentry\Tracing\Span|null
34+
*/
35+
protected function popSpan(): ?Span
36+
{
37+
if (count($this->currentSpanStack) === 0) {
38+
return null;
39+
}
40+
41+
$parent = array_pop($this->parentSpanStack);
42+
SentrySdk::getCurrentHub()->setSpan($parent);
43+
44+
return array_pop($this->currentSpanStack);
45+
}
46+
}

tests/TestCase/CakeSentryInitTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Cake\TestSuite\TestCase;
88
use CakeSentry\CakeSentryInit;
99

10-
final class CakeSentryInitTest extends TestCase
10+
class CakeSentryInitTest extends TestCase
1111
{
1212
/**
1313
* @inheritDoc

tests/TestCase/Database/CakeSentryLogTest.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
use Cake\Database\Log\LoggedQuery;
88
use Cake\TestSuite\TestCase;
99
use CakeSentry\Database\Log\CakeSentryLog;
10+
use PHPUnit\Framework\Attributes\DataProvider;
1011
use Psr\Log\LogLevel;
1112

12-
final class CakeSentryLogTest extends TestCase
13+
class CakeSentryLogTest extends TestCase
1314
{
1415
protected CakeSentryLog $logger;
1516

@@ -57,9 +58,9 @@ public function testLog()
5758
/**
5859
* Test log ignores schema reflection
5960
*
60-
* @dataProvider schemaQueryProvider
6161
* @return void
6262
*/
63+
#[DataProvider('schemaQueryProvider')]
6364
public function testLogIgnoreReflection($sql)
6465
{
6566
$query = new LoggedQuery();
@@ -78,9 +79,9 @@ public function testLogIgnoreReflection($sql)
7879
/**
7980
* Test config setting turns off schema ignores
8081
*
81-
* @dataProvider schemaQueryProvider
8282
* @return void
8383
*/
84+
#[DataProvider('schemaQueryProvider')]
8485
public function testLogIgnoreReflectionDisabled($sql)
8586
{
8687
$query = new LoggedQuery();

tests/TestCase/Error/SentryErrorLoggerTest.php

+12-37
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
use Cake\Error\PhpError;
88
use CakeSentry\Error\SentryErrorLogger;
99
use CakeSentry\Http\SentryClient;
10+
use Mockery;
1011
use PHPUnit\Framework\TestCase;
11-
use ReflectionProperty;
1212
use RuntimeException;
1313

14-
final class SentryErrorLoggerTest extends TestCase
14+
class SentryErrorLoggerTest extends TestCase
1515
{
16-
private SentryErrorLogger $subject;
16+
protected SentryErrorLogger $logger;
17+
18+
protected SentryClient $client;
1719

1820
/**
1921
* @inheritDoc
@@ -23,13 +25,9 @@ public function setUp(): void
2325
parent::setUp();
2426

2527
Configure::write('Sentry.dsn', 'https://[email protected]/yourproject/1');
26-
$subject = new SentryErrorLogger([]);
27-
28-
$clientMock = $this->createMock(SentryClient::class);
29-
$this->subject = $subject;
30-
31-
$clientProp = $this->getClientProp();
32-
$clientProp->setValue($this->subject, $clientMock);
28+
$logger = new SentryErrorLogger([]);
29+
$this->logger = $logger;
30+
$this->client = Mockery::mock(SentryClient::class);
3331
}
3432

3533
/**
@@ -38,13 +36,8 @@ public function setUp(): void
3836
public function testLogException()
3937
{
4038
$excpetion = new RuntimeException('some error');
41-
42-
$client = $this->getClientProp()->getValue($this->subject);
43-
$client->expects($this->once())
44-
->method('captureException')
45-
->with($excpetion);
46-
47-
$this->subject->logException($excpetion);
39+
$this->client->shouldReceive('captureException')->with($excpetion, null);
40+
$this->assertNull($this->logger->logException($excpetion));
4841
}
4942

5043
/**
@@ -53,25 +46,7 @@ public function testLogException()
5346
public function testLogError()
5447
{
5548
$phpError = new PhpError(E_USER_WARNING, 'some error');
56-
57-
$client = $this->getClientProp()->getValue($this->subject);
58-
$client->expects($this->once())
59-
->method('captureError')
60-
->with($phpError);
61-
62-
$this->subject->logError($phpError);
63-
}
64-
65-
/**
66-
* Helper access subject::$client(reflection)
67-
*
68-
* @return ReflectionProperty Client reflection
69-
*/
70-
private function getClientProp()
71-
{
72-
$clientProp = new ReflectionProperty($this->subject, 'client');
73-
$clientProp->setAccessible(true);
74-
75-
return $clientProp;
49+
$this->client->shouldReceive('captureError')->with($phpError, null);
50+
$this->assertNull($this->logger->logError($phpError));
7651
}
7752
}

0 commit comments

Comments
 (0)