Map OTEL Resources to Jaeger Process Tags (#636)
* Commit in progress work because Gitpod is weird * Finish initial stab at the changes * Forgot to update the exporter * Add in proper handling of serialization of ResourceInfo * ksort doesn't return the array... * Only PHP 8.1 supports key-ed array destructuring * Creating some adapters to break the hard dependency on Batch to make testing easier * Refactoring to break the hard dependency on Batch * Add initial unit tests around the new logic in HttpSender * Some refactoring of the test's helpers * Another small refactor * Some more refactoring * Rename ResourceInfo's test file to match it's file name * Move a test our of REsourceInfoTest into a more appropriate file * Add some basic conformance tests around the new ResourceInfo::serialize method * Add a test to try and catch future properties that aren't added to ResourceInfo::serialize * CLean up comments * Replace string with constant * Improve variable names * Cleaning up comment * Split out tag creation into a helper class * Phan didn't like the type docs * Fix style * Fix tests after merge from main * Fix coverage reporting issues on 2 of the new files * Fix style * Rename vals to values * Shortening the batch adapter factory method name to create * Inline a method call * Inline some method calls * Shorten factory method to just "create" * Inline some code * Split assertions into 3 tests * Rename parameter in interface implementation for psalm + update the rest of the file to match Co-authored-by: Timo Michna <timomichna@yahoo.de>
This commit is contained in:
parent
a2f64053da
commit
39c99e5a2f
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Contrib\Jaeger\BatchAdapter;
|
||||
|
||||
use Jaeger\Thrift\Batch;
|
||||
use Thrift\Protocol\TProtocol;
|
||||
|
||||
class BatchAdapter implements BatchAdapterInterface
|
||||
{
|
||||
private Batch $batchInstance;
|
||||
|
||||
public function __construct(array $values)
|
||||
{
|
||||
$this->batchInstance = new Batch($values);
|
||||
}
|
||||
|
||||
public function write(TProtocol $output): void
|
||||
{
|
||||
$this->batchInstance->write($output);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Contrib\Jaeger\BatchAdapter;
|
||||
|
||||
class BatchAdapterFactory implements BatchAdapterFactoryInterface
|
||||
{
|
||||
public function create(array $values): BatchAdapterInterface
|
||||
{
|
||||
return new BatchAdapter($values);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Contrib\Jaeger\BatchAdapter;
|
||||
|
||||
interface BatchAdapterFactoryInterface
|
||||
{
|
||||
public function create(array $values): BatchAdapterInterface;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Contrib\Jaeger\BatchAdapter;
|
||||
|
||||
use Thrift\Protocol\TProtocol;
|
||||
|
||||
interface BatchAdapterInterface
|
||||
{
|
||||
public function write(TProtocol $output): void;
|
||||
}
|
||||
|
|
@ -18,8 +18,6 @@ class HttpCollectorExporter implements SpanExporterInterface
|
|||
use UsesSpanConverterTrait;
|
||||
use SpanExporterTrait;
|
||||
|
||||
private SpanConverter $spanConverter;
|
||||
|
||||
private HttpSender $sender;
|
||||
|
||||
public function __construct(
|
||||
|
|
@ -39,8 +37,6 @@ class HttpCollectorExporter implements SpanExporterInterface
|
|||
$name,
|
||||
$parsedEndpoint
|
||||
);
|
||||
|
||||
$this->spanConverter = new SpanConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -48,9 +44,7 @@ class HttpCollectorExporter implements SpanExporterInterface
|
|||
*/
|
||||
public function doExport(iterable $spans): int
|
||||
{
|
||||
$this->sender->send(
|
||||
$this->spanConverter->convert($spans)
|
||||
);
|
||||
$this->sender->send($spans);
|
||||
|
||||
return SpanExporterInterface::STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace OpenTelemetry\Contrib\Jaeger;
|
||||
|
||||
use Jaeger\Thrift\Batch;
|
||||
use Jaeger\Thrift\Process;
|
||||
use Jaeger\Thrift\Span as JTSpan;
|
||||
use OpenTelemetry\Contrib\Jaeger\BatchAdapter\BatchAdapterFactory;
|
||||
use OpenTelemetry\Contrib\Jaeger\BatchAdapter\BatchAdapterFactoryInterface;
|
||||
use OpenTelemetry\Contrib\Jaeger\BatchAdapter\BatchAdapterInterface;
|
||||
use OpenTelemetry\Contrib\Jaeger\TagFactory\TagFactory;
|
||||
use OpenTelemetry\SDK\Behavior\LogsMessagesTrait;
|
||||
use OpenTelemetry\SDK\Resource\ResourceInfo;
|
||||
use OpenTelemetry\SemConv\ResourceAttributes;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Psr\Http\Message\RequestFactoryInterface;
|
||||
use Psr\Http\Message\StreamFactoryInterface;
|
||||
|
|
@ -22,75 +26,104 @@ class HttpSender
|
|||
|
||||
private TProtocol $protocol;
|
||||
|
||||
private BatchAdapterFactoryInterface $batchAdapterFactory;
|
||||
|
||||
public function __construct(
|
||||
ClientInterface $client,
|
||||
RequestFactoryInterface $requestFactory,
|
||||
StreamFactoryInterface $streamFactory,
|
||||
string $serviceName,
|
||||
ParsedEndpointUrl $parsedEndpoint
|
||||
ParsedEndpointUrl $parsedEndpoint,
|
||||
BatchAdapterFactoryInterface $batchAdapterFactory = null
|
||||
) {
|
||||
$this->serviceName = $serviceName;
|
||||
|
||||
$transport = (new ThriftHttpTransport(
|
||||
$client,
|
||||
$requestFactory,
|
||||
$streamFactory,
|
||||
$parsedEndpoint
|
||||
));
|
||||
$this->protocol = new TBinaryProtocol(
|
||||
new ThriftHttpTransport(
|
||||
$client,
|
||||
$requestFactory,
|
||||
$streamFactory,
|
||||
$parsedEndpoint
|
||||
)
|
||||
);
|
||||
|
||||
$this->protocol = new TBinaryProtocol($transport);
|
||||
$this->batchAdapterFactory = $batchAdapterFactory ?? new BatchAdapterFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param JTSpan[] $spans
|
||||
*/
|
||||
public function send(array $spans): void
|
||||
public function send(iterable $spans): void
|
||||
{
|
||||
///** @var Tag[] $tags */ TODO - uncomment this once the code below is uncommented/adapted
|
||||
$batches = $this->createBatchesPerResource(
|
||||
self::groupSpansByResource($spans)
|
||||
);
|
||||
|
||||
foreach ($batches as $batch) {
|
||||
$this->sendBatch($batch);
|
||||
}
|
||||
}
|
||||
|
||||
private static function groupSpansByResource(iterable $spans): array
|
||||
{
|
||||
$spansGroupedByResource = [];
|
||||
foreach ($spans as $span) {
|
||||
/** @var ResourceInfo */
|
||||
$resource = $span->getResource();
|
||||
$resourceAsKey = $resource->serialize();
|
||||
|
||||
if (!isset($spansGroupedByResource[$resourceAsKey])) {
|
||||
$spansGroupedByResource[$resourceAsKey] = [
|
||||
'spans' => [],
|
||||
'resource' => $resource,
|
||||
];
|
||||
}
|
||||
|
||||
$spansGroupedByResource[$resourceAsKey]['spans'][] = $span;
|
||||
}
|
||||
|
||||
return $spansGroupedByResource;
|
||||
}
|
||||
|
||||
private function createBatchesPerResource(array $spansGroupedByResource): array
|
||||
{
|
||||
$batches = [];
|
||||
foreach ($spansGroupedByResource as $unused => $dataForBatch) {
|
||||
$batch = $this->batchAdapterFactory->create([
|
||||
'spans' => (new SpanConverter())->convert(
|
||||
$dataForBatch['spans']
|
||||
),
|
||||
'process' => $this->createProcessFromResource(
|
||||
$dataForBatch['resource']
|
||||
),
|
||||
]);
|
||||
|
||||
$batches[] = $batch;
|
||||
}
|
||||
|
||||
return $batches;
|
||||
}
|
||||
|
||||
private function createProcessFromResource(ResourceInfo $resource): Process
|
||||
{
|
||||
$serviceName = $this->serviceName; //Defaulting to (what should be) the default resource's service name
|
||||
|
||||
$tags = [];
|
||||
foreach ($resource->getAttributes() as $key => $value) {
|
||||
if ($key === ResourceAttributes::SERVICE_NAME) {
|
||||
$serviceName = (string) $value;
|
||||
|
||||
//TODO - determine what of this is still needed and how to adapt it for spec compliance
|
||||
// foreach ($this->tracer->getTags() as $k => $v) {
|
||||
// if (!in_array($k, $this->mapper->getSpecialSpanTags())) {
|
||||
// if (strpos($k, $this->mapper->getProcessTagsPrefix()) !== 0) {
|
||||
// continue ;
|
||||
// }
|
||||
continue;
|
||||
}
|
||||
|
||||
// $quoted = preg_quote($this->mapper->getProcessTagsPrefix());
|
||||
// $k = preg_replace(sprintf('/^%s/', $quoted), '', $k);
|
||||
// }
|
||||
$tags[] = TagFactory::create($key, $value);
|
||||
}
|
||||
|
||||
// if ($k === JAEGER_HOSTNAME_TAG_KEY) {
|
||||
// $k = "hostname";
|
||||
// }
|
||||
|
||||
// $tags[] = new Tag([
|
||||
// "key" => $k,
|
||||
// "vType" => TagType::STRING,
|
||||
// "vStr" => $v
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// $tags[] = new Tag([
|
||||
// "key" => "format",
|
||||
// "vType" => TagType::STRING,
|
||||
// "vStr" => "jaeger.thrift"
|
||||
// ]);
|
||||
|
||||
// $tags[] = new Tag([
|
||||
// "key" => "ip",
|
||||
// "vType" => TagType::STRING,
|
||||
// "vStr" => $this->tracer->getIpAddress()
|
||||
// ]);
|
||||
|
||||
$batch = new Batch([
|
||||
'spans' => $spans,
|
||||
'process' => new Process([
|
||||
'serviceName' => $this->serviceName,
|
||||
'tags' => $tags,
|
||||
]),
|
||||
return new Process([
|
||||
'serviceName' => $serviceName,
|
||||
'tags' => $tags,
|
||||
]);
|
||||
}
|
||||
|
||||
private function sendBatch(BatchAdapterInterface $batch): void
|
||||
{
|
||||
$batch->write($this->protocol);
|
||||
$this->protocol->getTransport()->flush();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,9 @@ use Jaeger\Thrift\Log;
|
|||
use Jaeger\Thrift\Span as JTSpan;
|
||||
use Jaeger\Thrift\SpanRef;
|
||||
use Jaeger\Thrift\SpanRefType;
|
||||
use Jaeger\Thrift\Tag;
|
||||
use Jaeger\Thrift\TagType;
|
||||
use OpenTelemetry\API\Trace\SpanKind;
|
||||
use OpenTelemetry\API\Trace\StatusCode;
|
||||
use OpenTelemetry\Contrib\Jaeger\TagFactory\TagFactory;
|
||||
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
|
||||
use OpenTelemetry\SDK\Trace\EventInterface;
|
||||
use OpenTelemetry\SDK\Trace\LinkInterface;
|
||||
|
|
@ -197,89 +196,12 @@ class SpanConverter implements SpanConverterInterface
|
|||
{
|
||||
$tags = [];
|
||||
foreach ($tagPairs as $key => $value) {
|
||||
$tags[] = self::buildTag($key, $value);
|
||||
$tags[] = TagFactory::create($key, $value);
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
private static function buildTag(string $key, $value): Tag
|
||||
{
|
||||
return self::createJaegerTagInstance(
|
||||
$key,
|
||||
self::convertValueToTypeJaegerTagsSupport($value)
|
||||
);
|
||||
}
|
||||
|
||||
private static function convertValueToTypeJaegerTagsSupport($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return self::serializeArrayToString($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private static function createJaegerTagInstance(string $key, $value)
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::BOOL,
|
||||
'vBool' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
if (is_integer($value)) {
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::LONG,
|
||||
'vLong' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::DOUBLE,
|
||||
'vDouble' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::STRING,
|
||||
'vStr' => (string) $value,
|
||||
]);
|
||||
}
|
||||
|
||||
private static function serializeArrayToString(array $arrayToSerialize): string
|
||||
{
|
||||
return self::recursivelySerializeArray($arrayToSerialize);
|
||||
}
|
||||
|
||||
private static function recursivelySerializeArray($value): string
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return join(',', array_map(function ($val) {
|
||||
return self::recursivelySerializeArray($val);
|
||||
}, $value));
|
||||
}
|
||||
|
||||
// Casting false to string makes an empty string
|
||||
if (is_bool($value)) {
|
||||
return $value ? 'true' : 'false';
|
||||
}
|
||||
|
||||
// Floats will lose precision if their string representation
|
||||
// is >=14 or >=17 digits, depending on PHP settings.
|
||||
// Can also throw E_RECOVERABLE_ERROR if $value is an object
|
||||
// without a __toString() method.
|
||||
// This is possible because OpenTelemetry\Trace\Span does not verify
|
||||
// setAttribute() $value input.
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
private static function convertOtelEventsToJaegerLogs(SpanDataInterface $span): array
|
||||
{
|
||||
return array_map(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Contrib\Jaeger\TagFactory;
|
||||
|
||||
use Jaeger\Thrift\Tag;
|
||||
use Jaeger\Thrift\TagType;
|
||||
|
||||
class TagFactory
|
||||
{
|
||||
public static function create(string $key, $value): Tag
|
||||
{
|
||||
return self::createJaegerTagInstance(
|
||||
$key,
|
||||
self::convertValueToTypeJaegerTagsSupport($value)
|
||||
);
|
||||
}
|
||||
|
||||
private static function convertValueToTypeJaegerTagsSupport($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return self::serializeArrayToString($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private static function createJaegerTagInstance(string $key, $value)
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::BOOL,
|
||||
'vBool' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
if (is_integer($value)) {
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::LONG,
|
||||
'vLong' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::DOUBLE,
|
||||
'vDouble' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
return new Tag([
|
||||
'key' => $key,
|
||||
'vType' => TagType::STRING,
|
||||
'vStr' => (string) $value,
|
||||
]);
|
||||
}
|
||||
|
||||
private static function serializeArrayToString(array $arrayToSerialize): string
|
||||
{
|
||||
return self::recursivelySerializeArray($arrayToSerialize);
|
||||
}
|
||||
|
||||
private static function recursivelySerializeArray($value): string
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return join(',', array_map(function ($val) {
|
||||
return self::recursivelySerializeArray($val);
|
||||
}, $value));
|
||||
}
|
||||
|
||||
// Casting false to string makes an empty string
|
||||
if (is_bool($value)) {
|
||||
return $value ? 'true' : 'false';
|
||||
}
|
||||
|
||||
// Floats will lose precision if their string representation
|
||||
// is >=14 or >=17 digits, depending on PHP settings.
|
||||
// Can also throw E_RECOVERABLE_ERROR if $value is an object
|
||||
// without a __toString() method.
|
||||
// This is possible because OpenTelemetry\Trace\Span does not verify
|
||||
// setAttribute() $value input.
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,18 @@ class ResourceInfo
|
|||
return $this->schemaUrl;
|
||||
}
|
||||
|
||||
public function serialize(): string
|
||||
{
|
||||
$copyOfAttributesAsArray = array_slice($this->attributes->toArray(), 0); //This may be overly cautious (in trying to avoid mutating the source array)
|
||||
ksort($copyOfAttributesAsArray); //sort the associative array by keys since the serializer will consider equal arrays different otherwise
|
||||
|
||||
//The exact return value doesn't matter, as long as it can distingusih between instances that represent the same/different resources
|
||||
return serialize([
|
||||
'schemaUrl' => $this->schemaUrl,
|
||||
'attributes' => $copyOfAttributesAsArray,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Backward compatibility methods
|
||||
*
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ use PHPUnit\Framework\TestCase;
|
|||
* @covers OpenTelemetry\Contrib\Jaeger\HttpSender
|
||||
* @covers OpenTelemetry\Contrib\Jaeger\ThriftHttpTransport
|
||||
* @covers OpenTelemetry\Contrib\Jaeger\ParsedEndpointUrl
|
||||
* @covers OpenTelemetry\Contrib\Jaeger\BatchAdapter\BatchAdapter
|
||||
* @covers OpenTelemetry\Contrib\Jaeger\BatchAdapter\BatchAdapterFactory
|
||||
*
|
||||
*/
|
||||
class JaegerHttpCollectorExporterTest extends TestCase
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Tests\Unit\Contrib;
|
||||
|
||||
use OpenTelemetry\Contrib\Jaeger\BatchAdapter\BatchAdapterFactoryInterface;
|
||||
use OpenTelemetry\Contrib\Jaeger\BatchAdapter\BatchAdapterInterface;
|
||||
use OpenTelemetry\Contrib\Jaeger\HttpSender;
|
||||
use OpenTelemetry\Contrib\Jaeger\ParsedEndpointUrl;
|
||||
use OpenTelemetry\SDK\Common\Attribute\Attributes;
|
||||
use OpenTelemetry\SDK\Resource\ResourceInfo;
|
||||
use OpenTelemetry\Tests\Unit\SDK\Util\SpanData;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Thrift\Protocol\TProtocol;
|
||||
|
||||
/**
|
||||
* @covers OpenTelemetry\Contrib\Jaeger\HttpSender
|
||||
*/
|
||||
class JaegerHttpSenderTest extends TestCase
|
||||
{
|
||||
use UsesHttpClientTrait;
|
||||
|
||||
private function createSenderAndMocks(array $inputs): array
|
||||
{
|
||||
[
|
||||
'serviceName' => $serviceName
|
||||
] = $inputs;
|
||||
|
||||
$mockBatchAdapterFactory = $this->createBatchAdapterFactoryMock();
|
||||
|
||||
/**
|
||||
* @psalm-suppress PossiblyInvalidArgument
|
||||
*/
|
||||
$sender = new HttpSender(
|
||||
$this->getClientInterfaceMock(),
|
||||
$this->getRequestFactoryInterfaceMock(),
|
||||
$this->getStreamFactoryInterfaceMock(),
|
||||
$serviceName,
|
||||
$this->createParsedEndpointUrlMock(),
|
||||
$mockBatchAdapterFactory
|
||||
);
|
||||
|
||||
return [
|
||||
'sender' => $sender,
|
||||
'mockBatchAdapterFactory' => $mockBatchAdapterFactory,
|
||||
];
|
||||
}
|
||||
|
||||
private function createParsedEndpointUrlMock(): ParsedEndpointUrl
|
||||
{
|
||||
/** @var ParsedEndpointUrl */
|
||||
$mock = $this->createMock(ParsedEndpointUrl::class);
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
private function createBatchAdapterFactoryMock(): BatchAdapterFactoryInterface
|
||||
{
|
||||
return new class() implements BatchAdapterFactoryInterface {
|
||||
//Just enough spy functionality for what was needed for now. Generalize and extend as needed
|
||||
private array $interceptedValues = [];
|
||||
|
||||
public function getInterceptedValues()
|
||||
{
|
||||
return $this->interceptedValues;
|
||||
}
|
||||
|
||||
public function create(array $values): BatchAdapterInterface
|
||||
{
|
||||
$this->interceptedValues[] = $values;
|
||||
|
||||
$mockBatchAdapter = new class() implements BatchAdapterInterface {
|
||||
public function write(TProtocol $output): void
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
return $mockBatchAdapter;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public function test_span_and_process_data_are_batched_by_resource(): void
|
||||
{
|
||||
[
|
||||
'sender' => $sender,
|
||||
'mockBatchAdapterFactory' => $mockBatchAdapterFactory
|
||||
] = $this->createSenderAndMocks([
|
||||
'serviceName' => 'nameOfThe1stLogicalApp',
|
||||
]);
|
||||
|
||||
$spans = [
|
||||
(new SpanData())->setResource(ResourceInfo::create(
|
||||
new Attributes(), //code should default service.name from how its set above
|
||||
)),
|
||||
(new SpanData())->setResource(ResourceInfo::create(
|
||||
new Attributes([
|
||||
'service.name' => 'nameOfThe2ndLogicalApp',
|
||||
]),
|
||||
)),
|
||||
];
|
||||
|
||||
$sender->send($spans);
|
||||
|
||||
$interceptedValues = $mockBatchAdapterFactory->getInterceptedValues();
|
||||
$this->assertSame(2, count($interceptedValues));
|
||||
|
||||
//1st batch
|
||||
$this->assertSame(1, count($interceptedValues[0]['spans'])); //Detailed tests for the span conversion live elsewhere
|
||||
|
||||
//2nd batch
|
||||
$this->assertSame(1, count($interceptedValues[1]['spans'])); //Detailed tests for the span conversion live elsewhere
|
||||
}
|
||||
|
||||
public function test_process_service_names_are_correctly_set_from_resource_attributes_or_the_default_service_name(): void
|
||||
{
|
||||
[
|
||||
'sender' => $sender,
|
||||
'mockBatchAdapterFactory' => $mockBatchAdapterFactory
|
||||
] = $this->createSenderAndMocks([
|
||||
'serviceName' => 'nameOfThe1stLogicalApp',
|
||||
]);
|
||||
|
||||
$spans = [
|
||||
(new SpanData())->setResource(ResourceInfo::create(
|
||||
new Attributes(), //code should default service.name from how its set above
|
||||
)),
|
||||
(new SpanData())->setResource(ResourceInfo::create(
|
||||
new Attributes([
|
||||
'service.name' => 'nameOfThe2ndLogicalApp',
|
||||
]),
|
||||
)),
|
||||
];
|
||||
|
||||
$sender->send($spans);
|
||||
|
||||
$interceptedValues = $mockBatchAdapterFactory->getInterceptedValues();
|
||||
|
||||
//1st batch
|
||||
$this->assertSame('nameOfThe1stLogicalApp', $interceptedValues[0]['process']->serviceName);
|
||||
|
||||
//2nd batch
|
||||
$this->assertSame('nameOfThe2ndLogicalApp', $interceptedValues[1]['process']->serviceName);
|
||||
}
|
||||
|
||||
public function test_tags_are_correctly_set_from_resource_attributes(): void
|
||||
{
|
||||
[
|
||||
'sender' => $sender,
|
||||
'mockBatchAdapterFactory' => $mockBatchAdapterFactory
|
||||
] = $this->createSenderAndMocks([
|
||||
'serviceName' => 'someServiceName',
|
||||
]);
|
||||
|
||||
$spans = [
|
||||
(new SpanData())->setResource(ResourceInfo::create(
|
||||
new Attributes(),
|
||||
)),
|
||||
(new SpanData())->setResource(ResourceInfo::create(
|
||||
new Attributes([
|
||||
'telemetry.sdk.name' => 'opentelemetry',
|
||||
]),
|
||||
)),
|
||||
];
|
||||
|
||||
$sender->send($spans);
|
||||
|
||||
$interceptedValues = $mockBatchAdapterFactory->getInterceptedValues();
|
||||
|
||||
//1st batch
|
||||
$this->assertSame(0, count($interceptedValues[0]['process']->tags));
|
||||
|
||||
//2nd batch
|
||||
$this->assertSame(1, count($interceptedValues[1]['process']->tags));
|
||||
|
||||
$this->assertSame('telemetry.sdk.name', $interceptedValues[1]['process']->tags[0]->key);
|
||||
$this->assertSame('opentelemetry', $interceptedValues[1]['process']->tags[0]->vStr);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ use PHPUnit\Framework\TestCase;
|
|||
|
||||
/**
|
||||
* @covers OpenTelemetry\Contrib\Jaeger\SpanConverter
|
||||
* @covers OpenTelemetry\Contrib\Jaeger\TagFactory\TagFactory
|
||||
*/
|
||||
class JaegerSpanConverterTest extends TestCase
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,4 +25,12 @@ class ComposerTest extends TestCase
|
|||
$this->assertSame($name, $resource->getAttributes()->get(ResourceAttributes::SERVICE_NAME));
|
||||
$this->assertSame($version, $resource->getAttributes()->get(ResourceAttributes::SERVICE_VERSION));
|
||||
}
|
||||
|
||||
public function test_composer_detector(): void
|
||||
{
|
||||
$resource = (new Detectors\Composer())->getResource();
|
||||
|
||||
$this->assertNotNull($resource->getAttributes()->get(ResourceAttributes::SERVICE_NAME));
|
||||
$this->assertNotNull($resource->getAttributes()->get(ResourceAttributes::SERVICE_VERSION));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use PHPUnit\Framework\TestCase;
|
|||
/**
|
||||
* @covers OpenTelemetry\SDK\Resource\ResourceInfo
|
||||
*/
|
||||
class ResourceTest extends TestCase
|
||||
class ResourceInfoTest extends TestCase
|
||||
{
|
||||
use EnvironmentVariables;
|
||||
|
||||
|
|
@ -322,11 +322,55 @@ class ResourceTest extends TestCase
|
|||
$this->assertEquals('foo', $resource->getAttributes()->get('service.name'));
|
||||
}
|
||||
|
||||
public function test_composer_detector(): void
|
||||
/**
|
||||
* @dataProvider sameResourcesProvider
|
||||
*/
|
||||
public function test_serialize_returns_same_output_for_objects_representing_the_same_resource(ResourceInfo $resource1, ResourceInfo $resource2): void
|
||||
{
|
||||
$resource = (new Detectors\Composer())->getResource();
|
||||
$this->assertSame($resource1->serialize(), $resource2->serialize());
|
||||
}
|
||||
|
||||
$this->assertNotNull($resource->getAttributes()->get(ResourceAttributes::SERVICE_NAME));
|
||||
$this->assertNotNull($resource->getAttributes()->get(ResourceAttributes::SERVICE_VERSION));
|
||||
public function sameResourcesProvider(): iterable
|
||||
{
|
||||
yield 'Attribute keys sorted in ascending order vs Attribute keys sorted in descending order' => [
|
||||
ResourceInfo::create(new Attributes([
|
||||
'a' => 'someValue',
|
||||
'b' => 'someValue',
|
||||
'c' => 'someValue',
|
||||
])),
|
||||
ResourceInfo::create(new Attributes([
|
||||
'c' => 'someValue',
|
||||
'b' => 'someValue',
|
||||
'a' => 'someValue',
|
||||
])),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider differentResourcesProvider
|
||||
*/
|
||||
public function test_serialize_returns_different_output_for_objects_representing_different_resources(ResourceInfo $resource1, ResourceInfo $resource2): void
|
||||
{
|
||||
$this->assertNotSame($resource1->serialize(), $resource2->serialize());
|
||||
}
|
||||
|
||||
public function differentResourcesProvider(): iterable
|
||||
{
|
||||
yield 'Null schema url vs Some schema url' => [
|
||||
ResourceInfo::create(new Attributes(), null),
|
||||
ResourceInfo::create(new Attributes(), 'someSchemaUrl'),
|
||||
];
|
||||
}
|
||||
|
||||
public function test_serialize_incorporates_all_properties(): void
|
||||
{
|
||||
$resource = ResourceInfoFactory::emptyResource();
|
||||
$properties = (new \ReflectionClass($resource))->getProperties();
|
||||
|
||||
$serializedResource = $resource->serialize();
|
||||
|
||||
foreach ($properties as $property) {
|
||||
$this->assertStringContainsString($property->getName(), $serializedResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue