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

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