Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c7ec648
Add Sentry logs
cleptric Mar 21, 2025
1c1359e
Use new envelope item
cleptric Apr 16, 2025
f43e007
CS
cleptric Apr 16, 2025
5f25685
Add all log levels
cleptric Apr 16, 2025
3dde07e
Add some default attributes
cleptric Apr 16, 2025
72a9276
Fix span id
cleptric Apr 16, 2025
9720cc6
Expose more log levles
cleptric Apr 16, 2025
478a2e7
Add new data category for logs event
stayallive May 7, 2025
ad9a7a3
Add options for logs
stayallive May 7, 2025
bb89b44
CS
stayallive May 7, 2025
f2a6d21
Refactor logs to use it’s own object
stayallive May 7, 2025
7eaf2e4
Introduce LogAttribute object
stayallive May 7, 2025
081359a
Document new options
stayallive May 7, 2025
700359e
Use micro seconds
cleptric May 9, 2025
a2aa0b7
Merge branch 'master' into logs
cleptric May 9, 2025
f79da3c
CS
cleptric May 9, 2025
57100ee
CS
stayallive May 12, 2025
2248913
Allow user to pass values and attributes
stayallive May 12, 2025
629f86a
Add some initial tests
stayallive May 12, 2025
bd54398
Add a PSR logger that logs to logs
stayallive May 12, 2025
f588951
Merge branch 'master' into logs
stayallive May 13, 2025
302b6be
Use different expectations based on the PHP version
stayallive May 13, 2025
f16a4f8
More refactorings
stayallive May 13, 2025
b9f485d
Ensure we follow the propper SDK behavior
stayallive May 13, 2025
e8f9025
Refactor attributes to be re-usable
stayallive May 15, 2025
1b6bdca
Prevent logging to ourself
stayallive May 15, 2025
d62da81
Increase API surface for attributes and tests
stayallive May 15, 2025
f210459
Add attribute bag tests
stayallive May 15, 2025
2b23aee
When sending an event, also send pending logs
stayallive May 15, 2025
dcd5a8c
Merge branch 'master' into logs
stayallive May 15, 2025
1487ccc
CS
stayallive May 15, 2025
7c1a6b6
Prefix logs logs
stayallive May 15, 2025
1c47d1c
Append `$context` in debug loggers to output
stayallive May 15, 2025
5f6ddb6
phpstan
stayallive May 20, 2025
1578fa5
Flatten attributes passed for logs
stayallive May 20, 2025
9d42e0f
Polyfill `array_is_list`
stayallive May 20, 2025
6befa35
Try to get trace ID from span first
stayallive May 21, 2025
1bdc502
Simplify getting the trace ID
stayallive May 21, 2025
9f28a68
Merge branch 'master' into logs
cleptric May 22, 2025
ae308e8
Log if we don’t log
stayallive May 22, 2025
a12e912
Do not flush logs with other events
stayallive May 22, 2025
d6860a0
Add test
stayallive May 22, 2025
654ee8c
Remove invalid test case
stayallive May 22, 2025
219cd07
CS
stayallive May 22, 2025
3f91e30
Fix typo
stayallive May 22, 2025
0fc9daa
Remove unused logger class
stayallive May 22, 2025
f835832
Add getter for aggregator used in other SDKs
stayallive May 22, 2025
bef3448
Remove type check on removed class
stayallive May 22, 2025
1be4b5d
CS
stayallive May 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,7 @@ parameters:
-
message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#"
count: 1
path: src/Logger/DebugFileLogger.php

-
message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#"
count: 1
path: src/Logger/DebugStdOutLogger.php
path: src/Logger/DebugLogger.php

-
message: "#^Parameter \\#1 \\$level of method Monolog\\\\Handler\\\\AbstractHandler\\:\\:__construct\\(\\) expects 100\\|200\\|250\\|300\\|400\\|500\\|550\\|600\\|'ALERT'\\|'alert'\\|'CRITICAL'\\|'critical'\\|'DEBUG'\\|'debug'\\|'EMERGENCY'\\|'emergency'\\|'ERROR'\\|'error'\\|'INFO'\\|'info'\\|'NOTICE'\\|'notice'\\|'WARNING'\\|'warning'\\|Monolog\\\\Level, int\\|Monolog\\\\Level\\|string given\\.$#"
Expand All @@ -80,6 +75,11 @@ parameters:
count: 1
path: src/Options.php

