Skip to content

Commit 018bd69

Browse files
authored
Merge pull request #1923 from getsentry/merge-master
Merge master
2 parents 422a317 + b9e69ee commit 018bd69

10 files changed

Lines changed: 173 additions & 23 deletions

File tree

.github/pull_request_template.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
### Description
2+
<!-- What changed and why? -->
3+
4+
#### Issues
5+
<!--
6+
* resolves: #1234
7+
* resolves: LIN-1234
8+
-->
9+
10+
#### Reminders
11+
- Add GH Issue ID _&_ Linear ID
12+
- PR title should use [conventional commit](https://develop.sentry.dev/engineering-practices/commit-messages/#type) style (`feat:`, `fix:`, `ref:`, `meta:`)
13+
- For external contributors: [CONTRIBUTING.md](https://github.com/getsentry/sentry-php/blob/master/CONTRIBUTING.md), [Sentry SDK development docs](https://develop.sentry.dev/sdk/), [Discord community](https://discord.gg/Ww9hbqr)

.github/workflows/publish-release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
steps:
2525
- name: Get auth token
2626
id: token
27-
uses: actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b # v2.1.1
27+
uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4
2828
with:
2929
app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }}
3030
private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }}

CHANGELOG.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# CHANGELOG
22

3+
## 4.16.0
4+
5+
The Sentry SDK team is happy to announce the immediate availability of Sentry PHP SDK v4.16.0.
6+
7+
### Features
8+
9+
- Remove `max_breadcrumbs` limit. [(#1890)](https://github.com/getsentry/sentry-php/pull/1890)
10+
- Implement `__destruct` in `LogsHandler` to make sure logs are always flushed. [(#1916)](https://github.com/getsentry/sentry-php/pull/1916)
11+
12+
### Bug Fixes
13+
14+
- Use PSR log level when logging messages using the PSR-3 logger within the SDK. [(#1907)](https://github.com/getsentry/sentry-php/pull/1907)
15+
- Remove `@internal` annotation from `Sentry\Transport\Result`. [(#1904)](https://github.com/getsentry/sentry-php/pull/1904)
16+
17+
### Misc
18+
19+
- Add `sentry.origin` attribute to `LogsHandler`. [(#1917)](https://github.com/getsentry/sentry-php/pull/1917)
20+
321
## 4.15.2
422

523
The Sentry SDK team is happy to announce the immediate availability of Sentry PHP SDK v4.15.2.
@@ -30,26 +48,26 @@ The Sentry SDK team is happy to announce the immediate availability of Sentry PH
3048
use Monolog\Logger;
3149
use Sentry\Monolog\LogsHandler;
3250
use Sentry\Logs\LogLevel;
33-
51+
3452
// Initialize Sentry SDK first (make sure 'enable_logs' is set to true)
3553
\Sentry\init([
3654
'dsn' => '__YOUR_DSN__',
3755
'enable_logs' => true,
3856
]);
39-
57+
4058
// Create a Monolog logger
4159
$logger = new Logger('my-app');
42-
60+
4361
// Add the Sentry logs handler
4462
// Optional: specify minimum log level (defaults to LogLevel::debug())
4563
$handler = new LogsHandler(LogLevel::info());
4664
$logger->pushHandler($handler);
47-
65+
4866
// Now your logs will be sent to Sentry
4967
$logger->info('User logged in', ['user_id' => 123]);
5068
$logger->error('Payment failed', ['order_id' => 456]);
5169
```
52-
70+
5371
Note: The handler will not collect logs for exceptions (they should be handled separately via `captureException`).
5472

5573
### Bug Fixes

src/Client.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Client implements ClientInterface
3232
/**
3333
* The version of the SDK.
3434
*/
35-
public const SDK_VERSION = '4.15.2';
35+
public const SDK_VERSION = '4.16.0';
3636

3737
/**
3838
* Regex pattern to detect if a string is a regex pattern (starts and ends with / optionally followed by flags).

src/Logs/Log.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public function setLevel(LogLevel $level): self
8282
return $this;
8383
}
8484

85+
public function getPsrLevel(): string
86+
{
87+
return $this->level->toPsrLevel();
88+
}
89+
8590
public function getBody(): string
8691
{
8792
return $this->body;

src/Logs/LogLevel.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,24 @@ public function getPriority(): int
7070
return $this->priority;
7171
}
7272

73+
public function toPsrLevel(): string
74+
{
75+
switch ($this->value) {
76+
case 'trace':
77+
case 'debug':
78+
return \Psr\Log\LogLevel::DEBUG;
79+
case 'warn':
80+
return \Psr\Log\LogLevel::WARNING;
81+
case 'error':
82+
return \Psr\Log\LogLevel::ERROR;
83+
case 'fatal':
84+
return \Psr\Log\LogLevel::CRITICAL;
85+
case 'info':
86+
default:
87+
return \Psr\Log\LogLevel::INFO;
88+
}
89+
}
90+
7391
private static function getInstance(string $value, int $priority): self
7492
{
7593
if (!isset(self::$instances[$value])) {

src/Logs/LogsAggregator.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,8 @@ public function add(
147147
return;
148148
}
149149

150-
// We check if it's a `LogsLogger` to avoid a infinite loop where the logger is logging the logs it's writing
151150
if ($sdkLogger !== null) {
152-
$sdkLogger->log((string) $log->getLevel(), "Logs item: {$log->getBody()}", $log->attributes()->toSimpleArray());
151+
$sdkLogger->log($log->getPsrLevel(), "Logs item: {$log->getBody()}", $log->attributes()->toSimpleArray());
153152
}
154153

155154
$this->logs[] = $log;

src/Monolog/LogsHandler.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function handle($record): bool
6666
self::getSentryLogLevelFromMonologLevel($record['level']),
6767
$record['message'],
6868
[],
69-
array_merge($record['context'], $record['extra'])
69+
array_merge($record['context'], $record['extra'], ['sentry.origin' => 'auto.logger.monolog'])
7070
);
7171

7272
return $this->bubble === false;
@@ -114,4 +114,13 @@ public function getFormatter(): FormatterInterface
114114
// To adhere to the interface we need to return a formatter so we return a default one
115115
return new LineFormatter();
116116
}
117+
118+
public function __destruct()
119+
{
120+
try {
121+
$this->close();
122+
} catch (\Throwable $e) {
123+
// Just in case so that the destructor can never fail.
124+
}
125+
}
117126
}

tests/Logs/LogTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,31 @@ public function testGettersAndSetters(): void
3232
$log->setBody('bar');
3333
$this->assertSame('bar', $log->getBody());
3434
}
35+
36+
/**
37+
* @dataProvider logLevelDataProvider
38+
*/
39+
public function testLogLevelToPsrMapping(LogLevel $logLevel, $expected): void
40+
{
41+
$this->assertSame($expected, $logLevel->toPsrLevel());
42+
}
43+
44+
/**
45+
* @dataProvider logLevelDataProvider
46+
*/
47+
public function testLogAndLogLevelConsistent(LogLevel $level, $expected): void
48+
{
49+
$log = new Log(1.0, '123', $level, 'foo');
50+
$this->assertSame($expected, $log->getPsrLevel());
51+
}
52+
53+
public function logLevelDataProvider(): \Generator
54+
{
55+
yield 'Debug -> Debug' => [LogLevel::debug(), \Psr\Log\LogLevel::DEBUG];
56+
yield 'Trace -> Debug' => [LogLevel::trace(), \Psr\Log\LogLevel::DEBUG];
57+
yield 'Info -> Info' => [LogLevel::info(), \Psr\Log\LogLevel::INFO];
58+
yield 'Warn -> Warning' => [LogLevel::warn(), \Psr\Log\LogLevel::WARNING];
59+
yield 'Error -> Error' => [LogLevel::error(), \Psr\Log\LogLevel::ERROR];
60+
yield 'Fatal -> Critical' => [LogLevel::fatal(), \Psr\Log\LogLevel::CRITICAL];
61+
}
3562
}

tests/Monolog/LogsHandlerTest.php

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,22 @@
77
use Monolog\Logger;
88
use PHPUnit\Framework\TestCase;
99
use Sentry\ClientBuilder;
10+
use Sentry\Event;
1011
use Sentry\Logs\Log;
1112
use Sentry\Logs\LogLevel;
1213
use Sentry\Logs\Logs;
1314
use Sentry\Monolog\LogsHandler;
1415
use Sentry\SentrySdk;
1516
use Sentry\State\Hub;
17+
use Sentry\Transport\Result;
18+
use Sentry\Transport\ResultStatus;
19+
use Sentry\Transport\TransportInterface;
1620

1721
final class LogsHandlerTest extends TestCase
1822
{
1923
protected function setUp(): void
2024
{
2125
Logs::getInstance()->flush();
22-
}
23-
24-
/**
25-
* @dataProvider handleDataProvider
26-
*/
27-
public function testHandle($record, Log $expectedLog): void
28-
{
2926
$client = ClientBuilder::create([
3027
'enable_logs' => true,
3128
'before_send' => static function () {
@@ -35,7 +32,13 @@ public function testHandle($record, Log $expectedLog): void
3532

3633
$hub = new Hub($client);
3734
SentrySdk::setCurrentHub($hub);
35+
}
3836

37+
/**
38+
* @dataProvider handleDataProvider
39+
*/
40+
public function testHandle($record, Log $expectedLog): void
41+
{
3942
$handler = new LogsHandler();
4043
$handler->handle($record);
4144

@@ -65,21 +68,79 @@ static function (string $key) {
6568
*/
6669
public function testLogLevels($record, int $countLogs): void
6770
{
71+
$handler = new LogsHandler(LogLevel::warn());
72+
$handler->handle($record);
73+
74+
$logs = Logs::getInstance()->aggregator()->all();
75+
$this->assertCount($countLogs, $logs);
76+
}
77+
78+
public function testLogsHandlerDestructor()
79+
{
80+
$transport = new class implements TransportInterface {
81+
private $events = [];
82+
83+
public function send(Event $event): Result
84+
{
85+
$this->events[] = $event;
86+
87+
return new Result(ResultStatus::success());
88+
}
89+
90+
public function close(?int $timeout = null): Result
91+
{
92+
return new Result(ResultStatus::success());
93+
}
94+
95+
/**
96+
* @return Event[]
97+
*/
98+
public function getEvents(): array
99+
{
100+
return $this->events;
101+
}
102+
};
68103
$client = ClientBuilder::create([
69104
'enable_logs' => true,
70-
'before_send' => static function () {
71-
return null;
72-
},
73-
])->getClient();
105+
])->setTransport($transport)
106+
->getClient();
74107

75108
$hub = new Hub($client);
76109
SentrySdk::setCurrentHub($hub);
77110

111+
$this->handleLogAndDrop();
112+
113+
$this->assertCount(1, $transport->getEvents());
114+
$this->assertSame('I was dropped :(', $transport->getEvents()[0]->getLogs()[0]->getBody());
115+
}
116+
117+
private function handleLogAndDrop(): void
118+
{
119+
$handler = new LogsHandler();
120+
$handler->handle(RecordFactory::create('I was dropped :(', Logger::INFO, 'chanel.foo', [], []));
121+
}
122+
123+
public function testOriginTagAppliedWithHandler(): void
124+
{
78125
$handler = new LogsHandler(LogLevel::warn());
79-
$handler->handle($record);
126+
$handler->handle(RecordFactory::create('with origin', Logger::WARNING, 'channel.foo', [], []));
80127

81128
$logs = Logs::getInstance()->aggregator()->all();
82-
$this->assertCount($countLogs, $logs);
129+
$this->assertCount(1, $logs);
130+
$log = $logs[0];
131+
$this->assertArrayHasKey('sentry.origin', $log->attributes()->toSimpleArray());
132+
$this->assertSame('auto.logger.monolog', $log->attributes()->toSimpleArray()['sentry.origin']);
133+
}
134+
135+
public function testOriginTagNotAppliedWhenUsingDirectly()
136+
{
137+
\Sentry\logger()->info('No origin attribute');
138+
139+
$logs = Logs::getInstance()->aggregator()->all();
140+
$this->assertCount(1, $logs);
141+
$log = $logs[0];
142+
$this->assertSame('No origin attribute', $log->getBody());
143+
$this->assertArrayNotHasKey('sentry.origin', $log->attributes()->toSimpleArray());
83144
}
84145

85146
public static function handleDataProvider(): iterable

0 commit comments

Comments
 (0)