vendor/sentry/sentry/src/State/Scope.php line 378

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Sentry\State;
  4. use Sentry\Breadcrumb;
  5. use Sentry\Event;
  6. use Sentry\EventHint;
  7. use Sentry\Severity;
  8. use Sentry\Tracing\Span;
  9. use Sentry\Tracing\Transaction;
  10. use Sentry\UserDataBag;
  11. /**
  12.  * The scope holds data that should implicitly be sent with Sentry events. It
  13.  * can hold context data, extra parameters, level overrides, fingerprints etc.
  14.  */
  15. final class Scope
  16. {
  17.     /**
  18.      * @var Breadcrumb[] The list of breadcrumbs recorded in this scope
  19.      */
  20.     private $breadcrumbs = [];
  21.     /**
  22.      * @var UserDataBag|null The user data associated to this scope
  23.      */
  24.     private $user;
  25.     /**
  26.      * @var array<string, array<string, mixed>> The list of contexts associated to this scope
  27.      */
  28.     private $contexts = [];
  29.     /**
  30.      * @var array<string, string> The list of tags associated to this scope
  31.      */
  32.     private $tags = [];
  33.     /**
  34.      * @var array<string, mixed> A set of extra data associated to this scope
  35.      */
  36.     private $extra = [];
  37.     /**
  38.      * @var string[] List of fingerprints used to group events together in
  39.      *               Sentry
  40.      */
  41.     private $fingerprint = [];
  42.     /**
  43.      * @var Severity|null The severity to associate to the events captured in
  44.      *                    this scope
  45.      */
  46.     private $level;
  47.     /**
  48.      * @var callable[] List of event processors
  49.      *
  50.      * @psalm-var array<callable(Event, EventHint): ?Event>
  51.      */
  52.     private $eventProcessors = [];
  53.     /**
  54.      * @var Span|null Set a Span on the Scope
  55.      */
  56.     private $span;
  57.     /**
  58.      * @var callable[] List of event processors
  59.      *
  60.      * @psalm-var array<callable(Event, EventHint): ?Event>
  61.      */
  62.     private static $globalEventProcessors = [];
  63.     /**
  64.      * Sets a new tag in the tags context.
  65.      *
  66.      * @param string $key   The key that uniquely identifies the tag
  67.      * @param string $value The value
  68.      *
  69.      * @return $this
  70.      */
  71.     public function setTag(string $keystring $value): self
  72.     {
  73.         $this->tags[$key] = $value;
  74.         return $this;
  75.     }
  76.     /**
  77.      * Merges the given tags into the current tags context.
  78.      *
  79.      * @param array<string, string> $tags The tags to merge into the current context
  80.      *
  81.      * @return $this
  82.      */
  83.     public function setTags(array $tags): self
  84.     {
  85.         $this->tags array_merge($this->tags$tags);
  86.         return $this;
  87.     }
  88.     /**
  89.      * Removes a given tag from the tags context.
  90.      *
  91.      * @param string $key The key that uniquely identifies the tag
  92.      *
  93.      * @return $this
  94.      */
  95.     public function removeTag(string $key): self
  96.     {
  97.         unset($this->tags[$key]);
  98.         return $this;
  99.     }
  100.     /**
  101.      * Sets context data with the given name.
  102.      *
  103.      * @param string               $name  The name that uniquely identifies the context
  104.      * @param array<string, mixed> $value The value
  105.      *
  106.      * @return $this
  107.      */
  108.     public function setContext(string $name, array $value): self
  109.     {
  110.         $this->contexts[$name] = $value;
  111.         return $this;
  112.     }
  113.     /**
  114.      * Removes the context from the scope.
  115.      *
  116.      * @param string $name The name that uniquely identifies the context
  117.      *
  118.      * @return $this
  119.      */
  120.     public function removeContext(string $name): self
  121.     {
  122.         unset($this->contexts[$name]);
  123.         return $this;
  124.     }
  125.     /**
  126.      * Sets a new information in the extra context.
  127.      *
  128.      * @param string $key   The key that uniquely identifies the information
  129.      * @param mixed  $value The value
  130.      *
  131.      * @return $this
  132.      */
  133.     public function setExtra(string $key$value): self
  134.     {
  135.         $this->extra[$key] = $value;
  136.         return $this;
  137.     }
  138.     /**
  139.      * Merges the given data into the current extras context.
  140.      *
  141.      * @param array<string, mixed> $extras Data to merge into the current context
  142.      *
  143.      * @return $this
  144.      */
  145.     public function setExtras(array $extras): self
  146.     {
  147.         $this->extra array_merge($this->extra$extras);
  148.         return $this;
  149.     }
  150.     /**
  151.      * Get the user context.
  152.      */
  153.     public function getUser(): ?UserDataBag
  154.     {
  155.         return $this->user;
  156.     }
  157.     /**
  158.      * Merges the given data in the user context.
  159.      *
  160.      * @param array<string, mixed>|UserDataBag $user The user data
  161.      *
  162.      * @return $this
  163.      */
  164.     public function setUser($user): self
  165.     {
  166.         if (!\is_array($user) && !$user instanceof UserDataBag) {
  167.             throw new \TypeError(sprintf('The $user argument must be either an array or an instance of the "%s" class. Got: "%s".'UserDataBag::class, get_debug_type($user)));
  168.         }
  169.         if (\is_array($user)) {
  170.             $user UserDataBag::createFromArray($user);
  171.         }
  172.         if (null === $this->user) {
  173.             $this->user $user;
  174.         } else {
  175.             $this->user $this->user->merge($user);
  176.         }
  177.         return $this;
  178.     }
  179.     /**
  180.      * Removes all data of the user context.
  181.      *
  182.      * @return $this
  183.      */
  184.     public function removeUser(): self
  185.     {
  186.         $this->user null;
  187.         return $this;
  188.     }
  189.     /**
  190.      * Sets the list of strings used to dictate the deduplication of this event.
  191.      *
  192.      * @param string[] $fingerprint The fingerprint values
  193.      *
  194.      * @return $this
  195.      */
  196.     public function setFingerprint(array $fingerprint): self
  197.     {
  198.         $this->fingerprint $fingerprint;
  199.         return $this;
  200.     }
  201.     /**
  202.      * Sets the severity to apply to all events captured in this scope.
  203.      *
  204.      * @param Severity|null $level The severity
  205.      *
  206.      * @return $this
  207.      */
  208.     public function setLevel(?Severity $level): self
  209.     {
  210.         $this->level $level;
  211.         return $this;
  212.     }
  213.     /**
  214.      * Add the given breadcrumb to the scope.
  215.      *
  216.      * @param Breadcrumb $breadcrumb     The breadcrumb to add
  217.      * @param int        $maxBreadcrumbs The maximum number of breadcrumbs to record
  218.      *
  219.      * @return $this
  220.      */
  221.     public function addBreadcrumb(Breadcrumb $breadcrumbint $maxBreadcrumbs 100): self
  222.     {
  223.         $this->breadcrumbs[] = $breadcrumb;
  224.         $this->breadcrumbs \array_slice($this->breadcrumbs, -$maxBreadcrumbs);
  225.         return $this;
  226.     }
  227.     /**
  228.      * Clears all the breadcrumbs.
  229.      *
  230.      * @return $this
  231.      */
  232.     public function clearBreadcrumbs(): self
  233.     {
  234.         $this->breadcrumbs = [];
  235.         return $this;
  236.     }
  237.     /**
  238.      * Adds a new event processor that will be called after {@see Scope::applyToEvent}
  239.      * finished its work.
  240.      *
  241.      * @param callable $eventProcessor The event processor
  242.      *
  243.      * @return $this
  244.      */
  245.     public function addEventProcessor(callable $eventProcessor): self
  246.     {
  247.         $this->eventProcessors[] = $eventProcessor;
  248.         return $this;
  249.     }
  250.     /**
  251.      * Adds a new event processor that will be called after {@see Scope::applyToEvent}
  252.      * finished its work.
  253.      *
  254.      * @param callable $eventProcessor The event processor
  255.      */
  256.     public static function addGlobalEventProcessor(callable $eventProcessor): void
  257.     {
  258.         self::$globalEventProcessors[] = $eventProcessor;
  259.     }
  260.     /**
  261.      * Clears the scope and resets any data it contains.
  262.      *
  263.      * @return $this
  264.      */
  265.     public function clear(): self
  266.     {
  267.         $this->user null;
  268.         $this->level null;
  269.         $this->span null;
  270.         $this->fingerprint = [];
  271.         $this->breadcrumbs = [];
  272.         $this->tags = [];
  273.         $this->extra = [];
  274.         $this->contexts = [];
  275.         return $this;
  276.     }
  277.     /**
  278.      * Applies the current context and fingerprint to the event. If the event has
  279.      * already some breadcrumbs on it, the ones from this scope won't get merged.
  280.      *
  281.      * @param Event $event The event object that will be enriched with scope data
  282.      */
  283.     public function applyToEvent(Event $event, ?EventHint $hint null): ?Event
  284.     {
  285.         $event->setFingerprint(array_merge($event->getFingerprint(), $this->fingerprint));
  286.         if (empty($event->getBreadcrumbs())) {
  287.             $event->setBreadcrumb($this->breadcrumbs);
  288.         }
  289.         if (null !== $this->level) {
  290.             $event->setLevel($this->level);
  291.         }
  292.         if (!empty($this->tags)) {
  293.             $event->setTags(array_merge($this->tags$event->getTags()));
  294.         }
  295.         if (!empty($this->extra)) {
  296.             $event->setExtra(array_merge($this->extra$event->getExtra()));
  297.         }
  298.         if (null !== $this->user) {
  299.             $user $event->getUser();
  300.             if (null === $user) {
  301.                 $user $this->user;
  302.             } else {
  303.                 $user $this->user->merge($user);
  304.             }
  305.             $event->setUser($user);
  306.         }
  307.         // We do this here to also apply the trace context to errors if there is a Span on the Scope
  308.         if (null !== $this->span) {
  309.             $event->setContext('trace'$this->span->getTraceContext());
  310.         }
  311.         foreach (array_merge($this->contexts$event->getContexts()) as $name => $data) {
  312.             $event->setContext($name$data);
  313.         }
  314.         // We create a empty `EventHint` instance to allow processors to always receive a `EventHint` instance even if there wasn't one
  315.         if (null === $hint) {
  316.             $hint = new EventHint();
  317.         }
  318.         foreach (array_merge(self::$globalEventProcessors$this->eventProcessors) as $processor) {
  319.             $event $processor($event$hint);
  320.             if (null === $event) {
  321.                 return null;
  322.             }
  323.             if (!$event instanceof Event) {
  324.                 throw new \InvalidArgumentException(sprintf('The event processor must return null or an instance of the %s class'Event::class));
  325.             }
  326.         }
  327.         return $event;
  328.     }
  329.     /**
  330.      * Returns the span that is on the scope.
  331.      */
  332.     public function getSpan(): ?Span
  333.     {
  334.         return $this->span;
  335.     }
  336.     /**
  337.      * Sets the span on the scope.
  338.      *
  339.      * @param Span|null $span The span
  340.      *
  341.      * @return $this
  342.      */
  343.     public function setSpan(?Span $span): self
  344.     {
  345.         $this->span $span;
  346.         return $this;
  347.     }
  348.     /**
  349.      * Returns the transaction attached to the scope (if there is one).
  350.      */
  351.     public function getTransaction(): ?Transaction
  352.     {
  353.         if (null !== $this->span) {
  354.             return $this->span->getTransaction();
  355.         }
  356.         return null;
  357.     }
  358.     public function __clone()
  359.     {
  360.         if (null !== $this->user) {
  361.             $this->user = clone $this->user;
  362.         }
  363.     }
  364. }