-
message: "#^Method Sentry\\\\Options\\:\\:getBeforeSendLogCallback\\(\\) should return callable\\(Sentry\\\\Logs\\\\Log\\)\\: \\(Sentry\\\\Logs\\\\Log\\|null\\) but returns mixed\\.$#"
count: 1
path: src/Options.php

-
message: "#^Method Sentry\\\\Options\\:\\:getBeforeSendMetricsCallback\\(\\) should return callable\\(Sentry\\\\Event, Sentry\\\\EventHint\\|null\\)\\: \\(Sentry\\\\Event\\|null\\) but returns mixed\\.$#"
count: 1
Expand All @@ -105,6 +105,11 @@ parameters:
count: 1
path: src/Options.php

-
message: "#^Method Sentry\\\\Options\\:\\:getEnableLogs\\(\\) should return bool but returns mixed\\.$#"
count: 1
path: src/Options.php

-
message: "#^Method Sentry\\\\Options\\:\\:getEnableTracing\\(\\) should return bool\\|null but returns mixed\\.$#"
count: 1
Expand Down
126 changes: 126 additions & 0 deletions src/Attributes/Attribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

declare(strict_types=1);

namespace Sentry\Attributes;

/**
* @phpstan-type AttributeType 'string'|'boolean'|'integer'|'double'
* @phpstan-type AttributeValue string|bool|int|float
* @phpstan-type AttributeSerialized array{
* type: AttributeType,
* value: AttributeValue
* }
*/
class Attribute implements \JsonSerializable
{
/**
* @var AttributeType
*/
private $type;

/**
* @var AttributeValue
*/
private $value;

/**
* @param AttributeValue $value
* @param AttributeType $type
*/
public function __construct($value, string $type)
{
$this->value = $value;
$this->type = $type;
}

/**
* @return AttributeType
*/
public function getType(): string
{
return $this->type;
}

/**
* @return AttributeValue
*/
public function getValue()
{
return $this->value;
}

/**
* @param mixed $value
*
* @throws \InvalidArgumentException thrown when the value cannot be serialized as an attribute
*/
public static function fromValue($value): self
{
$attribute = self::tryFromValue($value);

if ($attribute === null) {
throw new \InvalidArgumentException(\sprintf('Invalid attribute value, %s cannot be serialized', \gettype($value)));
}

return $attribute;
}

/**
* @param mixed $value
*/
public static function tryFromValue($value): ?self
{
if ($value === null) {
return null;
}

if (\is_bool($value)) {
return new self($value, 'boolean');
}

if (\is_int($value)) {
return new self($value, 'integer');
}

if (\is_float($value)) {
return new self($value, 'double');
}

if (\is_string($value) || (\is_object($value) && method_exists($value, '__toString'))) {
$stringValue = (string) $value;

if (empty($stringValue)) {
return null;
}

return new self($stringValue, 'string');
}

return null;
}

/**
* @return AttributeSerialized
*/
public function toArray(): array
{
return [
'type' => $this->type,
'value' => $this->value,
];
}

/**
* @return AttributeSerialized
*/
public function jsonSerialize(): array
{
return $this->toArray();
}

public function __toString(): string
{
return "{$this->value} ({$this->type})";
}
}
74 changes: 74 additions & 0 deletions src/Attributes/AttributeBag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

declare(strict_types=1);

namespace Sentry\Attributes;

/**
* @phpstan-import-type AttributeValue from Attribute
* @phpstan-import-type AttributeSerialized from Attribute
*/
class AttributeBag implements \JsonSerializable
{
/**
* @var array<string, Attribute>
*/
private $attributes = [];

/**
* @param mixed $value
*/
public function set(string $key, $value): self
{
$attribute = $value instanceof Attribute
? $value
: Attribute::tryFromValue($value);

if ($attribute !== null) {
$this->attributes[$key] = $attribute;
}

return $this;
}

public function get(string $key): ?Attribute
{
return $this->attributes[$key] ?? null;
}

/**
* @return array<string, Attribute>
*/
public function all(): array
{
return $this->attributes;
}

/**
* @return array<string, AttributeSerialized>
*/
public function toArray(): array
{
return array_map(static function (Attribute $attribute) {
return $attribute->jsonSerialize();
}, $this->attributes);
}

/**
* @return array<string, AttributeSerialized>
*/
public function jsonSerialize(): array
{
return $this->toArray();
}

/**
* @return array<string, AttributeValue>
*/
public function toSimpleArray(): array
{
return array_map(static function (Attribute $attribute) {
return $attribute->getValue();
}, $this->attributes);
}
}
11 changes: 11 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,16 @@ public function getTransport(): TransportInterface
return $this->transport;
}

