woocommerce-pos
/
vendor_prefixed
/
sentry
/
sentry
/
src
/
Serializer
/
EnvelopItems
/
TransactionItem.php
TransactionItem.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.20, at vendor_prefixed/sentry/sentry/src/Serializer/EnvelopItems/TransactionItem.php
| 1 | <?php |
| 2 | |
| 3 | declare (strict_types=1); |
| 4 | namespace WCPOS\Vendor\Sentry\Serializer\EnvelopItems; |
| 5 | |
| 6 | use WCPOS\Vendor\Sentry\Attributes\Attribute; |
| 7 | use WCPOS\Vendor\Sentry\Attributes\AttributeBag; |
| 8 | use WCPOS\Vendor\Sentry\Event; |
| 9 | use WCPOS\Vendor\Sentry\EventType; |
| 10 | use WCPOS\Vendor\Sentry\Serializer\Traits\BreadcrumbSeralizerTrait; |
| 11 | use WCPOS\Vendor\Sentry\Tracing\Span; |
| 12 | use WCPOS\Vendor\Sentry\Tracing\SpanStatus; |
| 13 | use WCPOS\Vendor\Sentry\Tracing\TransactionMetadata; |
| 14 | use WCPOS\Vendor\Sentry\Util\JSON; |
| 15 | /** |
| 16 | * @internal |
| 17 | * |
| 18 | * @phpstan-type MetricsSummary array{ |
| 19 | * min: int|float, |
| 20 | * max: int|float, |
| 21 | * sum: int|float, |
| 22 | * count: int, |
| 23 | * tags: array<string>, |
| 24 | * } |
| 25 | */ |
| 26 | class TransactionItem implements EnvelopeItemInterface |
| 27 | { |
| 28 | use BreadcrumbSeralizerTrait; |
| 29 | public static function toEnvelopeItem(Event $event) : string |
| 30 | { |
| 31 | $transactionSpans = []; |
| 32 | $genAiSpans = []; |
| 33 | foreach ($event->getSpans() as $span) { |
| 34 | if (\strpos($span->getOp() ?? '', 'gen_ai.') === 0) { |
| 35 | $genAiSpans[] = $span; |
| 36 | } else { |
| 37 | $transactionSpans[] = $span; |
| 38 | } |
| 39 | } |
| 40 | $header = ['type' => (string) EventType::transaction(), 'content_type' => 'application/json']; |
| 41 | $payload = ['timestamp' => $event->getTimestamp(), 'platform' => 'php', 'sdk' => $event->getSdkPayload()]; |
| 42 | if ($event->getStartTimestamp() !== null) { |
| 43 | $payload['start_timestamp'] = $event->getStartTimestamp(); |
| 44 | } |
| 45 | if ($event->getLevel() !== null) { |
| 46 | $payload['level'] = (string) $event->getLevel(); |
| 47 | } |
| 48 | if ($event->getTransaction() !== null) { |
| 49 | $payload['transaction'] = $event->getTransaction(); |
| 50 | } |
| 51 | if ($event->getServerName() !== null) { |
| 52 | $payload['server_name'] = $event->getServerName(); |
| 53 | } |
| 54 | if ($event->getRelease() !== null) { |
| 55 | $payload['release'] = $event->getRelease(); |
| 56 | } |
| 57 | if ($event->getEnvironment() !== null) { |
| 58 | $payload['environment'] = $event->getEnvironment(); |
| 59 | } |
| 60 | if (!empty($event->getFingerprint())) { |
| 61 | $payload['fingerprint'] = $event->getFingerprint(); |
| 62 | } |
| 63 | if (!empty($event->getModules())) { |
| 64 | $payload['modules'] = $event->getModules(); |
| 65 | } |
| 66 | if (!empty($event->getExtra())) { |
| 67 | $payload['extra'] = $event->getExtra(); |
| 68 | } |
| 69 | if (!empty($event->getTags())) { |
| 70 | $payload['tags'] = $event->getTags(); |
| 71 | } |
| 72 | $user = $event->getUser(); |
| 73 | if ($user !== null) { |
| 74 | $payload['user'] = \array_merge($user->getMetadata(), ['id' => $user->getId(), 'username' => $user->getUsername(), 'email' => $user->getEmail(), 'ip_address' => $user->getIpAddress(), 'segment' => $user->getSegment()]); |
| 75 | } |
| 76 | $osContext = $event->getOsContext(); |
| 77 | if ($osContext !== null) { |
| 78 | $payload['contexts']['os'] = ['name' => $osContext->getName(), 'version' => $osContext->getVersion(), 'build' => $osContext->getBuild(), 'kernel_version' => $osContext->getKernelVersion()]; |
| 79 | } |
| 80 | $runtimeContext = $event->getRuntimeContext(); |
| 81 | if ($runtimeContext !== null) { |
| 82 | $payload['contexts']['runtime'] = ['name' => $runtimeContext->getName(), 'sapi' => $runtimeContext->getSAPI(), 'version' => $runtimeContext->getVersion()]; |
| 83 | } |
| 84 | if (!empty($event->getContexts())) { |
| 85 | $payload['contexts'] = \array_merge($payload['contexts'] ?? [], $event->getContexts()); |
| 86 | } |
| 87 | if (!empty($event->getBreadcrumbs())) { |
| 88 | $payload['breadcrumbs']['values'] = \array_map([self::class, 'serializeBreadcrumb'], $event->getBreadcrumbs()); |
| 89 | } |
| 90 | if (!empty($event->getRequest())) { |
| 91 | $payload['request'] = $event->getRequest(); |
| 92 | } |
| 93 | $payload['spans'] = \array_values(\array_map([self::class, 'serializeSpan'], $transactionSpans)); |
| 94 | $transactionMetadata = $event->getSdkMetadata('transaction_metadata'); |
| 95 | if ($transactionMetadata instanceof TransactionMetadata) { |
| 96 | $payload['transaction_info']['source'] = (string) $transactionMetadata->getSource(); |
| 97 | } |
| 98 | if (\count($genAiSpans) > 0) { |
| 99 | $genAi = []; |
| 100 | $genAi['items'] = \array_map(static function (Span $span) use($event) { |
| 101 | return self::serializeSpanV2($span, $event); |
| 102 | }, $genAiSpans); |
| 103 | $genAi['version'] = 2; |
| 104 | $genAiHeaders = ['type' => 'span', 'item_count' => \count($genAiSpans), 'content_type' => 'application/vnd.sentry.items.span.v2+json']; |
| 105 | return \sprintf("%s\n%s\n%s\n%s", JSON::encode($header), JSON::encode($payload), JSON::encode($genAiHeaders), JSON::encode($genAi)); |
| 106 | } |
| 107 | return \sprintf("%s\n%s", JSON::encode($header), JSON::encode($payload)); |
| 108 | } |
| 109 | /** |
| 110 | * @return array<string, mixed> |
| 111 | * |
| 112 | * @phpstan-return array{ |
| 113 | * span_id: string, |
| 114 | * trace_id: string, |
| 115 | * parent_span_id?: string, |
| 116 | * start_timestamp: float, |
| 117 | * timestamp?: float, |
| 118 | * status?: string, |
| 119 | * description?: string, |
| 120 | * op?: string, |
| 121 | * origin: string, |
| 122 | * data?: array<string, mixed>, |
| 123 | * tags?: array<string, string> |
| 124 | * } |
| 125 | */ |
| 126 | protected static function serializeSpan(Span $span) : array |
| 127 | { |
| 128 | $result = ['span_id' => (string) $span->getSpanId(), 'trace_id' => (string) $span->getTraceId(), 'start_timestamp' => $span->getStartTimestamp(), 'origin' => $span->getOrigin() ?? 'manual']; |
| 129 | if ($span->getParentSpanId() !== null) { |
| 130 | $result['parent_span_id'] = (string) $span->getParentSpanId(); |
| 131 | } |
| 132 | if ($span->getEndTimestamp() !== null) { |
| 133 | $result['timestamp'] = $span->getEndTimestamp(); |
| 134 | } |
| 135 | if ($span->getStatus() !== null) { |
| 136 | $result['status'] = (string) $span->getStatus(); |
| 137 | } |
| 138 | if ($span->getDescription() !== null) { |
| 139 | $result['description'] = $span->getDescription(); |
| 140 | } |
| 141 | if ($span->getOp() !== null) { |
| 142 | $result['op'] = $span->getOp(); |
| 143 | } |
| 144 | if (!empty($span->getData())) { |
| 145 | $result['data'] = $span->getData(); |
| 146 | } |
| 147 | if (!empty($span->getTags())) { |
| 148 | $result['tags'] = $span->getTags(); |
| 149 | } |
| 150 | return $result; |
| 151 | } |
| 152 | /** |
| 153 | * @return array<string, mixed> |
| 154 | * |
| 155 | * @phpstan-return array{ |
| 156 | * trace_id: string, |
| 157 | * span_id: string, |
| 158 | * name: string|null, |
| 159 | * is_segment: false, |
| 160 | * start_timestamp: float, |
| 161 | * attributes: array<string, mixed>, |
| 162 | * status: 'ok'|'error', |
| 163 | * end_timestamp?: float|null, |
| 164 | * parent_span_id?: string, |
| 165 | * } |
| 166 | */ |
| 167 | protected static function serializeSpanV2(Span $span, Event $event) : array |
| 168 | { |
| 169 | $result = ['trace_id' => (string) $span->getTraceId(), 'span_id' => (string) $span->getSpanId(), 'name' => $span->getDescription() ?? $span->getOp(), 'is_segment' => \false, 'start_timestamp' => $span->getStartTimestamp(), 'attributes' => \array_map(static function (Attribute $value) { |
| 170 | return ['type' => $value->getType(), 'value' => $value->getValue()]; |
| 171 | }, self::collectV2Attributes($span, $event)->all()), 'status' => 'ok']; |
| 172 | if ($span->getEndTimestamp() !== null) { |
| 173 | $result['end_timestamp'] = $span->getEndTimestamp(); |
| 174 | } |
| 175 | if ($span->getStatus() !== null) { |
| 176 | $result['status'] = $span->getStatus() === SpanStatus::ok() ? 'ok' : 'error'; |
| 177 | } |
| 178 | if ($span->getParentSpanId() !== null) { |
| 179 | $result['parent_span_id'] = (string) $span->getParentSpanId(); |
| 180 | } |
| 181 | return $result; |
| 182 | } |
| 183 | /*** |
| 184 | * @mago-ignore analysis:redundant-null-coalesce |
| 185 | * @mago-ignore analysis:mixed-assignment |
| 186 | */ |
| 187 | private static function collectV2Attributes(Span $span, Event $event) : AttributeBag |
| 188 | { |
| 189 | $attributes = new AttributeBag(); |
| 190 | $attributes->setUnlessNull('sentry.op', $span->getOp()); |
| 191 | $attributes->set('sentry.origin', $span->getOrigin() ?? 'manual'); |
| 192 | $attributes->setUnlessNull('sentry.release', $event->getRelease()); |
| 193 | $attributes->setUnlessNull('sentry.environment', $event->getEnvironment()); |
| 194 | $attributes->setUnlessNull('server.address', $event->getServerName()); |
| 195 | $attributes->setUnlessNull('sentry.segment.name', $event->getTransaction()); |
| 196 | $attributes->set('sentry.sdk.name', $event->getSdkPayload()['name'] ?? null); |
| 197 | $attributes->set('sentry.sdk.version', $event->getSdkPayload()['version'] ?? null); |
| 198 | $attributes->set('sentry.segment.id', $event->getContexts()['trace']['span_id'] ?? null); |
| 199 | foreach ($span->getTags() as $key => $value) { |
| 200 | $attributes->set($key, $value); |
| 201 | } |
| 202 | foreach ($span->getData() as $key => $value) { |
| 203 | $attributes->set($key, $value); |
| 204 | } |
| 205 | $attributes->forget('status'); |
| 206 | return $attributes; |
| 207 | } |
| 208 | } |
| 209 |