Make `AttributesInterface` immutable (#724)

* Cleanup `AttributesInterface`
- remove not required methods
- rename `::hasAttribute()` to `::has()` for consistency with `::get()`
* Remove public usage of `new Attributes()`
* Split `Attributes` into immutable attributes and mutable builder
* Remove `AttributesLimits`
* Remove `::incrementDroppedAttributesCount()` for now
Mainly useful for metrics sdk that has to rebuild filtered attributes.
* Remove obsolete cloning of attributes
* Update covers annotation
* Revert optional changes that might be controversial
This commit is contained in:
Tobias Bachert 2022-06-23 12:54:03 +02:00 committed by GitHub
parent 025b239adc
commit 41f74d2aff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 542 additions and 794 deletions

View File

@ -5,7 +5,6 @@ require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOffSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
@ -24,18 +23,18 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
->getTracer('io.opentelemetry.contrib.php');
// start a span, register some events
$span = $tracer->startAndActivateSpan('session.generate');
$span = $tracer->spanBuilder('session.generate')->startSpan();
$span->setAttribute('remote_ip', '1.2.3.4');
$span->setAttribute('country', 'USA');
$timestamp = ClockFactory::getDefault()->timestamp();
$span->addEvent('found_login', new Attributes([
$timestamp = ClockFactory::getDefault()->now();
$span->addEvent('found_login', [
'id' => 12345,
'username' => 'otuser',
]), $timestamp);
$span->addEvent('generated_session', new Attributes([
], $timestamp);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]), $timestamp);
], $timestamp);
$span->end(); // pass status as an optional argument
print_r($span); // print the span as a resulting output

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\Contrib\Jaeger\Exporter as JaegerExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
@ -36,13 +35,13 @@ for ($i = 0; $i < 5; $i++) {
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]));
$span->addEvent('generated_session', new Attributes([
]);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]));
]);
try {
throw new Exception('Record exception test event');

View File

@ -6,15 +6,14 @@ require __DIR__ . '/../vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\Contrib\Jaeger\AgentExporter;
use OpenTelemetry\SDK\Attributes;
use OpenTelemetry\SDK\GlobalLoggerHolder;
use OpenTelemetry\SDK\Common\Log\LoggerHolder;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
use Psr\Log\LogLevel;
$logger = new Logger('otel-php', [new StreamHandler(STDOUT, LogLevel::DEBUG)]);
GlobalLoggerHolder::set($logger);
LoggerHolder::set($logger);
$exporter = new AgentExporter('jaeger-thrift', 'jaeger:6831');
$tracerProvider = new TracerProvider(
@ -49,13 +48,13 @@ for ($i = 0; $i < 1; $i++) {
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]));
$span->addEvent('generated_session', new Attributes([
]);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]));
]);
try {
throw new Exception('Record exception test event');

View File

@ -8,7 +8,6 @@ use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\Newrelic\Exporter as NewrelicExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
@ -61,33 +60,30 @@ $newrelicExporter = new NewrelicExporter(
if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
echo 'Starting AlwaysOnNewrelicExample';
$tracer = (new TracerProvider())
->addSpanProcessor(new SimpleSpanProcessor($newrelicExporter))
$tracer = (new TracerProvider(new SimpleSpanProcessor($newrelicExporter)))
->getTracer('io.opentelemetry.contrib.php');
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->startAndActivateSpan('session.generate.span.' . microtime(true));
$span = $tracer->spanBuilder('session.generate.span.' . microtime(true))->startSpan();
$spanParent = $span->getParentContext();
echo sprintf(
PHP_EOL . 'Exporting Trace: %s, Parent: %s, Span: %s',
PHP_EOL . 'Exporting Trace: %s, Span: %s',
$span->getContext()->getTraceId(),
$spanParent ? $spanParent->getSpanId() : 'None',
$span->getContext()->getSpanId()
);
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]), $timestamp);
$span->addEvent('generated_session', new Attributes([
], $timestamp);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]), $timestamp);
], $timestamp);
$span->end();
}

View File

@ -6,7 +6,6 @@ require __DIR__ . '/../vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\Contrib\OtlpHttp\Exporter as OTLPExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
@ -36,13 +35,13 @@ for ($i = 0; $i < 3; $i++) {
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]));
$span->addEvent('generated_session', new Attributes([
]);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]));
]);
$span->end();
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\Contrib\OtlpGrpc\Exporter as OTLPGrpcExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
@ -29,13 +28,13 @@ for ($i = 0; $i < 3; $i++) {
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]));
$span->addEvent('generated_session', new Attributes([
]);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]));
]);
$span->end();
}

View File

@ -6,7 +6,6 @@ require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\OtlpGrpc\Exporter as OTLPExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
@ -25,17 +24,19 @@ $Exporter = new OTLPExporter();
if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
echo 'Starting OTLPGrpcExample';
$tracer = (new TracerProvider())
->addSpanProcessor(new SimpleSpanProcessor($Exporter))
$tracer = (new TracerProvider(new SimpleSpanProcessor($Exporter)))
->getTracer('io.opentelemetry.contrib.php');
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->startAndActivateSpan('session.generate.span' . microtime(true));
$span = $tracer->spanBuilder('session.generate.span' . microtime(true))->startSpan();
//startAndActivateSpan('session.generate.span.' . microtime(true));
$childSpan = $tracer->startSpan('child');
$childSpan = $tracer
->spanBuilder('child')
->setParent($span->storeInContext(Context::getCurrent()))
->startSpan();
// Temporarily setting service name here. It should eventually be pulled from tracer.resources.
$span->setAttribute('service.name', 'alwaysOnOTLPGrpcExample');
@ -43,13 +44,13 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]), $timestamp);
$span->addEvent('generated_session', new Attributes([
], $timestamp);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]), $timestamp);
], $timestamp);
// temporarily setting service name here. It should eventually be pulled from tracer.resources.
$childSpan->setAttribute('service.name', 'alwaysOnOTLPGrpcExample');
@ -57,10 +58,10 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
$childSpan->setAttribute('attr_one', 'one')
->setAttribute('attr_two', 'two');
$childSpan->addEvent('found_event1' . $i, new Attributes([
$childSpan->addEvent('found_event1' . $i, [
'id' => $i,
'username' => 'child' . $i,
]), $timestamp);
], $timestamp);
$childSpan->end();
$span->end();

View File

@ -6,7 +6,6 @@ require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\OtlpGrpc\Exporter as OTLPExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
@ -25,10 +24,12 @@ $Exporter = new OTLPExporter();
if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
echo 'Starting OTLPGrpcExample';
$tracer = (new TracerProvider())
->addSpanProcessor(new SimpleSpanProcessor($Exporter))
$tracer = (new TracerProvider(new SimpleSpanProcessor($Exporter)))
->getTracer('io.opentelemetry.contrib.php');
$rootSpan = $tracer->startSpan('root-span', null, API\SpanKind::KIND_SERVER);
$rootSpan = $tracer
->spanBuilder('root-span')
->setSpanKind(API\SpanKind::KIND_SERVER)
->startSpan();
// temporarily setting service name here. It should eventually be pulled from tracer.resources.
$rootSpan->setAttribute('service.name', 'alwaysOnOTLPGrpcExample');
@ -36,24 +37,30 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
$rootSpan->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$timestamp = ClockFactory::getDefault()->now();
$rootSpan->addEvent('found_login', new Attributes([
$rootSpan->addEvent('found_login', [
'id' => 1,
'username' => 'otuser',
]), $timestamp);
$rootSpan->addEvent('generated_session', new Attributes([
], $timestamp);
$rootSpan->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]), $timestamp);
], $timestamp);
sleep(1);
$rootScope = $rootSpan->activate(); // set the root span active in the current context
try {
$span1 = $tracer->startSpan('child-span-1', null, API\SpanKind::KIND_SERVER);
$span1 = $tracer
->spanBuilder('child-span-1')
->setSpanKind(API\SpanKind::KIND_SERVER)
->startSpan();
$internalScope = $span1->activate(); // set the child span active in the context
try {
for ($i = 0; $i < 3; $i++) {
$loopSpan = $tracer->startSpan('loop-' . $i, null, API\SpanKind::KIND_CLIENT);
$loopSpan = $tracer
->spanBuilder('loop-' . $i)
->setSpanKind(API\SpanKind::KIND_CLIENT)
->startSpan();
$loopSpan->setAttribute('db.statement', 'select foo from bar');
$loopSpan->setAttribute('db.system', 'mysql');
$loopSpan->setAttribute('db.query', 'select foo from bar');
@ -61,31 +68,40 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
$loopSpan->end();
}
} finally {
$internalScope->close(); // deactivate child span, the rootSpan is set back as active
$internalScope->detach(); // deactivate child span, the rootSpan is set back as active
}
$span1->end();
$span2 = $tracer->startSpan('child-span-2', null, API\SpanKind::KIND_SERVER);
$span2 = $tracer
->spanBuilder('child-span-2')
->setSpanKind(API\SpanKind::KIND_SERVER)
->startSpan();
$span2->setAttribute('error.message', 'this is an error');
$span2->setAttribute('error.class', 'error.class.this.is');
sleep(1);
$internalScope = $span2->activate(); // set the child span active in the context
try {
$internalSpan = $tracer->startSpan('internal', null, API\SpanKind::KIND_CLIENT);
$internalSpan = $tracer
->spanBuilder('internal')
->setSpanKind(API\SpanKind::KIND_CLIENT)
->startSpan();
usleep((int) (0.5 * 1e6));
$internalSpan->end();
$internalSpan = $tracer->startSpan('external', null, API\SpanKind::KIND_CLIENT);
$internalSpan = $tracer
->spanBuilder('external')
->setSpanKind(API\SpanKind::KIND_CLIENT)
->startSpan();
usleep((int) (0.5 * 1e6));
$internalSpan->setAttribute('http.method', 'GET');
$internalSpan->end();
} finally {
$internalScope->close(); // deactivate child span, the rootSpan is set back as active
$internalScope->detach(); // deactivate child span, the rootSpan is set back as active
}
$span2->end();
} finally {
$rootScope->close(); // close the scope of the root span, no active span in the context now
$rootScope->detach(); // close the scope of the root span, no active span in the context now
}
$rootSpan->end();

View File

@ -6,7 +6,6 @@ require __DIR__ . '/../vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\Contrib\Zipkin\Exporter as ZipkinExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
@ -36,13 +35,13 @@ for ($i = 0; $i < 3; $i++) {
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]));
$span->addEvent('generated_session', new Attributes([
]);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]));
]);
$span->end();
}

View File

@ -8,7 +8,6 @@ use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\ZipkinToNewrelic\Exporter as ZipkinToNewrelicExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
@ -61,33 +60,30 @@ $zipkinToNewrelicExporter = new ZipkinToNewrelicExporter(
if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
echo 'Starting AlwaysOnZipkinToNewRelicExample';
$tracer = (new TracerProvider())
->addSpanProcessor(new SimpleSpanProcessor($zipkinToNewrelicExporter))
$tracer = (new TracerProvider(new SimpleSpanProcessor($zipkinToNewrelicExporter)))
->getTracer('io.opentelemetry.contrib.php');
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->startAndActivateSpan('session.generate.span.' . microtime(true));
$span = $tracer->spanBuilder('session.generate.span.' . microtime(true))->startSpan();
$spanParent = $span->getParentContext();
echo sprintf(
PHP_EOL . 'Exporting Trace: %s, Parent: %s, Span: %s',
PHP_EOL . 'Exporting Trace: %s, Span: %s',
$span->getContext()->getTraceId(),
$spanParent ? $spanParent->getSpanId() : 'None',
$span->getContext()->getSpanId()
);
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, new Attributes([
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
]), $timestamp);
$span->addEvent('generated_session', new Attributes([
], $timestamp);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
]), $timestamp);
], $timestamp);
$span->end();
}

