agent/php/ElasticApm/Impl/InferredSpanFrame.php (98 lines of code) (raw):

<?php /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ declare(strict_types=1); namespace Elastic\Apm\Impl; use Elastic\Apm\Impl\BackendComm\SerializationUtil; use Elastic\Apm\Impl\Log\LoggableInterface; use Elastic\Apm\Impl\Log\LoggableTrait; use Elastic\Apm\Impl\Log\LoggerFactory; use Elastic\Apm\Impl\Util\ClassicFormatStackTraceFrame; use Elastic\Apm\Impl\Util\ClassNameUtil; use Elastic\Apm\Impl\Util\IdGenerator; use Elastic\Apm\Impl\Util\StackTraceUtil; use Elastic\Apm\Impl\Util\TimeUtil; /** * Code in this file is part of implementation internals and thus it is not covered by the backward compatibility. * * @internal */ final class InferredSpanFrame implements SpanToSendInterface, LoggableInterface { use LoggableTrait; private const SPAN_TYPE = 'inferred'; private const UNKNOWN_SPAN_NAME = 'unknown inferred span'; /** @var float */ public $timestamp; /** @var float Monotonic time since some unspecified starting point, in microseconds */ private $monotonicBeginTime; /** @var ClassicFormatStackTraceFrame */ public $stackFrame; /** @var ?float In milliseconds with 3 decimal points */ public $duration = null; /** @var ?string */ public $traceId = null; /** @var ?string */ public $parentId = null; /** @var ?string */ public $transactionId = null; /** @var ?string */ public $id = null; /** @var ?string */ public $name = null; /** @var ?string */ public $type = null; /** * @var ?float * * @see ExecutionSegment::$sampleRate */ public $sampleRate = null; /** @var null|StackTraceFrame[] */ public $stackTrace = null; public function __construct(float $systemClockBeginTime, float $monotonicBeginTime, ClassicFormatStackTraceFrame $stackFrame) { $this->timestamp = $systemClockBeginTime; $this->monotonicBeginTime = $monotonicBeginTime; $this->stackFrame = $stackFrame; } /** * @param ClassicFormatStackTraceFrame $stackFrame * * @return bool */ public function canBeExtendedWith(ClassicFormatStackTraceFrame $stackFrame): bool { return $this->stackFrame->class === $stackFrame->class && $this->stackFrame->function === $stackFrame->function && $this->stackFrame->file === $stackFrame->file; } public function setEndTime(float $systemClockEndTime, float $monotonicEndTime, LoggerFactory $loggerFactory): void { $durationInMicroseconds = ExecutionSegment::calcDurationInMicroseconds( $this->timestamp /* <- systemClockBeginTime */, $this->monotonicBeginTime, $systemClockEndTime, $monotonicEndTime, $loggerFactory ); $this->duration = TimeUtil::microsecondsToMilliseconds($durationInMicroseconds); } public function markAsAllocatedToBeSent(): string { if ($this->id === null) { $this->id = IdGenerator::generateId(Constants::EXECUTION_SEGMENT_ID_SIZE_IN_BYTES); } return $this->id; } public function isAllocatedToBeSent(): bool { return $this->id !== null; } /** * @param Transaction $transaction * @param string $parentId * @param null|StackTraceFrame[] $stackTrace */ public function prepareForSerialization(Transaction $transaction, string $parentId, ?array $stackTrace): void { $this->traceId = $transaction->getTraceId(); $this->transactionId = $transaction->getId(); $this->parentId = $parentId; $this->sampleRate = $transaction->sampleRate; $this->stackTrace = $stackTrace; } /** @inheritDoc */ public function jsonSerialize() { $result = []; /** * ClassNameUtil::fqToShort requires class-string * * @phpstan-ignore-next-line */ $shortClassName = $this->stackFrame->class === null ? null : ClassNameUtil::fqToShort($this->stackFrame->class); $this->name = StackTraceUtil::buildApmFormatFunctionForClassMethod($shortClassName, $this->stackFrame->isStaticMethod, $this->stackFrame->function); if ($this->name === null) { if ($this->stackFrame->file !== null && $this->stackFrame->line !== null) { $this->name = $this->stackFrame->file . ':' . $this->stackFrame->line; } else { $this->name = self::UNKNOWN_SPAN_NAME; } } SerializationUtil::addNameValue('name', $this->name, /* ref */ $result); $this->type = self::SPAN_TYPE; SerializationUtil::addNameValue('type', $this->type, /* ref */ $result); SerializationUtil::addNameValueAssumeNotNull('id', $this->id, /* ref */ $result); SerializationUtil::addNameValueAssumeNotNull('trace_id', $this->traceId, /* ref */ $result); SerializationUtil::addNameValueAssumeNotNull('transaction_id', $this->transactionId, /* ref */ $result); SerializationUtil::addNameValueAssumeNotNull('parent_id', $this->parentId, /* ref */ $result); $timestamp = SerializationUtil::adaptTimestamp($this->timestamp); SerializationUtil::addNameValue('timestamp', $timestamp, /* ref */ $result); SerializationUtil::addNameValueAssumeNotNull('duration', $this->duration, /* ref */ $result); SerializationUtil::addNameValueIfNotNull('sample_rate', $this->sampleRate, /* ref */ $result); SerializationUtil::addNameValueIfNotNull('stacktrace', $this->stackTrace, /* ref */ $result); return $result; } }