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;
}
}