View File

@ -13,7 +13,7 @@ use OpenTelemetry\SemConv\ResourceAttributes;
echo 'Starting ConsoleSpanExporter' . PHP_EOL;
$resource = ResourceInfoFactory::merge(ResourceInfo::create(new Attributes([
$resource = ResourceInfoFactory::merge(ResourceInfo::create(Attributes::create([
//@see https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/resource/semantic_conventions
ResourceAttributes::SERVICE_NAMESPACE => 'foo',
ResourceAttributes::SERVICE_NAME => 'bar',

View File

@ -1,32 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
final class AttributeLimits implements AttributeLimitsInterface
{
private int $attributeCountLimit;
private int $attributeValueLengthLimit;
public function __construct(
int $attributeCountLimit = AttributeLimitsInterface::DEFAULT_COUNT_LIMIT,
int $attributeValueLengthLimit = AttributeLimitsInterface::DEFAULT_VALUE_LENGTH_LIMIT
) {
$this->attributeCountLimit = $attributeCountLimit;
$this->attributeValueLengthLimit = $attributeValueLengthLimit;
}
/** @return int Maximum allowed attribute count */
public function getAttributeCountLimit(): int
{
return $this->attributeCountLimit;
}
/** @return int Maximum allowed attribute value length */
public function getAttributeValueLengthLimit(): int
{
return $this->attributeValueLengthLimit;
}
}

View File

@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
interface AttributeLimitsInterface
{
public const DEFAULT_COUNT_LIMIT = 128;
public const DEFAULT_VALUE_LENGTH_LIMIT = PHP_INT_MAX;
/** @return int Maximum allowed attribute count */
public function getAttributeCountLimit(): int;
/** @return int Maximum allowed attribute value length */
public function getAttributeValueLengthLimit(): int;
}

View File

@ -4,65 +4,37 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
use function mb_substr;
use function array_key_exists;
use IteratorAggregate;
use Traversable;
class Attributes implements AttributesInterface
final class Attributes implements AttributesInterface, IteratorAggregate
{
private array $attributes = [];
private array $attributes;
private int $droppedAttributesCount;
private AttributeLimitsInterface $attributeLimits;
private int $totalAddedAttributes = 0;
public function __construct(iterable $attributes = [], AttributeLimitsInterface $attributeLimits = null)
/**
* @internal
*/
public function __construct(array $attributes, int $droppedAttributesCount)
{
$this->attributeLimits = $attributeLimits ?? new AttributeLimits();
foreach ($attributes as $key => $value) {
$this->setAttribute((string) $key, $value);
}
$this->attributes = $attributes;
$this->droppedAttributesCount = $droppedAttributesCount;
}
/** @return Attributes Returns a new instance of Attributes with the limits applied */
public static function withLimits(iterable $attributes, AttributeLimitsInterface $attributeLimits): Attributes
public static function create(iterable $attributes): AttributesInterface
{
return new self($attributes, $attributeLimits);
return self::factory()->builder($attributes)->build();
}
public function hasAttribute(string $name): bool
public static function factory(?int $attributeCountLimit = null, ?int $attributeValueLengthLimit = null): AttributesFactoryInterface
{
return isset($this->attributes[$name]);
return new AttributesFactory($attributeCountLimit, $attributeValueLengthLimit);
}
public function setAttribute(string $name, $value): AttributesInterface
public function has(string $name): bool
{
// unset the attribute when null value is passed
if ($value === null) {
return $this->unsetAttribute($name);
}
if (!$this->hasAttribute($name)) {
$this->totalAddedAttributes++;
}
// drop attribute when limit is reached
if (!$this->hasAttribute($name) && $this->isLimitReached()) {
return $this;
}
$this->attributes[$name] = $this->normalizeValue($value);
return $this;
}
public function unsetAttribute(string $name): AttributesInterface
{
if ($this->hasAttribute($name)) {
unset($this->attributes[$name]);
$this->totalAddedAttributes--;
}
return $this;
return array_key_exists($name, $this->attributes);
}
public function get(string $name)
@ -88,38 +60,8 @@ class Attributes implements AttributesInterface
return $this->attributes;
}
public function getTotalAddedValues(): int
{
return $this->totalAddedAttributes;
}
public function getDroppedAttributesCount(): int
{
return $this->totalAddedAttributes - count($this);
}
public function isLimitReached(): bool
{
return count($this) >= $this->attributeLimits->getAttributeCountLimit();
}
private function truncateStringValue(string $value): string
{
return mb_substr($value, 0, $this->attributeLimits->getAttributeValueLengthLimit());
}
private function normalizeValue($value)
{
if (is_string($value)) {
return $this->truncateStringValue($value);
}
if (is_array($value)) {
return array_map(function ($value) {
return $this->normalizeValue($value);
}, $value);
}
return $value;
return $this->droppedAttributesCount;
}
}

View File

@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
use function array_key_exists;
use function count;
use function is_array;
use function is_string;
use function mb_substr;
/**
* @internal
*/
final class AttributesBuilder implements AttributesBuilderInterface
{
private array $attributes;
private ?int $attributeCountLimit;
private ?int $attributeValueLengthLimit;
private int $droppedAttributesCount;
public function __construct(array $attributes, ?int $attributeCountLimit, ?int $attributeValueLengthLimit, int $droppedAttributesCount)
{
$this->attributes = $attributes;
$this->attributeCountLimit = $attributeCountLimit;
$this->attributeValueLengthLimit = $attributeValueLengthLimit;
$this->droppedAttributesCount = $droppedAttributesCount;
}
public function build(): AttributesInterface
{
return new Attributes($this->attributes, $this->droppedAttributesCount);
}
public function offsetExists($offset): bool
{
return array_key_exists($offset, $this->attributes);
}
/**
* @phan-suppress PhanUndeclaredClassAttribute
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->attributes[$offset] ?? null;
}
/**
* @phan-suppress PhanUndeclaredClassAttribute
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if ($offset === null) {
return;
}
if ($value === null) {
unset($this->attributes[$offset]);
return;
}
if (count($this->attributes) === $this->attributeCountLimit && !array_key_exists($offset, $this->attributes)) {
$this->droppedAttributesCount++;
return;
}
$this->attributes[$offset] = $this->normalizeValue($value);
}
/**
* @phan-suppress PhanUndeclaredClassAttribute
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->attributes[$offset]);
}
private function normalizeValue($value)
{
if (is_string($value) && $this->attributeValueLengthLimit !== null) {
return mb_substr($value, 0, $this->attributeValueLengthLimit);
}
if (is_array($value)) {
foreach ($value as $k => $v) {
$processed = $this->normalizeValue($v);
if ($processed !== $v) {
$value[$k] = $processed;
}
}
return $value;
}
return $value;
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
use ArrayAccess;
interface AttributesBuilderInterface extends ArrayAccess
{
public function build(): AttributesInterface;
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
/**
* @internal
*/
final class AttributesFactory implements AttributesFactoryInterface
{
private ?int $attributeCountLimit;
private ?int $attributeValueLengthLimit;
public function __construct(?int $attributeCountLimit = null, ?int $attributeValueLengthLimit = null)
{
$this->attributeCountLimit = $attributeCountLimit;
$this->attributeValueLengthLimit = $attributeValueLengthLimit;
}
public function builder(iterable $attributes = []): AttributesBuilderInterface
{
$builder = new AttributesBuilder(
[],
$this->attributeCountLimit,
$this->attributeValueLengthLimit,
0,
);
foreach ($attributes as $key => $value) {
$builder[$key] = $value;
}
return $builder;
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
interface AttributesFactoryInterface
{
public function builder(iterable $attributes = []): AttributesBuilderInterface;
}

View File

@ -5,21 +5,15 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Attribute;
use Countable;
use IteratorAggregate;
use Traversable;
interface AttributesInterface extends IteratorAggregate, Countable
interface AttributesInterface extends Traversable, Countable
{
public function setAttribute(string $name, $value): AttributesInterface;
public function unsetAttribute(string $name): AttributesInterface;
public function hasAttribute(string $name): bool;
public function has(string $name): bool;
public function get(string $name);
public function getIterator(): Traversable;
public function toArray(): array;
public function getTotalAddedValues(): int;
public function getDroppedAttributesCount(): int;
public function isLimitReached(): bool;
public function toArray(): array;
}

View File

@ -1,47 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Dev\Compatibility\BC;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimits as Moved;
use OpenTelemetry\SDK\Common\Dev\Compatibility\Util;
/**
* @codeCoverageIgnoreStart
*/
const OpenTelemetry_SDK_AttributeLimits = 'OpenTelemetry\SDK\AttributeLimits';
final class AttributeLimits implements AttributeLimitsInterface
{
private Moved $adapted;
public function __construct(
int $attributeCountLimit = AttributeLimitsInterface::DEFAULT_COUNT_LIMIT,
int $attributeValueLengthLimit = AttributeLimitsInterface::DEFAULT_VALUE_LENGTH_LIMIT
) {
$this->adapted = new Moved(
$attributeCountLimit,
$attributeValueLengthLimit
);
Util::triggerClassDeprecationNotice(
OpenTelemetry_SDK_AttributeLimits,
Moved::class
);
}
public function getAttributeCountLimit(): int
{
return $this->adapted->getAttributeCountLimit();
}
public function getAttributeValueLengthLimit(): int
{
return $this->adapted->getAttributeValueLengthLimit();
}
}
class_alias(AttributeLimits::class, OpenTelemetry_SDK_AttributeLimits);
/**
* @codeCoverageIgnoreEnd
*/

View File

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Dev\Compatibility\BC;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimitsInterface as Moved;
interface AttributeLimitsInterface extends Moved
{
}
/**
* @codeCoverageIgnoreStart
*/
class_alias(AttributeLimitsInterface::class, 'OpenTelemetry\SDK\AttributeLimitsInterface');
/**
* @codeCoverageIgnoreEnd
*/

View File

@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Dev\Compatibility\BC;
use OpenTelemetry\SDK\Common\Attribute\Attributes as Moved;
use OpenTelemetry\SDK\Common\Dev\Compatibility\Util;
/**
* @codeCoverageIgnoreStart
*/
const OpenTelemetry_SDK_Attributes = 'OpenTelemetry\SDK\Attributes';
final class Attributes extends Moved implements AttributesInterface
{
public function __construct(iterable $attributes = [], AttributeLimitsInterface $attributeLimits = null)
{
parent::__construct($attributes, $attributeLimits);
Util::triggerClassDeprecationNotice(
OpenTelemetry_SDK_Attributes,
Moved::class
);
}
}
class_alias(Attributes::class, OpenTelemetry_SDK_Attributes);
/**
* @codeCoverageIgnoreEnd
*/

View File

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Dev\Compatibility\BC;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface as Moved;
interface AttributesInterface extends Moved
{
}
/**
* @codeCoverageIgnoreStart
*/
class_alias(AttributesInterface::class, 'OpenTelemetry\SDK\AttributesInterface');
/**
* @codeCoverageIgnoreEnd
*/

View File

@ -2,10 +2,6 @@
declare(strict_types=1);
require_once __DIR__ . '/BC/AttributeLimitsInterface.php';
require_once __DIR__ . '/BC/AttributeLimits.php';
require_once __DIR__ . '/BC/AttributesInterface.php';
require_once __DIR__ . '/BC/Attributes.php';
require_once __DIR__ . '/BC/ClockInterface.php';
require_once __DIR__ . '/BC/AbstractClock.php';
require_once __DIR__ . '/BC/SystemClock.php';

View File

@ -25,6 +25,6 @@ final class Composer implements ResourceDetectorInterface
ResourceAttributes::SERVICE_VERSION => InstalledVersions::getRootPackage()['pretty_version'],
];
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -30,6 +30,6 @@ final class Environment implements ResourceDetectorInterface
$attributes[ResourceAttributes::SERVICE_NAME] = $serviceName;
}
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -22,6 +22,6 @@ final class Host implements ResourceDetectorInterface
ResourceAttributes::HOST_ARCH => php_uname('m'),
];
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -27,6 +27,6 @@ final class OperatingSystem implements ResourceDetectorInterface
ResourceAttributes::OS_VERSION => php_uname('v'),
];
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -31,6 +31,6 @@ final class Process implements ResourceDetectorInterface
$attributes[ResourceAttributes::PROCESS_OWNER] = \posix_getpwuid(\posix_geteuid())['name'];
}
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -23,6 +23,6 @@ final class ProcessRuntime implements ResourceDetectorInterface
ResourceAttributes::PROCESS_RUNTIME_VERSION => PHP_VERSION,
];
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -43,6 +43,6 @@ final class Sdk implements ResourceDetectorInterface
}
}
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -20,6 +20,6 @@ final class SdkProvided implements ResourceDetectorInterface
ResourceAttributes::SERVICE_NAME => 'unknown_service',
];
return ResourceInfo::create(new Attributes($attributes), ResourceAttributes::SCHEMA_URL);
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
}
}

View File

@ -28,7 +28,7 @@ class ResourceInfo
public static function create(AttributesInterface $attributes, ?string $schemaUrl = null): self
{
return new ResourceInfo(clone $attributes, $schemaUrl);
return new ResourceInfo($attributes, $schemaUrl);
}
public function getAttributes(): AttributesInterface

View File

@ -31,7 +31,7 @@ class ResourceInfoFactory
$schemaUrl = self::mergeSchemaUrl(...$resources);
return ResourceInfo::create(new Attributes($attributes), $schemaUrl);
return ResourceInfo::create(Attributes::create($attributes), $schemaUrl);
}
public static function defaultResource(): ResourceInfo
@ -91,7 +91,7 @@ class ResourceInfoFactory
public static function emptyResource(): ResourceInfo
{
return ResourceInfo::create(new Attributes());
return ResourceInfo::create(Attributes::create([]));
}
private static function mergeSchemaUrl(ResourceInfo ...$resources): ?string

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Trace;
use function count;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
final class Event implements EventInterface
@ -14,11 +13,11 @@ final class Event implements EventInterface
private int $timestamp;
private AttributesInterface $attributes;
public function __construct(string $name, int $timestamp, AttributesInterface $attributes = null)
public function __construct(string $name, int $timestamp, AttributesInterface $attributes)
{
$this->name = $name;
$this->timestamp = $timestamp;
$this->attributes = $attributes ?? new Attributes();
$this->attributes = $attributes;
}
public function getAttributes(): AttributesInterface

View File

@ -27,7 +27,6 @@ final class ImmutableSpan implements SpanDataInterface
private array $links;
private AttributesInterface $attributes;
private int $totalAttributeCount;
private int $totalRecordedEvents;
private StatusDataInterface $status;
private int $endEpochNanos;
@ -44,7 +43,6 @@ final class ImmutableSpan implements SpanDataInterface
array $links,
array $events,
AttributesInterface $attributes,
int $totalAttributeCount,
int $totalRecordedEvents,
StatusDataInterface $status,
int $endEpochNanos,
@ -55,7 +53,6 @@ final class ImmutableSpan implements SpanDataInterface
$this->links = $links;
$this->events = $events;
$this->attributes = $attributes;
$this->totalAttributeCount = $totalAttributeCount;
$this->totalRecordedEvents = $totalRecordedEvents;
$this->status = $status;
$this->endEpochNanos = $endEpochNanos;
@ -134,11 +131,6 @@ final class ImmutableSpan implements SpanDataInterface
return $this->attributes;
}
public function getTotalDroppedAttributes(): int
{
return max(0, $this->totalAttributeCount - count($this->attributes));
}
public function getTotalDroppedEvents(): int
{
return max(0, $this->totalRecordedEvents - count($this->events));

View File

@ -4,22 +4,18 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Trace;
use function count;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
final class Link implements LinkInterface
{
private AttributesInterface $attributes;
private API\SpanContextInterface $context;
private int $totalAttributeCount;
public function __construct(API\SpanContextInterface $context, AttributesInterface $attributes = null)
public function __construct(API\SpanContextInterface $context, AttributesInterface $attributes)
{
$this->context = $context;
$this->attributes = $attributes ?? new Attributes();
$this->totalAttributeCount = count($this->attributes);
$this->attributes = $attributes;
}
public function getSpanContext(): API\SpanContextInterface
@ -31,9 +27,4 @@ final class Link implements LinkInterface
{
return $this->attributes;
}
public function getTotalAttributeCount(): int
{
return $this->totalAttributeCount;
}
}

View File

@ -11,5 +11,4 @@ interface LinkInterface
{
public function getSpanContext(): SpanContextInterface;
public function getAttributes(): AttributesInterface;
public function getTotalAttributeCount(): int;
}

View File

@ -38,7 +38,7 @@ class AlwaysOffSampler implements SamplerInterface
return new SamplingResult(
SamplingResult::DROP,
null,
[],
$traceState
);
}

View File

@ -38,7 +38,7 @@ class AlwaysOnSampler implements SamplerInterface
return new SamplingResult(
SamplingResult::RECORD_AND_SAMPLE,
null,
[],
$traceState
);
}

View File