public function getSdkIdentifier(): string
{
return $this->sdkIdentifier;
}

public function getSdkVersion(): string
{
return $this->sdkVersion;
}

/**
* Assembles an event and prepares it to be sent of to Sentry.
*
Expand All @@ -280,6 +290,7 @@ private function prepareEvent(Event $event, ?EventHint $hint = null, ?Scope $sco

$event->setSdkIdentifier($this->sdkIdentifier);
$event->setSdkVersion($this->sdkVersion);

$event->setTags(array_merge($this->options->getTags(), $event->getTags()));

if ($event->getServerName() === null) {
Expand Down
29 changes: 29 additions & 0 deletions src/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Sentry\Context\OsContext;
use Sentry\Context\RuntimeContext;
use Sentry\Logs\Log;
use Sentry\Profiling\Profile;
use Sentry\Tracing\Span;

Expand Down Expand Up @@ -65,6 +66,11 @@ final class Event
*/
private $checkIn;

/**
* @var Log[]
*/
private $logs = [];

/**
* @var string|null The name of the server (e.g. the host name)
*/
Expand Down Expand Up @@ -230,6 +236,11 @@ public static function createCheckIn(?EventId $eventId = null): self
return new self($eventId, EventType::checkIn());
}

public static function createLogs(?EventId $eventId = null): self
{
return new self($eventId, EventType::logs());
}

/**
* @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x.
*/
Expand Down Expand Up @@ -416,6 +427,24 @@ public function setCheckIn(?CheckIn $checkIn): self
return $this;
}

/**
* @return Log[]
*/
public function getLogs(): array
{
return $this->logs;
}

/**
* @param Log[] $logs
*/
public function setLogs(array $logs): self
{
$this->logs = $logs;

return $this;
}

/**
* @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/EventType.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public static function checkIn(): self
return self::getInstance('check_in');
}

public static function logs(): self
{
return self::getInstance('log');
}

/**
* @deprecated Metrics are no longer supported. Metrics API is a no-op and will be removed in 5.x.
*/
Expand All @@ -61,6 +66,7 @@ public static function cases(): array
self::event(),
self::transaction(),
self::checkIn(),
self::logs(),
self::metrics(),
];
}
Expand Down
13 changes: 3 additions & 10 deletions src/Logger/DebugFileLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

namespace Sentry\Logger;

use Psr\Log\AbstractLogger;

class DebugFileLogger extends AbstractLogger
class DebugFileLogger extends DebugLogger
{
/**
* @var string
Expand All @@ -18,13 +16,8 @@ public function __construct(string $filePath)
$this->filePath = $filePath;
}

/**
* @param mixed $level
* @param string|\Stringable $message
* @param mixed[] $context
*/
public function log($level, $message, array $context = []): void
public function write(string $message): void
{
file_put_contents($this->filePath, \sprintf("sentry/sentry: [%s] %s\n", $level, (string) $message), \FILE_APPEND);
file_put_contents($this->filePath, $message, \FILE_APPEND);
}
}
26 changes: 26 additions & 0 deletions src/Logger/DebugLogger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Sentry\Logger;

use Psr\Log\AbstractLogger;

abstract class DebugLogger extends AbstractLogger
{
/**
* @param mixed $level
* @param string|\Stringable $message
* @param mixed[] $context
*/
public function log($level, $message, array $context = []): void
{
$formattedMessageAndContext = implode(' ', array_filter([(string) $message, json_encode($context)]));

$this->write(
\sprintf("sentry/sentry: [%s] %s\n", $level, $formattedMessageAndContext)
);
}

abstract public function write(string $message): void;
}
Loading