@ -60,7 +60,7 @@ class TraceIdRatioBasedSampler implements SamplerInterface
$traceIdCondition = $lowerOrderBytes < round($this->probability * $traceIdLimit);
$decision = $traceIdCondition ? SamplingResult::RECORD_AND_SAMPLE : SamplingResult::DROP;
return new SamplingResult($decision, null, $traceState);
return new SamplingResult($decision, [], $traceState);
}
public function getDescription(): string

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Trace;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
final class SamplingResult
{
@ -30,16 +29,16 @@ final class SamplingResult
private int $decision;
/**
* @var ?AttributesInterface A set of span Attributes that will also be added to the Span.
* @var iterable A set of span Attributes that will also be added to the Span.
*/
private ?AttributesInterface $attributes;
private iterable $attributes;
/**
* @var ?API\TraceStateInterface A Tracestate that will be associated with the Span through the new SpanContext.
*/
private ?API\TraceStateInterface $traceState;
public function __construct(int $decision, ?AttributesInterface $attributes = null, ?API\TraceStateInterface $traceState = null)
public function __construct(int $decision, iterable $attributes = [], ?API\TraceStateInterface $traceState = null)
{
$this->decision = $decision;
$this->attributes = $attributes;
@ -57,7 +56,7 @@ final class SamplingResult
/**
* Return attributes which will be attached to the span.
*/
public function getAttributes(): ?AttributesInterface
public function getAttributes(): iterable
{
return $this->attributes;
}

View File

@ -4,14 +4,10 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Trace;
use function count;
use function ctype_space;
use function get_class;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimits;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
use OpenTelemetry\SDK\Common\Attribute\AttributesBuilderInterface;
use OpenTelemetry\SDK\Common\Dev\Compatibility\Util as BcUtil;
use OpenTelemetry\SDK\Common\Exception\StackTraceFormatter;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface;
@ -62,7 +58,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
/** @var list<EventInterface> */
private array $events = [];
private ?AttributesInterface $attributes;
private AttributesBuilderInterface $attributesBuilder;
private int $totalRecordedEvents = 0;
private StatusDataInterface $status;
private int $endEpochNanos = 0;
@ -81,7 +77,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
SpanLimits $spanLimits,
SpanProcessorInterface $spanProcessor,
ResourceInfo $resource,
?AttributesInterface $attributes,
AttributesBuilderInterface $attributesBuilder,
array $links,
int $totalRecordedLinks,
int $startEpochNanos
@ -96,7 +92,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
$this->spanProcessor = $spanProcessor;
$this->resource = $resource;
$this->startEpochNanos = $startEpochNanos;
$this->attributes = Attributes::withLimits($attributes ?? new Attributes(), $spanLimits->getAttributeLimits());
$this->attributesBuilder = $attributesBuilder;
$this->status = StatusData::unset();
$this->spanLimits = $spanLimits;
}
@ -122,7 +118,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
SpanLimits $spanLimits,
SpanProcessorInterface $spanProcessor,
ResourceInfo $resource,
?AttributesInterface $attributes,
AttributesBuilderInterface $attributesBuilder,
array $links,
int $totalRecordedLinks,
int $startEpochNanos
@ -136,7 +132,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
$spanLimits,
$spanProcessor,
$resource,
$attributes,
$attributesBuilder,
$links,
$totalRecordedLinks,
$startEpochNanos !== 0 ? $startEpochNanos : ClockFactory::getDefault()->now()
@ -179,15 +175,11 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
/** @inheritDoc */
public function setAttribute(string $key, $value): self
{
if ($this->hasEnded || ctype_space($key)) {
if ($this->hasEnded) {
return $this;
}
if (null === $this->attributes) {
$this->attributes = Attributes::withLimits(new Attributes(), $this->spanLimits->getAttributeLimits());
}
$this->attributes->setAttribute($key, $value);
$this->attributesBuilder[$key] = $value;
return $this;
}
@ -196,53 +188,54 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
public function setAttributes(iterable $attributes): self
{
foreach ($attributes as $key => $value) {
$this->setAttribute($key, $value);
$this->attributesBuilder[$key] = $value;
}
return $this;
}
/** @inheritDoc */
public function addEvent(string $name, iterable $attributes = [], int $timestamp = null): self
public function addEvent(string $name, iterable $attributes = [], ?int $timestamp = null): self
{
if ($this->hasEnded) {
return $this;
}
if (count($this->events) < $this->spanLimits->getEventCountLimit()) {
$this->events[] = new Event(
$name,
$timestamp ?? ClockFactory::getDefault()->now(),
Attributes::withLimits(
$attributes,
new AttributeLimits(
$this->spanLimits->getAttributePerEventCountLimit(),
$this->spanLimits->getAttributeLimits()->getAttributeValueLengthLimit()
)
),
);
if (++$this->totalRecordedEvents > $this->spanLimits->getEventCountLimit()) {
return $this;
}
$this->totalRecordedEvents++;
$timestamp ??= ClockFactory::getDefault()->now();
$eventAttributesBuilder = $this->spanLimits->getEventAttributesFactory()->builder($attributes);
$this->events[] = new Event($name, $timestamp, $eventAttributesBuilder->build());
return $this;
}
/** @inheritDoc */
public function recordException(Throwable $exception, iterable $attributes = []): self
public function recordException(Throwable $exception, iterable $attributes = [], ?int $timestamp = null): self
{
$timestamp = ClockFactory::getDefault()->now();
$eventAttributes = new Attributes([
'exception.type' => get_class($exception),
'exception.message' => $exception->getMessage(),
'exception.stacktrace' => StackTraceFormatter::format($exception),
]);
foreach ($attributes as $key => $value) {
$eventAttributes->setAttribute($key, $value);
if ($this->hasEnded) {
return $this;
}
if (++$this->totalRecordedEvents > $this->spanLimits->getEventCountLimit()) {
return $this;
}
return $this->addEvent('exception', $eventAttributes, $timestamp);
$timestamp ??= ClockFactory::getDefault()->now();
$eventAttributesBuilder = $this->spanLimits->getEventAttributesFactory()->builder([
'exception.type' => get_class($exception),
'exception.message' => $exception->getMessage(),
'exception.stacktrace' => StackTraceFormatter::format($exception),
]);
foreach ($attributes as $key => $value) {
$eventAttributesBuilder[$key] = $value;
}
$this->events[] = new Event('exception', $timestamp, $eventAttributesBuilder->build());
return $this;
}
/** @inheritDoc */
@ -309,8 +302,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
$this->name,
$this->links,
$this->events,
$this->getImmutableAttributes(),
(null === $this->attributes) ? 0 : $this->attributes->getTotalAddedValues(),
$this->attributesBuilder->build(),
$this->totalRecordedEvents,
$this->status,
$this->endEpochNanos,
@ -333,11 +325,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
/** @inheritDoc */
public function getAttribute(string $key)
{
if (null === $this->attributes) {
return null;
}
return $this->attributes->get($key);
return $this->attributesBuilder[$key];
}
public function getStartEpochNanos(): int
@ -359,13 +347,4 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
{
return $this->resource;
}
private function getImmutableAttributes(): AttributesInterface
{
if (null === $this->attributes) {
return new Attributes();
}
return clone $this->attributes;
}
}

View File

@ -7,9 +7,7 @@ namespace OpenTelemetry\SDK\Trace;
use function in_array;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimits;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
use OpenTelemetry\SDK\Common\Attribute\AttributesBuilderInterface;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeInterface;
final class SpanBuilder implements API\SpanBuilderInterface
@ -26,9 +24,6 @@ final class SpanBuilder implements API\SpanBuilderInterface
/** @readonly */
private TracerSharedState $tracerSharedState;
/** @readonly */
private SpanLimits $spanLimits;
private ?Context $parentContext = null; // Null means use current context.
/**
@ -39,7 +34,7 @@ final class SpanBuilder implements API\SpanBuilderInterface
/** @var list<LinkInterface>|null */
private ?array $links = null;
private ?AttributesInterface $attributes = null;
private AttributesBuilderInterface $attributesBuilder;
private int $totalNumberOfLinksAdded = 0;
private int $startEpochNanos = 0;
@ -47,13 +42,12 @@ final class SpanBuilder implements API\SpanBuilderInterface
public function __construct(
string $spanName,
InstrumentationScopeInterface $instrumentationScope,
TracerSharedState $tracerSharedState,
SpanLimits $spanLimits
TracerSharedState $tracerSharedState
) {
$this->spanName = $spanName;
$this->instrumentationScope = $instrumentationScope;
$this->tracerSharedState = $tracerSharedState;
$this->spanLimits = $spanLimits;
$this->attributesBuilder = $tracerSharedState->getSpanLimits()->getAttributesFactory()->builder();
}
/** @inheritDoc */
@ -85,19 +79,17 @@ final class SpanBuilder implements API\SpanBuilderInterface
$this->links = [];
}
if (count($this->links) === $this->spanLimits->getLinkCountLimit()) {
if (count($this->links) === $this->tracerSharedState->getSpanLimits()->getLinkCountLimit()) {
return $this;
}
$this->links[] = new Link(
$context,
Attributes::withLimits(
$attributes,
new AttributeLimits(
$this->spanLimits->getAttributePerLinkCountLimit(),
$this->spanLimits->getAttributeLimits()->getAttributeValueLengthLimit()
)
),
$this->tracerSharedState
->getSpanLimits()
->getLinkAttributesFactory()
->builder($attributes)
->build(),
);
return $this;
@ -106,11 +98,7 @@ final class SpanBuilder implements API\SpanBuilderInterface
/** @inheritDoc */
public function setAttribute(string $key, $value): API\SpanBuilderInterface
{
if (null === $this->attributes) {
$this->attributes = Attributes::withLimits(new Attributes(), $this->spanLimits->getAttributeLimits());
}
$this->attributes->setAttribute($key, $value);
$this->attributesBuilder[$key] = $value;
return $this;
}
@ -119,7 +107,7 @@ final class SpanBuilder implements API\SpanBuilderInterface
public function setAttributes(iterable $attributes): API\SpanBuilderInterface
{
foreach ($attributes as $key => $value) {
$this->setAttribute($key, $value);
$this->attributesBuilder[$key] = $value;
}
return $this;
@ -168,9 +156,6 @@ final class SpanBuilder implements API\SpanBuilderInterface
$links = $this->links ?? [];
$this->links = null;
$attributes = $this->attributes ?? new Attributes();
$this->attributes = null;
$samplingResult = $this
->tracerSharedState
->getSampler()
@ -179,7 +164,7 @@ final class SpanBuilder implements API\SpanBuilderInterface
$traceId,
$this->spanName,
$this->spanKind,
$attributes,
$this->attributesBuilder->build(),
$links
);
$samplingDecision = $samplingResult->getDecision();
@ -196,11 +181,9 @@ final class SpanBuilder implements API\SpanBuilderInterface
return Span::wrap($spanContext);
}
$samplingAttributes = $samplingResult->getAttributes();
if ($samplingAttributes && $samplingAttributes->count() > 0) {
foreach ($samplingAttributes as $key => $value) {
$attributes->setAttribute($key, $value);
}
$attributesBuilder = clone $this->attributesBuilder;
foreach ($samplingResult->getAttributes() as $key => $value) {
$attributesBuilder[$key] = $value;
}
return Span::startSpan(
@ -210,10 +193,10 @@ final class SpanBuilder implements API\SpanBuilderInterface
$this->spanKind,
$parentSpan,
$parentContext,
$this->spanLimits,
$this->tracerSharedState->getSpanLimits(),
$this->tracerSharedState->getSpanProcessor(),
$this->tracerSharedState->getResource(),
$attributes,
$attributesBuilder,
$links,
$this->totalNumberOfLinksAdded,
$this->startEpochNanos

View File

@ -43,7 +43,4 @@ interface SpanDataInterface
/** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/sdk_exporters/non-otlp.md#dropped-links-count */
public function getTotalDroppedLinks(): int;
/** @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/sdk_exporters/non-otlp.md#dropped-attributes-count */
public function getTotalDroppedAttributes(): int;
}

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Trace;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimits;
use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface;
final class SpanLimits
{
@ -15,19 +15,25 @@ final class SpanLimits
public const DEFAULT_EVENT_ATTRIBUTE_COUNT_LIMIT = 128;
public const DEFAULT_LINK_ATTRIBUTE_COUNT_LIMIT = 128;
private AttributeLimits $attributeLimits;
private AttributesFactoryInterface $attributesFactory;
private AttributesFactoryInterface $eventAttributesFactory;
private AttributesFactoryInterface $linkAttributesFactory;
private int $eventCountLimit;
private int $linkCountLimit;
private int $attributePerEventCountLimit;
private int $attributePerLinkCountLimit;
public function getAttributeLimits(): AttributeLimits
public function getAttributesFactory(): AttributesFactoryInterface
{
return $this->attributeLimits;
return $this->attributesFactory;
}
public function getEventAttributesFactory(): AttributesFactoryInterface
{
return $this->eventAttributesFactory;
}
public function getLinkAttributesFactory(): AttributesFactoryInterface
{
return $this->linkAttributesFactory;
}
/** @return int Maximum allowed span event count */
@ -42,33 +48,20 @@ final class SpanLimits
return $this->linkCountLimit;
}
/** @return int Maximum allowed attribute per span event count */
public function getAttributePerEventCountLimit(): int
{
return $this->attributePerEventCountLimit;
}
/** @return int Maximum allowed attribute per span link count */
public function getAttributePerLinkCountLimit(): int
{
return $this->attributePerLinkCountLimit;
}
/**
* @internal Use {@see SpanLimitsBuilder} to create {@see SpanLimits} instance.
*/
public function __construct(
int $attributeCountLimit,
int $attributeValueLengthLimit,
AttributesFactoryInterface $attributesFactory,
AttributesFactoryInterface $eventAttributesFactory,
AttributesFactoryInterface $linkAttributesFactory,
int $eventCountLimit,
int $linkCountLimit,
int $attributePerEventCountLimit,
int $attributePerLinkCountLimit
int $linkCountLimit
) {
$this->attributeLimits = new AttributeLimits($attributeCountLimit, $attributeValueLengthLimit);
$this->attributesFactory = $attributesFactory;
$this->eventAttributesFactory = $eventAttributesFactory;
$this->linkAttributesFactory = $linkAttributesFactory;
$this->eventCountLimit = $eventCountLimit;
$this->linkCountLimit = $linkCountLimit;
$this->attributePerEventCountLimit = $attributePerEventCountLimit;
$this->attributePerLinkCountLimit = $attributePerLinkCountLimit;
}
}

View File

@ -4,8 +4,10 @@ declare(strict_types=1);
namespace OpenTelemetry\SDK\Trace;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Environment\EnvironmentVariablesTrait;
use OpenTelemetry\SDK\Common\Environment\Variables as Env;
use const PHP_INT_MAX;
class SpanLimitsBuilder
{
@ -94,19 +96,29 @@ class SpanLimitsBuilder
*/
public function build(): SpanLimits
{
$attributeCountLimit = $this->attributeCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_ATTRIBUTE_COUNT_LIMIT);
$attributeValueLengthLimit = $this->attributeValueLengthLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT, SpanLimits::DEFAULT_SPAN_ATTRIBUTE_LENGTH_LIMIT);
$eventCountLimit = $this->eventCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_EVENT_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_EVENT_COUNT_LIMIT);
$linkCountLimit = $this->linkCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_LINK_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_LINK_COUNT_LIMIT);
$attributePerEventCountLimit = $this->attributePerEventCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_EVENT_ATTRIBUTE_COUNT_LIMIT);
$attributePerLinkCountLimit = $this->attributePerLinkCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_LINK_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_LINK_ATTRIBUTE_COUNT_LIMIT);
if ($attributeValueLengthLimit === PHP_INT_MAX) {
$attributeValueLengthLimit = null;
}
return new SpanLimits(
$this->attributeCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_ATTRIBUTE_COUNT_LIMIT),
$this->attributeValueLengthLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT, SpanLimits::DEFAULT_SPAN_ATTRIBUTE_LENGTH_LIMIT),
$this->eventCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_EVENT_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_EVENT_COUNT_LIMIT),
$this->linkCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_SPAN_LINK_COUNT_LIMIT, SpanLimits::DEFAULT_SPAN_LINK_COUNT_LIMIT),
$this->attributePerEventCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_EVENT_ATTRIBUTE_COUNT_LIMIT),
$this->attributePerLinkCountLimit
?: $this->getIntFromEnvironment(Env::OTEL_LINK_ATTRIBUTE_COUNT_LIMIT, SpanLimits::DEFAULT_LINK_ATTRIBUTE_COUNT_LIMIT),
Attributes::factory($attributeCountLimit, $attributeValueLengthLimit),
Attributes::factory($attributePerEventCountLimit, $attributeValueLengthLimit),
Attributes::factory($attributePerLinkCountLimit, $attributeValueLengthLimit),
$eventCountLimit,
$linkCountLimit,
);
}
}

View File

@ -41,7 +41,6 @@ class Tracer implements API\TracerInterface
$spanName,
$this->instrumentationScope,
$this->tracerSharedState,
$this->tracerSharedState->getSpanLimits()
);
}

View File

@ -35,7 +35,7 @@ class OtlpBench
public function __construct()
{
$this->sampler = new AlwaysOnSampler();
$this->resource = ResourceInfo::create(new Attributes([
$this->resource = ResourceInfo::create(Attributes::create([
'service.name' => 'A123456789',
'service.version' => '1.34567890',
'service.instance.id' => '123ab456-a123-12ab-12ab-12340a1abc12',

View File

@ -30,7 +30,7 @@ class ResourceInfoTest extends TestCase
{
$this->setEnvironmentVariable('OTEL_RESOURCE_ATTRIBUTES', $envAttributes);
$resource = (new Detectors\Composite([
new Detectors\Constant(ResourceInfo::create(new Attributes($userAttributes))),
new Detectors\Constant(ResourceInfo::create(Attributes::create($userAttributes))),
new Detectors\Environment(),
]))->getResource();
foreach ($expected as $name => $value) {

View File

@ -58,7 +58,7 @@ class SpanBuilderTest extends MockeryTestCase
->tracer
->spanBuilder(self::SPAN_NAME)
->addLink($this->sampledSpanContext)
->addLink($this->sampledSpanContext, new Attributes())
->addLink($this->sampledSpanContext, [])
->startSpan();
$this->assertCount(2, $span->toSpanData()->getLinks());
@ -71,7 +71,7 @@ class SpanBuilderTest extends MockeryTestCase
->tracer
->spanBuilder(self::SPAN_NAME)
->addLink(Span::getInvalid()->getContext())
->addLink(Span::getInvalid()->getContext(), new Attributes())
->addLink(Span::getInvalid()->getContext(), [])
->startSpan();
$this->assertEmpty($span->toSpanData()->getLinks());
@ -99,7 +99,7 @@ class SpanBuilderTest extends MockeryTestCase
$this->assertSame(8, $spanData->getTotalDroppedLinks());
for ($idx = 0; $idx < $maxNumberOfLinks; $idx++) {
$this->assertEquals(new Link($this->sampledSpanContext), $links[$idx]);
$this->assertEquals(new Link($this->sampledSpanContext, Attributes::create([])), $links[$idx]);
}
$span->end();
@ -113,11 +113,11 @@ class SpanBuilderTest extends MockeryTestCase
->spanBuilder(self::SPAN_NAME)
->addLink(
$this->sampledSpanContext,
new Attributes([
[
'key0' => 0,
'key1' => 1,
'key2' => 2,
])
]
)
->startSpan();
@ -138,12 +138,12 @@ class SpanBuilderTest extends MockeryTestCase
->spanBuilder(self::SPAN_NAME)
->addLink(
$this->sampledSpanContext,
new Attributes([
[
'string' => $tooLongStrVal,
'bool' => true,
'string_array' => [$strVal, $tooLongStrVal],
'int_array' => [1, 2],
])
]
)
->startSpan();
@ -235,7 +235,7 @@ class SpanBuilderTest extends MockeryTestCase
$span->setAttribute('doo', 'baz');
$this->assertSame(2, $attributes->count());
$this->assertFalse($attributes->hasAttribute('doo'));
$this->assertFalse($attributes->has('doo'));
}
/**
@ -297,7 +297,7 @@ class SpanBuilderTest extends MockeryTestCase
$attributes = $span->toSpanData()->getAttributes();
$this->assertSame(2, $attributes->count());
$this->assertFalse($attributes->hasAttribute('bar1'));
$this->assertFalse($attributes->has('bar1'));
}
public function test_set_attribute_dropping(): void
@ -336,7 +336,7 @@ class SpanBuilderTest extends MockeryTestCase
?AttributesInterface $attributes = null,
array $links = []
): SamplingResult {
return new SamplingResult(SamplingResult::RECORD_AND_SAMPLE, new Attributes(['cat' => 'meow']));
return new SamplingResult(SamplingResult::RECORD_AND_SAMPLE, ['cat' => 'meow']);
}
public function getDescription(): string
@ -357,7 +357,7 @@ class SpanBuilderTest extends MockeryTestCase
public function test_set_attributes(): void
{
$attributes = new Attributes(['id' => 1, 'foo' => 'bar']);
$attributes = ['id' => 1, 'foo' => 'bar'];
/** @var Span $span */
$span = $this->tracer->spanBuilder(self::SPAN_NAME)->setAttributes($attributes)->startSpan();
@ -374,7 +374,7 @@ class SpanBuilderTest extends MockeryTestCase
*/
public function test_set_attributes_merges_attributes_correctly(): void
{
$attributes = new Attributes(['id' => 2, 'foo' => 'bar', 'key' => 'val']);
$attributes = ['id' => 2, 'foo' => 'bar', 'key' => 'val'];
/** @var Span $span */
$span = $this
@ -397,7 +397,7 @@ class SpanBuilderTest extends MockeryTestCase
public function test_set_attributes_overrides_values(): void
{
$attributes = new Attributes(['id' => 1, 'foo' => 'bar']);
$attributes = ['id' => 1, 'foo' => 'bar'];
/** @var Span $span */
$span = $this

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Tests\Integration\SDK;
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\SpanLimitsBuilder;
use PHPUnit\Framework\TestCase;
@ -28,7 +29,7 @@ class SpanLimitsBuilderTest extends TestCase
$this->setEnvironmentVariable('OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT', 9);
$builder = new SpanLimitsBuilder();
$spanLimits = $builder->build();
$this->assertEquals(9, $spanLimits->getAttributeLimits()->getAttributeValueLengthLimit());
$this->assertEquals(Attributes::factory(128, 9), $spanLimits->getAttributesFactory());
}
/**
@ -40,7 +41,7 @@ class SpanLimitsBuilderTest extends TestCase
$builder = new SpanLimitsBuilder();
$builder->setAttributeValueLengthLimit(201);
$spanLimits = $builder->build();
$this->assertEquals(201, $spanLimits->getAttributeLimits()->getAttributeValueLengthLimit());
$this->assertEquals(Attributes::factory(128, 201), $spanLimits->getAttributesFactory());
}
/**
@ -97,7 +98,7 @@ class SpanLimitsBuilderTest extends TestCase
$this->setEnvironmentVariable('OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT', 400);
$builder = new SpanLimitsBuilder();
$spanLimits = $builder->build();
$this->assertEquals(400, $spanLimits->getAttributePerEventCountLimit());
$this->assertEquals(Attributes::factory(400), $spanLimits->getEventAttributesFactory());
}
/**
@ -109,7 +110,7 @@ class SpanLimitsBuilderTest extends TestCase
$builder = new SpanLimitsBuilder();
$builder->setAttributePerEventCountLimit(155);
$spanLimits = $builder->build();
$this->assertEquals(155, $spanLimits->getAttributePerEventCountLimit());
$this->assertEquals(Attributes::factory(155), $spanLimits->getEventAttributesFactory());
}
/**
@ -120,7 +121,7 @@ class SpanLimitsBuilderTest extends TestCase
$this->setEnvironmentVariable('OTEL_LINK_ATTRIBUTE_COUNT_LIMIT', 500);
$builder = new SpanLimitsBuilder();
$spanLimits = $builder->build();
$this->assertEquals(500, $spanLimits->getAttributePerLinkCountLimit());
$this->assertEquals(Attributes::factory(500), $spanLimits->getLinkAttributesFactory());
}
/**
@ -132,6 +133,6 @@ class SpanLimitsBuilderTest extends TestCase
$builder = new SpanLimitsBuilder();
$builder->setAttributePerLinkCountLimit(450);
$spanLimits = $builder->build();
$this->assertEquals(450, $spanLimits->getAttributePerLinkCountLimit());
$this->assertEquals(Attributes::factory(450), $spanLimits->getLinkAttributesFactory());
}
}

View File

@ -56,7 +56,7 @@ class TracerTest extends TestCase
$sampler->method('shouldSample')
->willReturn(new SamplingResult(
SamplingResult::RECORD_AND_SAMPLE,
null,
[],
$newTraceState
));

View File

@ -92,10 +92,10 @@ class JaegerHttpSenderTest extends TestCase
$spans = [
(new SpanData())->setResource(ResourceInfo::create(
new Attributes(), //code should default service.name from how its set above
Attributes::create([]), //code should default service.name from how its set above
)),
(new SpanData())->setResource(ResourceInfo::create(
new Attributes([
Attributes::create([
'service.name' => 'nameOfThe2ndLogicalApp',
]),
)),
@ -124,10 +124,10 @@ class JaegerHttpSenderTest extends TestCase
$spans = [
(new SpanData())->setResource(ResourceInfo::create(
new Attributes(), //code should default service.name from how its set above
Attributes::create([]), //code should default service.name from how its set above
)),
(new SpanData())->setResource(ResourceInfo::create(
new Attributes([
Attributes::create([
'service.name' => 'nameOfThe2ndLogicalApp',
]),
)),
@ -155,10 +155,10 @@ class JaegerHttpSenderTest extends TestCase
$spans = [
(new SpanData())->setResource(ResourceInfo::create(
new Attributes(),
Attributes::create([]),
)),
(new SpanData())->setResource(ResourceInfo::create(
new Attributes([
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
]),
)),

View File

@ -63,7 +63,7 @@ class JaegerSpanConverterTest extends TestCase
->addAttribute('keyForFloat', 1.00)
->setResource(
ResourceInfo::create(
new Attributes([
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'php',
'telemetry.sdk.version' => 'dev',
@ -173,7 +173,7 @@ class JaegerSpanConverterTest extends TestCase
new Event(
'eventName',
1505855794194009601,
new Attributes([
Attributes::create([
'eventAttributeKey' => 'eventAttributeValue',
])
),
@ -198,7 +198,7 @@ class JaegerSpanConverterTest extends TestCase
new Event(
'eventName',
1505855794194009601,
new Attributes([
Attributes::create([
'event' => 'valueForTheEventAttributeOnTheEvent',
])
),
@ -219,7 +219,8 @@ class JaegerSpanConverterTest extends TestCase
->setLinks(
[
new Link(
SpanContext::getInvalid()
SpanContext::getInvalid(),
Attributes::create([]),
),
]
);

View File

@ -22,14 +22,14 @@ class NewrelicSpanConverterTest extends TestCase
->addAttribute('service', 'guard')
->setResource(
ResourceInfo::create(
new Attributes([
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'php',
'telemetry.sdk.version' => 'dev',
])
)
)
->addEvent('validators.list', new Attributes(['job' => 'stage.updateTime']), 1505855799433901068)
->addEvent('validators.list', Attributes::create(['job' => 'stage.updateTime']), 1505855799433901068)
->setHasEnded(true);
$converter = new SpanConverter('test.name');

View File

@ -36,8 +36,8 @@ class OTLPSpanConverterTest extends TestCase
->setName('batch.manager')
->addAttribute('attr1', 'apple')
->addAttribute('attr2', 'orange')
->addEvent('validators.list', new Attributes(['job' => 'stage.updateTime']), 1505855799433901068)
->addLink($context, new Attributes(['foo' => 'bar']))
->addEvent('validators.list', Attributes::create(['job' => 'stage.updateTime']), 1505855799433901068)
->addLink($context, Attributes::create(['foo' => 'bar']))
->setHasEnded(true);
$converter = new SpanConverter();
@ -152,7 +152,7 @@ class OTLPSpanConverterTest extends TestCase
)
->setResource(
ResourceInfo::create(
new Attributes([
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'php',
'telemetry.sdk.version' => 'dev',
@ -167,7 +167,7 @@ class OTLPSpanConverterTest extends TestCase
->setInstrumentationScope(new InstrumentationScope('lib-test', 'v0.1.0', 'http://url'))
->addAttribute('user', 'alice')
->addAttribute('authenticated', true)
->addEvent('Event1', new Attributes(['success' => 'yes']), 1617313804325769955)
->addEvent('Event1', Attributes::create(['success' => 'yes']), 1617313804325769955)
->setStatus(StatusData::ok())
->setHasEnded(true);
@ -253,7 +253,7 @@ class OTLPSpanConverterTest extends TestCase
{
$span = $this->createMock(SpanData::class);
$resource = $this->createMock(ResourceInfo::class);
$attributes = new Attributes(['foo' => 'foo', 'bar' => 'bar']);
$attributes = Attributes::create(['foo' => 'foo', 'bar' => 'bar']);
$span->method('getResource')->willReturn($resource);
$resource->method('getAttributes')->willReturn($attributes);
$converter = new SpanConverter();

View File

@ -47,7 +47,7 @@ class ZipkinSpanConverterTest extends TestCase
->addAttribute('peer.service', 'AuthService')
->setResource(
ResourceInfo::create(
new Attributes([
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'php',
'telemetry.sdk.version' => 'dev',
@ -56,7 +56,7 @@ class ZipkinSpanConverterTest extends TestCase
])
)
)
->addEvent('validators.list', new Attributes(['job' => 'stage.updateTime']), 1505855799433901068)
->addEvent('validators.list', Attributes::create(['job' => 'stage.updateTime']), 1505855799433901068)
->setHasEnded(true);
$converter = new SpanConverter('test.name');
@ -162,7 +162,7 @@ class ZipkinSpanConverterTest extends TestCase
public function test_should_convert_an_event_without_attributes_to_an_annotation_with_only_its_name(): void
{
$span = (new SpanData())
->addEvent('event.name', new Attributes());
->addEvent('event.name', Attributes::create([]));
$converter = new SpanConverter('test.name');
$row = $converter->convert([$span])[0];

View File

@ -23,14 +23,14 @@ class ZipkinToNewrelicSpanConverterTest extends TestCase
->addAttribute('service', 'guard')
->setResource(
ResourceInfo::create(
new Attributes([
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'php',
'telemetry.sdk.version' => 'dev',
])
)
)
->addEvent('validators.list', new Attributes(['job' => 'stage.updateTime']), 1505855799433901068)
->addEvent('validators.list', Attributes::create(['job' => 'stage.updateTime']), 1505855799433901068)
->setHasEnded(true);
$converter = new SpanConverter('test.name');

View File

@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Common\Attribute;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimits;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimitsInterface;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\SDK\Common\Attribute\AttributeLimits
*/
class AttributeLimitsTest extends TestCase
{
public function test_compare(): void
{
$attrLimits1 = new AttributeLimits(10, 20);
$attrLimits2 = new AttributeLimits(10, 20);
$attrLimits3 = new AttributeLimits(20, 30);
$this->assertEquals($attrLimits1, $attrLimits2);
$this->assertNotEquals($attrLimits1, $attrLimits3);
}
public function test_default_limits(): void
{
$limits = new AttributeLimits();
$this->assertSame(AttributeLimitsInterface::DEFAULT_COUNT_LIMIT, $limits->getAttributeCountLimit());
$this->assertSame(AttributeLimitsInterface::DEFAULT_VALUE_LENGTH_LIMIT, $limits->getAttributeValueLengthLimit());
}
public function test_limits(): void
{
$limits = new AttributeLimits(10, 20);
$this->assertSame(10, $limits->getAttributeCountLimit());
$this->assertSame(20, $limits->getAttributeValueLengthLimit());
}
}

View File

@ -4,32 +4,36 @@ declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Common\Attribute;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimits;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\SDK\Common\Attribute\Attributes
* @covers \OpenTelemetry\SDK\Common\Attribute\AttributesBuilder
* @covers \OpenTelemetry\SDK\Common\Attribute\AttributesFactory
*/
class AttributesTest extends TestCase
{
public function test_has_attribute(): void
{
$attributes = new Attributes([
$attributes = Attributes::create([
'foo' => 'foo',
]);
$this->assertFalse($attributes->hasAttribute('bar'));
$this->assertFalse($attributes->has('bar'));
$attributes->setAttribute('bar', 'bar');
$attributes = Attributes::create([
'foo' => 'foo',
'bar' => 'bar',
]);
$this->assertTrue($attributes->hasAttribute('bar'));
$this->assertTrue($attributes->has('bar'));
}
/** Test numeric attribute key is not cast to integer value */
public function test_numeric_attribute_name(): void
{
$attributes = new Attributes(['1' => '2']);
$attributes = Attributes::create(['1' => '2']);
$this->assertCount(1, $attributes);
foreach ($attributes as $key => $value) {
$this->assertIsString($key);
@ -48,8 +52,7 @@ class AttributesTest extends TestCase
$longStringValue = '0123456789abcdefghijklmnopqrstuvwxyz';
$longStringTrimmed = '0123456789abcdef';
$attributeLimits = new AttributeLimits(6, 16);
$attributes = new Attributes([
$attributes = Attributes::factory(6, 16)->builder([
'bool' => true,
'int' => $intValue,
'float' => $floatValue,
@ -61,7 +64,7 @@ class AttributesTest extends TestCase
true,
],
'ignored_key' => 'ignored_value',
], $attributeLimits);
])->build();
$this->assertTrue($attributes->get('bool'));
$this->assertEquals($intValue, $attributes->get('int'));
@ -78,12 +81,12 @@ class AttributesTest extends TestCase
*/
public function test_apply_limits(): void
{
$attributes = new Attributes([
$attributes = Attributes::create([
'short' => '123',
'long' => '1234567890',
'dropped' => true,
]);
$limitedAttributes = Attributes::withLimits($attributes, new AttributeLimits(2, 5));
$limitedAttributes = Attributes::factory(2, 5)->builder($attributes)->build();
$this->assertCount(2, $limitedAttributes);
$this->assertEquals('123', $limitedAttributes->get('short'));
$this->assertEquals('12345', $limitedAttributes->get('long'));
@ -93,24 +96,24 @@ class AttributesTest extends TestCase
public function test_null_attribute_removes_existing(): void
{
$attributes = new Attributes([
$attributesBuilder = Attributes::factory()->builder([
'foo' => 'foo',
'bar' => 'bar',
'baz' => 'baz',
]);
$this->assertCount(3, $attributes);
$attributes->setAttribute('foo', null);
$this->assertCount(2, $attributes);
$this->assertCount(3, $attributesBuilder->build());
$attributesBuilder['foo'] = null;
$this->assertCount(2, $attributesBuilder->build());
}
public function test_null_missing_attribute_does_nothing(): void
{
$attributes = new Attributes([
$attributesBuilder = Attributes::factory()->builder([
'foo' => 'foo',
]);
$this->assertCount(1, $attributes);
$attributes->setAttribute('bar', null);
$this->assertCount(1, $attributes);
$this->assertCount(1, $attributesBuilder->build());
$attributesBuilder['bar'] = null;
$this->assertCount(1, $attributesBuilder->build());
}
public function test_to_array(): void
@ -119,82 +122,53 @@ class AttributesTest extends TestCase
'foo' => 'foo',
'bar' => 'bar',
];
$attributes = new Attributes($values);
$attributes = Attributes::create($values);
$this->assertSame($values, $attributes->toArray());
}
public function test_get_total_added_values(): void
public function test_get_dropped_attributes_count(): void
{
$attributes = new Attributes([
$attributesBuilder = Attributes::factory()->builder([
'foo' => 'foo',
'bar' => 'bar',
]);
$this->assertEquals(2, $attributes->getTotalAddedValues());
$this->assertEquals(0, $attributesBuilder->build()->getDroppedAttributesCount());
$attributes->setAttribute('baz', 'baz');
$this->assertEquals(3, $attributes->getTotalAddedValues());
$attributesBuilder['baz'] = 'baz';
$this->assertEquals(0, $attributesBuilder->build()->getDroppedAttributesCount());
}
public function test_unset_get_total_added_values(): void
public function test_unset_get_dropped_attributes_count(): void
{
$attributes = new Attributes([
$attributesBuilder = Attributes::factory()->builder([
'foo' => 'foo',
'bar' => 'bar',
]);
$this->assertEquals(2, $attributes->getTotalAddedValues());
$this->assertEquals(0, $attributesBuilder->build()->getDroppedAttributesCount());
$attributes->unsetAttribute('foo');
$this->assertEquals(1, $attributes->getTotalAddedValues());
$attributesBuilder->offsetUnset('foo');
$this->assertEquals(0, $attributesBuilder->build()->getDroppedAttributesCount());
}
public function test_limit_get_total_added_values(): void
public function test_limit_get_dropped_attributes_count(): void
{
$attributes = new Attributes([
$attributesBuilder = Attributes::factory(1)->builder([
'foo' => 'foo',
'bar' => 'bar',
], new AttributeLimits(1));
$this->assertEquals(2, $attributes->getTotalAddedValues());
]);
$this->assertEquals(1, $attributesBuilder->build()->getDroppedAttributesCount());
$attributes->setAttribute('baz', 'baz');
$this->assertEquals(3, $attributes->getTotalAddedValues());
$attributesBuilder['baz'] = 'baz';
$this->assertEquals(2, $attributesBuilder->build()->getDroppedAttributesCount());
}
public function test_replace_attribute_does_not_increase_count(): void
public function test_replace_attribute_does_not_increase_dropped_attributes_count(): void
{
$attributes = new Attributes([
$attributesBuilder = Attributes::factory(2)->builder([
'foo' => 'foo',
], new AttributeLimits(2));
]);
$attributes->setAttribute('foo', 'bar');
$this->assertEquals(1, $attributes->getTotalAddedValues());
$this->assertEquals(0, $attributes->getDroppedAttributesCount());
}
public function test_count_dropped_attributes(): void
{
$attributes = new Attributes([
'foo' => 'foo',
'bar' => 'bar',
], new AttributeLimits(1));
$this->assertEquals(1, $attributes->getTotalAddedValues() - count($attributes));
$attributes->setAttribute('baz', 'baz');
$this->assertEquals(2, $attributes->getTotalAddedValues() - count($attributes));
}
public function test_is_limit_reached(): void
{
$attributes = new Attributes([
'foo' => 'foo',
'bar' => 'bar',
], new AttributeLimits(3));
$this->assertFalse($attributes->isLimitReached());
$attributes->setAttribute('baz', 'baz');
$this->assertTrue($attributes->isLimitReached());
$attributesBuilder['foo'] = 'bar';
$this->assertEquals(0, $attributesBuilder->build()->getDroppedAttributesCount());
}
}

View File

@ -26,7 +26,7 @@ class CompositeTest extends TestCase
public function test_composite_get_resource(): void
{
$resource = ResourceInfo::create(new Attributes(['foo' => 'user-foo', 'bar' => 'user-bar']));
$resource = ResourceInfo::create(Attributes::create(['foo' => 'user-foo', 'bar' => 'user-bar']));
$resourceDetector = $this->createMock(ResourceDetectorInterface::class);
$resourceDetector->method('getResource')->willReturn($resource);

View File

@ -16,7 +16,7 @@ class ConstantTest extends TestCase
{
public function test_constant_get_resource_with_empty_resource(): void
{
$resouceDetector = new Detectors\Constant(ResourceInfo::create(new Attributes()));
$resouceDetector = new Detectors\Constant(ResourceInfo::create(Attributes::create([])));
$resource = $resouceDetector->getResource();
$this->assertNull($resource->getSchemaUrl());
@ -25,7 +25,7 @@ class ConstantTest extends TestCase
public function test_constant_get_resource_with_custom_resource(): void
{
$resouceDetector = new Detectors\Constant(ResourceInfo::create(new Attributes(['foo' => 'user-foo', 'bar' => 'user-bar'])));
$resouceDetector = new Detectors\Constant(ResourceInfo::create(Attributes::create(['foo' => 'user-foo', 'bar' => 'user-bar'])));
$resource = $resouceDetector->getResource();
$this->assertNull($resource->getSchemaUrl());

View File

@ -31,8 +31,8 @@ class ResourceInfoFactoryTest extends TestCase
public function test_merge(): void
{
$primary = ResourceInfo::create(new Attributes(['name' => 'primary', 'empty' => '']));
$secondary = ResourceInfo::create(new Attributes(['version' => '1.0.0', 'empty' => 'value']));
$primary = ResourceInfo::create(Attributes::create(['name' => 'primary', 'empty' => '']));
$secondary = ResourceInfo::create(Attributes::create(['version' => '1.0.0', 'empty' => 'value']));
$result = ResourceInfoFactory::merge($primary, $secondary);
$name = $result->getAttributes()->get('name');
@ -52,7 +52,7 @@ class ResourceInfoFactoryTest extends TestCase
{
$resourcesToMerge = [];
foreach ($schemaUrlsToMerge as $schemaUrl) {
$resourcesToMerge[] = ResourceInfo::create(new Attributes([]), $schemaUrl);
$resourcesToMerge[] = ResourceInfo::create(Attributes::create([]), $schemaUrl);
}
$result = ResourceInfoFactory::merge(...$resourcesToMerge);

View File

@ -27,8 +27,7 @@ class ResourceInfoTest extends TestCase
public function test_get_attributes(): void
{
$attributes = new Attributes();
$attributes->setAttribute('name', 'test');
$attributes = Attributes::create(['name' => 'test']);
$resource = (new Detectors\Composite([
new Detectors\Constant(ResourceInfo::create($attributes)),
@ -43,33 +42,12 @@ class ResourceInfoTest extends TestCase
$sdklanguage = $resource->getAttributes()->get(ResourceAttributes::TELEMETRY_SDK_LANGUAGE);
$sdkversion = $resource->getAttributes()->get(ResourceAttributes::TELEMETRY_SDK_VERSION);
$attributes->setAttribute(ResourceAttributes::TELEMETRY_SDK_NAME, 'opentelemetry');
$attributes->setAttribute(ResourceAttributes::TELEMETRY_SDK_LANGUAGE, 'php');
$attributes->setAttribute(ResourceAttributes::TELEMETRY_SDK_VERSION, $version);
$attributes->setAttribute(ResourceAttributes::SERVICE_NAME, 'unknown_service');
$this->assertEquals($attributes, $resource->getAttributes());
$this->assertSame('opentelemetry', $sdkname);
$this->assertSame('php', $sdklanguage);
$this->assertSame($version, $sdkversion);
$this->assertSame('test', $name);
}
public function test_immutable_create(): void
{
$attributes = new Attributes();
$attributes->setAttribute('name', 'test');
$attributes->setAttribute('version', '1.0.0');
$resource = ResourceInfo::create($attributes);
$attributes->setAttribute('version', '2.0.0');
$version = $resource->getAttributes()->get('version');
$this->assertEquals('1.0.0', $version);
}
/**
* @dataProvider sameResourcesProvider
*/
@ -81,12 +59,12 @@ class ResourceInfoTest extends TestCase
public function sameResourcesProvider(): iterable
{
yield 'Attribute keys sorted in ascending order vs Attribute keys sorted in descending order' => [
ResourceInfo::create(new Attributes([
ResourceInfo::create(Attributes::create([
'a' => 'someValue',
'b' => 'someValue',
'c' => 'someValue',
])),
ResourceInfo::create(new Attributes([
ResourceInfo::create(Attributes::create([
'c' => 'someValue',
'b' => 'someValue',
'a' => 'someValue',
@ -105,8 +83,8 @@ class ResourceInfoTest extends TestCase
public function differentResourcesProvider(): iterable
{
yield 'Null schema url vs Some schema url' => [
ResourceInfo::create(new Attributes(), null),
ResourceInfo::create(new Attributes(), 'someSchemaUrl'),
ResourceInfo::create(Attributes::create([]), null),
ResourceInfo::create(Attributes::create([]), 'someSchemaUrl'),
];
}

View File

@ -32,7 +32,6 @@ class ImmutableSpanTest extends TestCase
private string $parentSpanId = 'parent-span-id';
private int $endEpochNanos = 2000;
private int $startEpochNanes = 1000;
private int $totalAttributeCount = 1;
private int $totalRecordedEvents = 1;
private int $totalRecordedLinks = 1;
@ -67,7 +66,6 @@ class ImmutableSpanTest extends TestCase
[],
[],
$this->attributes,
$this->totalAttributeCount,
$this->totalRecordedEvents,
$this->status,
$this->endEpochNanos,
@ -88,7 +86,6 @@ class ImmutableSpanTest extends TestCase
$this->assertSame([], $span->getLinks());
$this->assertSame([], $span->getEvents());
$this->assertSame($this->attributes, $span->getAttributes());
$this->assertSame(1, $span->getTotalDroppedAttributes());
$this->assertSame(1, $span->getTotalDroppedEvents());
$this->assertSame(1, $span->getTotalDroppedLinks());
$this->assertSame($this->status, $span->getStatus());

View File

@ -30,12 +30,5 @@ class LinkTest extends TestCase
$this->assertSame($this->context, $link->getSpanContext());
$this->assertSame($this->attributes, $link->getAttributes());
$this->assertSame(5, $link->getTotalAttributeCount());
}
public function test_null_attributes(): void
{
$link = new Link($this->context);
$this->assertSame(0, $link->getTotalAttributeCount());
}
}

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Trace;
use OpenTelemetry\API\Trace\TraceStateInterface;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\SamplingResult;
use PHPUnit\Framework\TestCase;
@ -32,11 +31,11 @@ class SamplingResultTest extends TestCase
{
return [
[
new Attributes(['foo' => 'bar']),
['foo' => 'bar'],
$this->createMock(TraceStateInterface::class),
],
[
null,
[],
null,
],
];

View File

@ -6,7 +6,7 @@ namespace OpenTelemetry\Tests\Unit\SDK\Trace;
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
use Exception;
use OpenTelemetry\SDK\Trace\SpanLimits;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Trace\SpanLimitsBuilder;
use PHPUnit\Framework\TestCase;
@ -21,7 +21,7 @@ class SpanLimitsBuilderTest extends TestCase
{
$builder = new SpanLimitsBuilder();
$spanLimits = $builder->build();
$this->assertEquals(SpanLimits::DEFAULT_EVENT_ATTRIBUTE_COUNT_LIMIT, $spanLimits->getAttributeLimits()->getAttributeCountLimit());
$this->assertEquals(Attributes::factory(128), $spanLimits->getAttributesFactory());
}
/**
@ -32,7 +32,7 @@ class SpanLimitsBuilderTest extends TestCase
$this->setEnvironmentVariable('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT', 111);
$builder = new SpanLimitsBuilder();
$spanLimits = $builder->build();
$this->assertEquals(111, $spanLimits->getAttributeLimits()->getAttributeCountLimit());
$this->assertEquals(Attributes::factory(111), $spanLimits->getAttributesFactory());
}
/**
@ -44,7 +44,7 @@ class SpanLimitsBuilderTest extends TestCase
$builder = new SpanLimitsBuilder();
$builder->setAttributeCountLimit(222);
$spanLimits = $builder->build();
$this->assertEquals(222, $spanLimits->getAttributeLimits()->getAttributeCountLimit());
$this->assertEquals(Attributes::factory(222), $spanLimits->getAttributesFactory());
}
/**

View File

@ -84,9 +84,9 @@ class SpanTest extends MockeryTestCase
$this->spanContext = SpanContext::create($this->traceId, $this->spanId);
$this->testClock = new TestClock(self::START_EPOCH);
$this->link = new Link($this->spanContext);
$this->link = new Link($this->spanContext, Attributes::create([]));
$this->expectedAttributes = new Attributes(
$this->expectedAttributes = Attributes::create(
array_merge(
['single_string_attribute' => 'some_string_value'],
self::ATTRIBUTES
@ -224,7 +224,7 @@ class SpanTest extends MockeryTestCase
$this->assertSpanData(
$span->toSpanData(),
new Attributes(),
Attributes::create([]),
[],
[$this->link],
self::SPAN_NAME,
@ -259,7 +259,7 @@ class SpanTest extends MockeryTestCase
$this->assertSpanData(
$span->toSpanData(),
$this->expectedAttributes,
[new Event('event2', self::START_EPOCH + ClockInterface::NANOS_PER_SECOND)],
[new Event('event2', self::START_EPOCH + ClockInterface::NANOS_PER_SECOND, Attributes::create([]))],
[$this->link],
self::NEW_SPAN_NAME,
self::START_EPOCH,
@ -295,7 +295,7 @@ class SpanTest extends MockeryTestCase
$this->assertSpanData(
$span->toSpanData(),
$this->expectedAttributes,
[new Event('event2', self::START_EPOCH + ClockInterface::NANOS_PER_SECOND)],
[new Event('event2', self::START_EPOCH + ClockInterface::NANOS_PER_SECOND, Attributes::create([]))],
[$this->link],
self::NEW_SPAN_NAME,
self::START_EPOCH,
@ -335,7 +335,7 @@ class SpanTest extends MockeryTestCase
$spanData = $span->toSpanData();
$this->assertSame(count(self::ATTRIBUTES) + 1, $spanData->getAttributes()->count());
$this->assertSame(0, $spanData->getTotalDroppedAttributes());
$this->assertSame(0, $spanData->getAttributes()->getDroppedAttributesCount());
}
/**
@ -401,14 +401,6 @@ class SpanTest extends MockeryTestCase
$span->end();
}
public function test_set_attribute_empty_key(): void
{
$span = $this->createTestSpan();
$this->assertEmpty($span->toSpanData()->getAttributes());
$span->setAttribute(' ', 123);
$this->assertEmpty($span->toSpanData()->getAttributes());
}
public function test_get_instrumentation_scope_info(): void
{
$span = $this->createTestSpanWithAttributes(self::ATTRIBUTES);
@ -460,12 +452,12 @@ class SpanTest extends MockeryTestCase
{
$span = $this->createTestRootSpan();
$attributes = new Attributes([
$attributes = [
'string' => 'str',
'empty_str' => '',
'null' => null,
'str_array' => ['a', 'b'],
]);
];
$span->setAttributes($attributes);
$span->end();
@ -481,14 +473,14 @@ class SpanTest extends MockeryTestCase
{
$span = $this->createTestSpanWithAttributes(self::ATTRIBUTES);
$this->assertFalse($span->toSpanData()->getAttributes()->get('bool_attribute'));
$span->setAttributes(new Attributes(['bool_attribute' => true]));
$span->setAttributes(['bool_attribute' => true]);
$this->assertTrue($span->toSpanData()->getAttributes()->get('bool_attribute'));
}
public function test_set_attributes_empty(): void
{
$span = $this->createTestRootSpan();
$span->setAttributes(new Attributes());
$span->setAttributes([]);
$this->assertEmpty($span->toSpanData()->getAttributes());
}
@ -500,7 +492,7 @@ class SpanTest extends MockeryTestCase
{
$span = $this->createTestRootSpan();
$span->addEvent('event1');
$span->addEvent('event2', new Attributes(['key1' => 1]));
$span->addEvent('event2', ['key1' => 1]);
$span->addEvent('event3', [], TimeUtil::secondsToNanos(10));
$span->end();
@ -509,9 +501,9 @@ class SpanTest extends MockeryTestCase
$this->assertCount(3, $events);
$idx = 0;
$this->assertEvent($events[$idx++], 'event1', new Attributes(), self::START_EPOCH);
$this->assertEvent($events[$idx++], 'event2', new Attributes(['key1' => 1]), self::START_EPOCH);
$this->assertEvent($events[$idx], 'event3', new Attributes(), TimeUtil::secondsToNanos(10));
$this->assertEvent($events[$idx++], 'event1', Attributes::create([]), self::START_EPOCH);
$this->assertEvent($events[$idx++], 'event2', Attributes::create(['key1' => 1]), self::START_EPOCH);
$this->assertEvent($events[$idx], 'event3', Attributes::create([]), TimeUtil::secondsToNanos(10));
}
public function test_add_event_attribute_length(): void
@ -525,7 +517,7 @@ class SpanTest extends MockeryTestCase
$span->addEvent(
'event',
new Attributes([
Attributes::create([
'string' => $tooLongStrVal,
'bool' => true,
'string_array' => [$strVal, $tooLongStrVal],
@ -568,7 +560,7 @@ class SpanTest extends MockeryTestCase
$this->assertSame('exception', $event->getName());
$this->assertSame($timestamp, $event->getEpochNanos());
$this->assertEquals(
new Attributes([
Attributes::create([
'exception.type' => 'Exception',
'exception.message' => 'ERR',
'exception.stacktrace' => StackTraceFormatter::format($exception),
@ -585,16 +577,16 @@ class SpanTest extends MockeryTestCase
$this->testClock->advance(1000);
$timestamp = $this->testClock->now();
$span->recordException($exception, new Attributes([
$span->recordException($exception, [
'foo' => 'bar',
]));
]);
$this->assertCount(1, $events = $span->toSpanData()->getEvents());
$event = $events[0];
$this->assertSame('exception', $event->getName());
$this->assertSame($timestamp, $event->getEpochNanos());
$this->assertEquals(
new Attributes([
Attributes::create([
'exception.type' => 'Exception',
'exception.message' => 'ERR',
'exception.stacktrace' => StackTraceFormatter::format($exception),
@ -615,7 +607,7 @@ class SpanTest extends MockeryTestCase
API\SpanKind::KIND_INTERNAL,
(new SpanLimitsBuilder())->setAttributeValueLengthLimit($maxLength)->build(),
null,
new Attributes([
Attributes::create([
'string' => $tooLongStrVal,
'bool' => true,
'string_array' => [$strVal, $tooLongStrVal],
@ -653,42 +645,42 @@ class SpanTest extends MockeryTestCase
$spanData = $span->toSpanData();
$this->assertCount($maxNumberOfAttributes, $spanData->getAttributes());
$this->assertSame(8, $spanData->getTotalDroppedAttributes());
$this->assertSame(8, $spanData->getAttributes()->getDroppedAttributesCount());
$span->end();
$spanData = $span->toSpanData();
$this->assertCount($maxNumberOfAttributes, $spanData->getAttributes());
$this->assertSame(8, $spanData->getTotalDroppedAttributes());
$this->assertSame(8, $spanData->getAttributes()->getDroppedAttributesCount());
}
public function test_dropping_attributes_provided_via_span_builder(): void
{
$maxNumberOfAttributes = 8;
$attributes = new Attributes();
$attributesBuilder = Attributes::factory()->builder();
foreach (range(1, $maxNumberOfAttributes * 2) as $idx) {
$attributes->setAttribute("str_attribute_${idx}", $idx);
$attributesBuilder["str_attribute_${idx}"] = $idx;
}
$span = $this->createTestSpan(
API\SpanKind::KIND_INTERNAL,
(new SpanLimitsBuilder())->setAttributeCountLimit($maxNumberOfAttributes)->build(),
null,
$attributes
$attributesBuilder->build(),
);
$spanData = $span->toSpanData();
$this->assertCount($maxNumberOfAttributes, $spanData->getAttributes());
$this->assertSame(8, $spanData->getTotalDroppedAttributes());
$this->assertSame(8, $spanData->getAttributes()->getDroppedAttributesCount());
$span->end();
$spanData = $span->toSpanData();
$this->assertCount($maxNumberOfAttributes, $spanData->getAttributes());
$this->assertSame(8, $spanData->getTotalDroppedAttributes());
$this->assertSame(8, $spanData->getAttributes()->getDroppedAttributesCount());
}
public function test_dropping_events(): void
@ -717,11 +709,11 @@ class SpanTest extends MockeryTestCase
{
$span = $this->createTestRootSpan();
$attributes = new Attributes([
$attributes = [
'string' => 'str_val',
'empty_key' => '',
'str_array' => ['f', 'b'],
]);
];
$span->setAttribute('str_array', ['a', 'b']);
$span->setAttribute('string', 'str');
@ -743,15 +735,15 @@ class SpanTest extends MockeryTestCase
$span = $this->createTestRootSpan();
$span->addEvent('a');
$span->addEvent('b');
$span->addEvent('c', new Attributes(['key' => 2]));
$span->addEvent('c', ['key' => 2]);
$span->end();
$events = $span->toSpanData()->getEvents();
$this->assertEvent($events[0], 'a', new Attributes(), self::START_EPOCH);
$this->assertEvent($events[1], 'b', new Attributes(), self::START_EPOCH);
$this->assertEvent($events[2], 'c', new Attributes(['key' => 2]), self::START_EPOCH);
$this->assertEvent($events[0], 'a', Attributes::create([]), self::START_EPOCH);
$this->assertEvent($events[1], 'b', Attributes::create([]), self::START_EPOCH);
$this->assertEvent($events[2], 'c', Attributes::create(['key' => 2]), self::START_EPOCH);
}
private function createTestRootSpan(): Span
@ -772,7 +764,7 @@ class SpanTest extends MockeryTestCase
int $kind = API\SpanKind::KIND_INTERNAL,
SpanLimits $spanLimits = null,
string $parentSpanId = null,
?AttributesInterface $attributes = null,
iterable $attributes = [],
array $links = []
): Span {
$parentSpanId = $parentSpanId ?? $this->parentSpanId;
@ -789,7 +781,7 @@ class SpanTest extends MockeryTestCase
$spanLimits,
$this->spanProcessor,
$this->resource,
$attributes,
$spanLimits->getAttributesFactory()->builder($attributes),
$links,
1,
0
@ -811,7 +803,7 @@ class SpanTest extends MockeryTestCase
API\SpanKind::KIND_INTERNAL,
null,
null,
new Attributes($attributes),
Attributes::create($attributes),
);
}

View File

@ -8,6 +8,7 @@ use function count;
use function max;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesBuilderInterface;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScope;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
@ -30,14 +31,13 @@ class SpanData implements SDK\SpanDataInterface
*/
private array $links = [];
private AttributesInterface $attributes;
private AttributesBuilderInterface $attributesBuilder;
private int $kind;
private StatusData $status;
private ResourceInfo $resource;
private InstrumentationScope $instrumentationScope;
private API\SpanContextInterface $context;
private API\SpanContextInterface $parentContext;
private int $totalAttributeCount = 0;
private int $totalRecordedEvents = 0;
private int $totalRecordedLinks = 0;
private int $startEpochNanos = 1505855794194009601;
@ -46,7 +46,7 @@ class SpanData implements SDK\SpanDataInterface
public function __construct()
{
$this->attributes = new Attributes();
$this->attributesBuilder = Attributes::factory()->builder();
$this->kind = API\SpanKind::KIND_INTERNAL;
$this->status = StatusData::unset();
$this->resource = ResourceInfoFactory::emptyResource();
@ -82,7 +82,7 @@ class SpanData implements SDK\SpanDataInterface
return $this;
}
public function addLink(API\SpanContextInterface $context, AttributesInterface $attributes = null): self
public function addLink(API\SpanContextInterface $context, AttributesInterface $attributes): self
{
$this->links[] = new SDK\Link($context, $attributes);
@ -103,7 +103,7 @@ class SpanData implements SDK\SpanDataInterface
return $this;
}
public function addEvent(string $name, ?AttributesInterface $attributes, int $timestamp = null): self
public function addEvent(string $name, AttributesInterface $attributes, int $timestamp = null): self
{
$this->events[] = new SDK\Event($name, $timestamp ?? ClockFactory::getDefault()->now(), $attributes);
@ -112,31 +112,12 @@ class SpanData implements SDK\SpanDataInterface
public function getAttributes(): AttributesInterface
{
return $this->attributes;
}
public function setAttributes(AttributesInterface $attributes): self
{
$this->attributes = $attributes;
return $this;
return $this->attributesBuilder->build();
}
public function addAttribute(string $key, $value): self
{
$this->attributes->setAttribute($key, $value);
return $this;
}
public function getTotalDroppedAttributes(): int
{
return max(0, $this->totalAttributeCount - count($this->attributes));
}
public function setTotalAttributeCount(int $totalAttributeCount): self
{
$this->totalAttributeCount = $totalAttributeCount;
$this->attributesBuilder[$key] = $value;
return $this;
}