remove proprietary new relic exporters (#998)

New Relic now fully supports OTLP ingestion, and having proprietary exporters is no longer their strategy. The proprietary exporters have been marked as abandoned in packagist, and suggest exporter-otlp as a replacement.
This commit is contained in:
Brett McBride 2023-05-09 20:20:50 +10:00 committed by GitHub
parent 593fa344bc
commit 5d35c998e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2 additions and 947 deletions

View File

@ -16,16 +16,12 @@ splits:
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/api.git"
- prefix: "src/SDK"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/sdk.git"
- prefix: "src/Contrib/Newrelic"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/exporter-newrelic.git"
- prefix: "src/Contrib/Otlp"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/exporter-otlp.git"
- prefix: "src/Contrib/Grpc"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/transport-grpc.git"
- prefix: "src/Contrib/Zipkin"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/exporter-zipkin.git"
- prefix: "src/Contrib/ZipkinToNewrelic"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/exporter-zipkintonewrelic.git"
- prefix: "src/Extension/Propagator/B3"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/extension-propagator-b3.git"

View File

@ -66,10 +66,6 @@ smoke-test-exporter-examples: FORCE ## Run (some) exporter smoke test examples
$(DOCKER_COMPOSE) up -d --remove-orphans
$(DC_RUN_PHP) php ./examples/traces/exporters/zipkin.php
$(DC_RUN_PHP) php ./examples/traces/features/parent_span_example.php
# The following examples do not use the DC_RUN_PHP global because they need environment variables.
$(DOCKER_COMPOSE) run -e NEW_RELIC_ENDPOINT -e NEW_RELIC_INSERT_KEY --rm php php ./examples/traces/exporters/newrelic.php
$(DOCKER_COMPOSE) run -e NEW_RELIC_ENDPOINT -e NEW_RELIC_INSERT_KEY --rm php php ./examples/traces/exporters/zipkin_to_newrelic.php
$(DOCKER_COMPOSE) stop
smoke-test-collector-integration: ## Run smoke test collector integration
$(DOCKER_COMPOSE) -f docker-compose.collector.yaml up -d --remove-orphans
sleep 5

View File

@ -52,7 +52,6 @@
"src/API/Trace/functions.php",
"src/Contrib/Otlp/_register.php",
"src/Contrib/Grpc/_register.php",
"src/Contrib/Newrelic/_register.php",
"src/Contrib/Zipkin/_register.php",
"src/Extension/Propagator/B3/_register.php",
"src/SDK/Logs/Exporter/_register.php",

View File

@ -1,65 +0,0 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../../vendor/autoload.php';
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
/*
* Experimental example to send trace data to New Relic.
* It will send PHP Otel trace data end to end across the internet to a functional backend.
* Needs a license key to connect. For a free account/key, go to: https://newrelic.com/signup/
*/
$licenseKey = getenv('NEW_RELIC_INSERT_KEY');
// Needs a license key in the environment to connect to the backend server.
if ($licenseKey == false) {
echo PHP_EOL . 'NEW_RELIC_INSERT_KEY not found in environment. Newrelic Example tracing is not enabled.' . PHP_EOL;
return;
}
/*
* Default Trace API endpoint: https://trace-api.newrelic.com/trace/v1
* EU data centers: https://trace-api.eu.newrelic.com/trace/v1
*/
putenv('NEW_RELIC_ENDPOINT', 'https://trace-api.newrelic.com/trace/v1');
$newrelicExporter = (new \OpenTelemetry\Contrib\Newrelic\SpanExporterFactory())->create();
echo 'Starting Newrelic example';
$tracerProvider = new TracerProvider(new SimpleSpanProcessor($newrelicExporter));
$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php');
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->spanBuilder('session.generate.span.' . microtime(true))->startSpan();
echo sprintf(
PHP_EOL . 'Exporting Trace: %s, Span: %s',
$span->getContext()->getTraceId(),
$span->getContext()->getSpanId()
);
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
], $timestamp);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
], $timestamp);
$span->end();
}
echo PHP_EOL . 'Newrelic example complete! See the results at https://one.newrelic.com/launcher/distributed-tracing.launcher?pane=eyJuZXJkbGV0SWQiOiJkaXN0cmlidXRlZC10cmFjaW5nLmhvbWUiLCJzb3J0SW5kZXgiOjAsInNvcnREaXJlY3Rpb24iOiJERVNDIiwicXVlcnkiOnsib3BlcmF0b3IiOiJBTkQiLCJpbmRleFF1ZXJ5Ijp7ImNvbmRpdGlvblR5cGUiOiJJTkRFWCIsIm9wZXJhdG9yIjoiQU5EIiwiY29uZGl0aW9uU2V0cyI6W119LCJzcGFuUXVlcnkiOnsib3BlcmF0b3IiOiJBTkQiLCJjb25kaXRpb25TZXRzIjpbeyJjb25kaXRpb25UeXBlIjoiU1BBTiIsIm9wZXJhdG9yIjoiQU5EIiwiY29uZGl0aW9ucyI6W3siYXR0ciI6InNlcnZpY2UubmFtZSIsIm9wZXJhdG9yIjoiRVEiLCJ2YWx1ZSI6ImFsd2F5c09uTmV3cmVsaWNFeGFtcGxlIn1dfV19fX0=&platform[timeRange][duration]=1800000&platform[$isFallbackTimeRange]=true';
echo PHP_EOL;
$tracerProvider->shutdown();

View File

@ -1,72 +0,0 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../../vendor/autoload.php';
use OpenTelemetry\Contrib\ZipkinToNewrelic\Exporter as ZipkinToNewrelicExporter;
use OpenTelemetry\SDK\Common\Configuration\Configuration;
use OpenTelemetry\SDK\Common\Export\Http\PsrTransportFactory;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
/*
* Experimental example to send trace data to New Relic.
* It will send PHP Otel trace data end to end across the internet to a functional backend.
* Needs a license key to connect. For a free account/key, go to: https://newrelic.com/signup/
*/
$licenseKey = getenv('NEW_RELIC_INSERT_KEY');
// Needs a license key in the environment to connect to the backend server.
if ($licenseKey == false) {
echo PHP_EOL . 'NEW_RELIC_INSERT_KEY not found in environment. Newrelic Example tracing is not enabled.';
return;
}
/*
* Default Trace API endpoint: https://trace-api.newrelic.com/trace/v1
* EU data centers: https://trace-api.eu.newrelic.com/trace/v1
*/
$endpointUrl = Configuration::getString('NEW_RELIC_ENDPOINT', 'https://trace-api.newrelic.com/trace/v1');
$transport = PsrTransportFactory::discover()->create($endpointUrl, $licenseKey);
$zipkinToNewrelicExporter = new ZipkinToNewrelicExporter(
'AlwaysOnZipkinToNewrelicExample',
$transport
);
echo 'Starting ZipkinToNewRelic example';
$tracerProvider = new TracerProvider(new SimpleSpanProcessor($zipkinToNewrelicExporter));
$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php');
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->spanBuilder('session.generate.span.' . microtime(true))->startSpan();
echo sprintf(
PHP_EOL . 'Exporting Trace: %s, Span: %s',
$span->getContext()->getTraceId(),
$span->getContext()->getSpanId()
);
$span->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$span->addEvent('found_login' . $i, [
'id' => $i,
'username' => 'otuser' . $i,
], $timestamp);
$span->addEvent('generated_session', [
'id' => md5((string) microtime(true)),
], $timestamp);
$span->end();
}
echo PHP_EOL . 'ZipkinToNewrelic example complete! See the results at https://one.newrelic.com/launcher/distributed-tracing.launcher?pane=eyJuZXJkbGV0SWQiOiJkaXN0cmlidXRlZC10cmFjaW5nLmhvbWUiLCJzb3J0SW5kZXgiOjAsInNvcnREaXJlY3Rpb24iOiJERVNDIiwicXVlcnkiOnsib3BlcmF0b3IiOiJBTkQiLCJpbmRleFF1ZXJ5Ijp7ImNvbmRpdGlvblR5cGUiOiJJTkRFWCIsIm9wZXJhdG9yIjoiQU5EIiwiY29uZGl0aW9uU2V0cyI6W119LCJzcGFuUXVlcnkiOnsib3BlcmF0b3IiOiJBTkQiLCJjb25kaXRpb25TZXRzIjpbeyJjb25kaXRpb25UeXBlIjoiU1BBTiIsIm9wZXJhdG9yIjoiQU5EIiwiY29uZGl0aW9ucyI6W3siYXR0ciI6InNlcnZpY2UubmFtZSIsIm9wZXJhdG9yIjoiRVEiLCJ2YWx1ZSI6ImFsd2F5c09uWmlwa2luVG9OZXdyZWxpY0V4YW1wbGUifV19XX19fQ==&platform[timeRange][duration]=1800000&platform[$isFallbackTimeRange]=true';
echo PHP_EOL;
$tracerProvider->shutdown();

View File

@ -1,82 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Contrib\Newrelic;
use JsonException;
use OpenTelemetry\API\Behavior\LogsMessagesTrait;
use OpenTelemetry\SDK\Common\Export\TransportInterface;
use OpenTelemetry\SDK\Common\Future\CancellationInterface;
use OpenTelemetry\SDK\Common\Future\FutureInterface;
use OpenTelemetry\SDK\Trace\Behavior\UsesSpanConverterTrait;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use Throwable;
/**
* Class NewrelicExporter - implements the export interface for data transfer via Newrelic protocol
* @package OpenTelemetry\Exporter
*
* This is an experimental, non-supported exporter.
* It will send PHP Otel trace data end to end across the internet to a functional backend.
* Needs a license key to connect. For a free account/key, go to: https://newrelic.com/signup/
*/
class Exporter implements SpanExporterInterface
{
use LogsMessagesTrait;
use UsesSpanConverterTrait;
public const DATA_FORMAT_VERSION_DEFAULT = '1';
private TransportInterface $transport;
private string $endpointUrl;
public function __construct(
TransportInterface $transport,
string $endpointUrl,
SpanConverter $spanConverter = null
) {
$this->endpointUrl = $endpointUrl;
$this->transport = $transport;
$this->setSpanConverter($spanConverter ?? new SpanConverter());
}
/**
* @throws JsonException
*/
protected function serializeTrace(iterable $spans): string
{
return json_encode($this->convert($spans), JSON_THROW_ON_ERROR);
}
private function convert(iterable $spans): array
{
$commonAttributes = ['attributes' => [
'host' => $this->endpointUrl, ]];
return [[ 'common' => $commonAttributes,
'spans' => $this->getSpanConverter()->convert($spans), ]];
}
public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface
{
return $this->transport
->send($this->serializeTrace($batch), $cancellation)
->map(static fn (): bool => true)
->catch(static function (Throwable $throwable): bool {
self::logError('Export failure', ['exception' => $throwable]);
return false;
});
}
public function shutdown(?CancellationInterface $cancellation = null): bool
{
return $this->transport->shutdown($cancellation);
}
public function forceFlush(?CancellationInterface $cancellation = null): bool
{
return $this->transport->forceFlush($cancellation);
}
}

View File

@ -1,7 +0,0 @@
# OpenTelemetry New Relic Exporter
A New Relic exporter for OpenTelemetry.
## Usage
See https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/traces/exporters/newrelic.php

View File

@ -1,96 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Contrib\Newrelic;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\Trace\SpanConverterInterface;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
use OpenTelemetry\SemConv\ResourceAttributes;
/**
* @see https://docs.newrelic.com/docs/distributed-tracing/trace-api/report-new-relic-format-traces-trace-api/#new-relic-guidelines
*/
class SpanConverter implements SpanConverterInterface
{
const STATUS_CODE_TAG_KEY = 'otel.status_code';
const STATUS_DESCRIPTION_TAG_KEY = 'otel.status_description';
const KEY_DROPPED_ATTRIBUTES_COUNT = 'otel.dropped_attributes_count';
private string $defaultServiceName;
public function __construct()
{
$this->defaultServiceName = ResourceInfoFactory::defaultResource()->getAttributes()->get(ResourceAttributes::SERVICE_NAME);
}
public function convert(iterable $spans): array
{
$aggregate = [];
foreach ($spans as $span) {
$aggregate[] = $this->convertSpan($span);
}
return $aggregate;
}
private function convertSpan(SpanDataInterface $span): array
{
$spanParent = $span->getParentContext();
$startTimestamp = TimeUtil::nanosToMillis($span->getStartEpochNanos());
$endTimestamp = TimeUtil::nanosToMillis($span->getEndEpochNanos());
$serviceName = $span->getResource()->getAttributes()->get(ResourceAttributes::SERVICE_NAME)
??
$this->defaultServiceName;
$row = [
'id' => $span->getSpanId(),
'trace.id' => $span->getTraceId(),
'attributes' => [
'name' => $span->getName(),
'service.name' => $serviceName,
'parent.id' => $spanParent->isValid() ? $spanParent->getSpanId() : null,
'timestamp' => $startTimestamp,
'duration.ms' => (float) $endTimestamp - $startTimestamp,
self::STATUS_CODE_TAG_KEY => $span->getStatus()->getCode(),
self::STATUS_DESCRIPTION_TAG_KEY => $span->getStatus()->getDescription(),
],
];
foreach ($span->getAttributes() as $k => $v) {
$row['attributes'][$k] = $v;
}
foreach ($span->getResource()->getAttributes() as $k => $v) {
$row['attributes'][$k] = $v;
}
foreach ($span->getInstrumentationScope()->getAttributes() as $k => $v) {
$row['attributes'][$k] = $v;
}
$droppedAttributes = $span->getAttributes()->getDroppedAttributesCount()
+ $span->getInstrumentationScope()->getAttributes()->getDroppedAttributesCount()
+ $span->getResource()->getAttributes()->getDroppedAttributesCount();
if ($droppedAttributes > 0) {
$row['attributes'][self::KEY_DROPPED_ATTRIBUTES_COUNT] = $droppedAttributes;
}
/*
foreach ($span->getEvents() as $event) {
if (!array_key_exists('annotations', $row)) {
$row['annotations'] = [];
}
$row['annotations'][] = [
'timestamp' => (int) ($event->getTimestamp() / 1e6), // RealtimeClock in milliseconds
'value' => $event->getName(),
];
}
*/
return $row;
}
}

View File

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Contrib\Newrelic;
use OpenTelemetry\SDK\Common\Configuration\Configuration;
use OpenTelemetry\SDK\Common\Export\Http\PsrTransportFactory;
use OpenTelemetry\SDK\Trace\SpanExporter\SpanExporterFactoryInterface;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
class SpanExporterFactory implements SpanExporterFactoryInterface
{
public function create(): SpanExporterInterface
{
$licenseKey = Configuration::getString('NEW_RELIC_INSERT_KEY');
$endpointUrl = Configuration::getString('NEW_RELIC_ENDPOINT', 'https://trace-api.newrelic.com/trace/v1');
$dataFormatVersion = Exporter::DATA_FORMAT_VERSION_DEFAULT;
$transport = PsrTransportFactory::discover()->create($endpointUrl, 'application/json', [
'Api-Key' => $licenseKey,
'Data-Format' => 'newrelic',
'Data-Format-Version' => $dataFormatVersion,
]);
return new Exporter($transport, $endpointUrl);
}
}

View File

@ -1,5 +0,0 @@
<?php
declare(strict_types=1);
\OpenTelemetry\SDK\Registry::registerSpanExporterFactory('newrelic', \OpenTelemetry\Contrib\Newrelic\SpanExporterFactory::class);

View File

@ -1,33 +0,0 @@
{
"name": "open-telemetry/exporter-newrelic",
"description": "New Relic exporter for OpenTelemetry PHP.",
"keywords": ["opentelemetry", "otel", "tracing", "exporter", "newrelic"],
"type": "library",
"license": "Apache-2.0",
"authors": [
{
"name": "opentelemetry-php contributors",
"homepage": "https://github.com/open-telemetry/opentelemetry-php/graphs/contributors"
}
],
"require": {
"php": "^7.4 || ^8.0",
"open-telemetry/sdk": "^1.0",
"php-http/async-client-implementation": "^1.0",
"php-http/discovery": "^1.14",
"psr/http-factory-implementation": "^1.0"
},
"autoload": {
"psr-4": {
"OpenTelemetry\\Contrib\\Newrelic\\": "."
},
"files": [
"_register.php"
]
},
"extra": {
"branch-alias": {
"dev-main": "1.0.x-dev"
}
}
}

View File

@ -1,85 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Contrib\ZipkinToNewrelic;
use JsonException;
use OpenTelemetry\API\Behavior\LogsMessagesTrait;
use OpenTelemetry\SDK\Common\Export\Http\PsrTransportFactory;
use OpenTelemetry\SDK\Common\Export\TransportInterface;
use OpenTelemetry\SDK\Common\Future\CancellationInterface;
use OpenTelemetry\SDK\Common\Future\FutureInterface;
use OpenTelemetry\SDK\Trace\Behavior\UsesSpanConverterTrait;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use Throwable;
/**
* Class ZipkinExporter - implements the export interface for data transfer via Zipkin protocol
* @package OpenTelemetry\Exporter
*
* This is an experimental, non-supported exporter.
* It will send PHP Otel trace data end to end across the internet to a functional backend.
* Needs a license key to connect. For a free account/key, go to: https://newrelic.com/signup/
*/
class Exporter implements SpanExporterInterface
{
use LogsMessagesTrait;
use UsesSpanConverterTrait;
private TransportInterface $transport;
public function __construct(
TransportInterface $transport,
SpanConverter $spanConverter = null
) {
$this->transport = $transport;
$this->setSpanConverter($spanConverter ?? new SpanConverter());
}
public static function create(
string $endpointUrl,
string $licenseKey
): self {
$transport = PsrTransportFactory::discover()->create($endpointUrl, 'application/json', [
'Api-Key' => $licenseKey,
'Data-Format' => 'zipkin',
'Data-Format-Version' => '2',
]);
return new self($transport);
}
/**
* @throws JsonException
*/
protected function serializeTrace(iterable $spans): string
{
return json_encode(
$this->getSpanConverter()->convert($spans),
JSON_THROW_ON_ERROR
);
}
public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface
{
return $this->transport
->send($this->serializeTrace($batch), $cancellation)
->map(static fn (): bool => true)
->catch(static function (Throwable $throwable): bool {
self::logError('Export failure', ['exception' => $throwable]);
return false;
});
}
public function shutdown(?CancellationInterface $cancellation = null): bool
{
return $this->transport->shutdown($cancellation);
}
public function forceFlush(?CancellationInterface $cancellation = null): bool
{
return $this->transport->forceFlush($cancellation);
}
}

View File

@ -1,7 +0,0 @@
# OpenTelemetry Zipkin to New Relic Exporter
_Experimental_ New Relic exporter for OpenTelemetry, which uses the Zipkin protocol.
## Usage
See https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/traces/exporters/zipkin_to_newrelic.php

View File

@ -1,108 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Contrib\ZipkinToNewrelic;
use function max;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\Trace\SpanConverterInterface;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
use OpenTelemetry\SemConv\ResourceAttributes;
class SpanConverter implements SpanConverterInterface
{
const STATUS_CODE_TAG_KEY = 'otel.status_code';
const STATUS_DESCRIPTION_TAG_KEY = 'otel.status_description';
private string $defaultServiceName;
public function __construct()
{
$this->defaultServiceName = ResourceInfoFactory::defaultResource()->getAttributes()->get(ResourceAttributes::SERVICE_NAME);
}
private function sanitiseTagValue($value)
{
// Casting false to string makes an empty string
if (is_bool($value)) {
return $value ? 'true' : 'false';
}
// Zipkin tags must be strings, but opentelemetry
// accepts strings, booleans, numbers, and lists of each.
if (is_array($value)) {
return implode(',', array_map(fn ($value) => $this->sanitiseTagValue($value), $value));
}
// 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\API\Trace\Span does not verify
// setAttribute() $value input.
return (string) $value;
}
public function convert(iterable $spans): array
{
$aggregate = [];
foreach ($spans as $span) {
$aggregate[] = $this->convertSpan($span);
}
return $aggregate;
}
private function convertSpan(SpanDataInterface $span): array
{
$spanParent = $span->getParentContext();
$startTimestamp = TimeUtil::nanosToMicros($span->getStartEpochNanos());
$endTimestamp = TimeUtil::nanosToMicros($span->getEndEpochNanos());
$serviceName = $span->getResource()->getAttributes()->get(ResourceAttributes::SERVICE_NAME)
??
$this->defaultServiceName;
$row = [
'id' => $span->getSpanId(),
'traceId' => $span->getTraceId(),
'parentId' => $spanParent->isValid() ? $spanParent->getSpanId() : null,
'localEndpoint' => [
'serviceName' => $serviceName,
],
'name' => $span->getName(),
'timestamp' => $startTimestamp,
'duration' => max(1, $endTimestamp - $startTimestamp),
'tags' => [
self::STATUS_CODE_TAG_KEY => $span->getStatus()->getCode(),
self::STATUS_DESCRIPTION_TAG_KEY => $span->getStatus()->getDescription(),
],
];
foreach ($span->getAttributes() as $k => $v) {
$row['tags'][$k] = $this->sanitiseTagValue($v);
}
foreach ($span->getResource()->getAttributes() as $k => $v) {
$row['tags'][$k] = $this->sanitiseTagValue($v);
}
foreach ($span->getInstrumentationScope()->getAttributes() as $k => $v) {
$row['tags'][$k] = $this->sanitiseTagValue($v);
}
foreach ($span->getEvents() as $event) {
if (!array_key_exists('annotations', $row)) {
$row['annotations'] = [];
}
$row['annotations'][] = [
'timestamp' => TimeUtil::nanosToMicros($event->getEpochNanos()),
'value' => $event->getName(),
];
}
return $row;
}
}

View File

@ -1,30 +0,0 @@
{
"name": "open-telemetry/exporter-zipkintonewrelic",
"description": "Zipkin to New Relic exporter for OpenTelemetry PHP.",
"keywords": ["opentelemetry", "otel", "tracing", "zipkin", "newrelic", "exporter", "contrib"],
"type": "library",
"license": "Apache-2.0",
"authors": [
{
"name": "opentelemetry-php contributors",
"homepage": "https://github.com/open-telemetry/opentelemetry-php/graphs/contributors"
}
],
"require": {
"php": "^7.4 || ^8.0",
"open-telemetry/sdk": "^1.0",
"php-http/async-client-implementation": "^1.0",
"php-http/discovery": "^1.14",
"psr/http-factory-implementation": "^1.0"
},
"autoload": {
"psr-4": {
"OpenTelemetry\\Contrib\\ZipkinToNewrelic\\": "."
}
},
"extra": {
"branch-alias": {
"dev-main": "1.0.x-dev"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "open-telemetry/sdk-contrib",
"description": "Vendor specific implementations for OpenTelemetry PHP API/SDK.",
"keywords": ["opentelemetry", "otel", "metrics", "tracing", "logging", "apm", "otlp", "zipkin", "prometheus", "newrelic"],
"keywords": ["opentelemetry", "otel", "metrics", "tracing", "logging", "apm", "otlp", "zipkin"],
"type": "library",
"license": "Apache-2.0",
"authors": [
@ -33,7 +33,6 @@
},
"files": [
"Grpc/_register.php",
"Newrelic/_register.php",
"Otlp/_register.php",
"Zipkin/_register.php"

View File

@ -40,7 +40,6 @@ interface KnownValues
public const VALUE_HTTP_NDJSON = 'http/ndjson';
public const VALUE_OTLP = 'otlp';
public const VALUE_ZIPKIN = 'zipkin';
public const VALUE_NEWRELIC = 'newrelic';
public const VALUE_PROMETHEUS = 'prometheus';
public const VALUE_WITH_SAMPLED_TRACE = 'with_sampled_trace';
public const VALUE_BATCH = 'batch';
@ -142,7 +141,6 @@ interface KnownValues
public const OTEL_TRACES_EXPORTER = [
self::VALUE_OTLP,
self::VALUE_ZIPKIN,
self::VALUE_NEWRELIC,
self::VALUE_NONE,
];
public const OTEL_METRICS_EXPORTER = [

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\Contrib\Newrelic;
use OpenTelemetry\Contrib\Newrelic\Exporter;
use OpenTelemetry\SDK\Common\Export\TransportInterface;
use OpenTelemetry\Tests\Unit\SDK\Trace\SpanExporter\AbstractExporterTest;
/**
* @covers OpenTelemetry\Contrib\Newrelic\Exporter
*/
class NewrelicExporterTest extends AbstractExporterTest
{
protected const LICENSE_KEY = 'abc123';
public function createExporterWithTransport(TransportInterface $transport): Exporter
{
return new Exporter(
$transport,
'http://endpoint.url'
);
}
public function getExporterClass(): string
{
return Exporter::class;
}
}

View File

@ -1,134 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\Contrib\Newrelic;
use OpenTelemetry\Contrib\Newrelic\SpanConverter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
use OpenTelemetry\SemConv\ResourceAttributes;
use OpenTelemetry\Tests\Unit\SDK\Util\SpanData;
use PHPUnit\Framework\TestCase;
/**
* @covers OpenTelemetry\Contrib\Newrelic\SpanConverter
*/
class NewrelicSpanConverterTest extends TestCase
{
public function test_should_convert_a_span_to_a_payload_for_newrelic(): void
{
$span = (new SpanData())
->setName('guard.validate')
->addAttribute('service', 'guard')
->setResource(
ResourceInfo::create(
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'php',
'telemetry.sdk.version' => 'dev',
])
)
)
->addEvent('validators.list', Attributes::create(['job' => 'stage.updateTime']), 1505855799433901068)
->setHasEnded(true);
$converter = new SpanConverter();
$row = $converter->convert([$span])[0];
$this->assertSame($span->getContext()->getSpanId(), $row['id']);
$this->assertSame($span->getContext()->getTraceId(), $row['trace.id']);
$this->assertSame(
ResourceInfoFactory::defaultResource()->getAttributes()->get(ResourceAttributes::SERVICE_NAME),
$row['attributes']['service.name']
);
$this->assertSame($span->getName(), $row['attributes']['name']);
$this->assertNull($row['attributes']['parent.id']);
$this->assertSame(1505855794194, $row['attributes']['timestamp']);
$this->assertIsFloat($row['attributes']['duration.ms']);
$this->assertSame(5271.0, $row['attributes']['duration.ms']);
$attribute = $span->getAttributes()->get('service');
$this->assertEquals($attribute, $row['attributes']['service']);
$this->assertSame('opentelemetry', $row['attributes']['telemetry.sdk.name']);
$this->assertSame('php', $row['attributes']['telemetry.sdk.language']);
$this->assertSame('dev', $row['attributes']['telemetry.sdk.version']);
}
public function test_attributes_maintain_types(): void
{
$listOfStrings = ['string-1', 'string-2'];
$listOfNumbers = [1, 2, 3, 3.1415, 42];
$listOfBooleans = [true, true, false, true];
$listOfRandoms = [true, [1, 2, 3], false, 'string-1', 3.1415];
$span = (new SpanData())
->setName('attributes.test')
->addAttribute('string', 'string')
->addAttribute('integer-1', 1024)
->addAttribute('integer-2', 0)
->addAttribute('float', 1.2345)
->addAttribute('boolean-1', true)
->addAttribute('boolean-2', false)
->addAttribute('list-of-strings', $listOfStrings)
->addAttribute('list-of-numbers', $listOfNumbers)
->addAttribute('list-of-booleans', $listOfBooleans)
->addAttribute('list-of-random', $listOfRandoms);
$attributes = (new SpanConverter())->convert([$span])[0]['attributes'];
// Check that we can convert all attributes to tags
$this->assertCount(17, $attributes);
// Attributes destined for Newrelic must be key/value pairs
$this->assertSame('string', $attributes['string']);
$this->assertSame(1024, $attributes['integer-1']);
$this->assertSame(0, $attributes['integer-2']);
$this->assertSame(1.2345, $attributes['float']);
$this->assertTrue($attributes['boolean-1']);
$this->assertFalse($attributes['boolean-2']);
// Lists are accepted
$this->assertSame($listOfStrings, $attributes['list-of-strings']);
$this->assertSame($listOfNumbers, $attributes['list-of-numbers']);
$this->assertSame($listOfBooleans, $attributes['list-of-booleans']);
// This currently works, but OpenTelemetry\Trace\Span should stop arrays
// containing multiple value types from being passed to the Exporter.
$this->assertSame($listOfRandoms, $attributes['list-of-random']);
}
/**
* @dataProvider droppedProvider
*/
public function test_displays_non_zero_dropped_counts(int $dropped, bool $expected): void
{
$attributes = $this->createMock(AttributesInterface::class);
$attributes->method('getDroppedAttributesCount')->willReturn($dropped);
$spanData = $this->createMock(SpanDataInterface::class);
$spanData->method('getAttributes')->willReturn($attributes);
$converter = new SpanConverter();
$converted = $converter->convert([$spanData])[0];
if ($expected) {
$this->assertArrayHasKey(SpanConverter::KEY_DROPPED_ATTRIBUTES_COUNT, $converted['attributes']);
} else {
$this->assertArrayNotHasKey(SpanConverter::KEY_DROPPED_ATTRIBUTES_COUNT, $converted['attributes']);
}
}
public static function droppedProvider(): array
{
return [
'no dropped' => [0, false],
'some dropped' => [1, true],
];
}
}

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\Contrib\ZipkinToNewrelic;
use OpenTelemetry\Contrib\ZipkinToNewrelic\Exporter;
use OpenTelemetry\SDK\Common\Export\TransportInterface;
use OpenTelemetry\Tests\Unit\SDK\Trace\SpanExporter\AbstractExporterTest;
/**
* @covers OpenTelemetry\Contrib\ZipkinToNewrelic\Exporter
*/
class ZipkinToNewrelicExporterTest extends AbstractExporterTest
{
protected const LICENSE_KEY = 'abc123';
/**
* @psalm-suppress PossiblyInvalidArgument
*/
public function createExporterWithTransport(TransportInterface $transport): Exporter
{
return new Exporter(
$transport
);
}
public function getExporterClass(): string
{
return Exporter::class;
}
}

View File

@ -1,115 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\Contrib\ZipkinToNewrelic;
use function implode;
use OpenTelemetry\Contrib\ZipkinToNewrelic\SpanConverter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SemConv\ResourceAttributes;
use OpenTelemetry\Tests\Unit\SDK\Util\SpanData;
use PHPUnit\Framework\TestCase;
/**
* @covers OpenTelemetry\Contrib\ZipkinToNewrelic\SpanConverter
*/
class ZipkinToNewrelicSpanConverterTest extends TestCase
{
public function test_should_convert_a_span_to_a_payload_for_zipkin(): void
{
$span = (new SpanData())
->setName('guard.validate')
->addAttribute('service', 'guard')
->setResource(
ResourceInfo::create(
Attributes::create([
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'php',
'telemetry.sdk.version' => 'dev',
])
)
)
->addEvent('validators.list', Attributes::create(['job' => 'stage.updateTime']), 1505855799433901068)
->setHasEnded(true);
$converter = new SpanConverter();
$row = $converter->convert([$span])[0];
$this->assertSame($span->getContext()->getSpanId(), $row['id']);
$this->assertSame($span->getContext()->getTraceId(), $row['traceId']);
$this->assertSame(
ResourceInfoFactory::defaultResource()->getAttributes()->get(ResourceAttributes::SERVICE_NAME),
$row['localEndpoint']['serviceName']
);
$this->assertSame($span->getName(), $row['name']);
$this->assertSame(1505855794194009, $row['timestamp']);
$this->assertSame(5271717, $row['duration']);
$this->assertCount(6, $row['tags']);
$attribute = $span->getAttributes()->get('service');
$this->assertSame($attribute, $row['tags']['service']);
$this->assertSame('opentelemetry', $row['tags']['telemetry.sdk.name']);
$this->assertSame('php', $row['tags']['telemetry.sdk.language']);
$this->assertSame('dev', $row['tags']['telemetry.sdk.version']);
$this->assertCount(1, $row['annotations']);
[$annotation] = $row['annotations'];
$this->assertSame('validators.list', $annotation['value']);
$this->assertSame(1505855799433901, $annotation['timestamp']);
}
public function test_tags_are_coerced_correctly_to_strings(): void
{
$listOfStrings = ['string-1', 'string-2'];
$listOfNumbers = [1, 2, 3, 3.1415, 42];
$listOfBooleans = [true, true, false, true];
$listOfRandoms = [true, [1, 2, 3], false, 'string-1', 3.1415];
$span = (new SpanData())
->setName('tags.test')
->addAttribute('string', 'string')
->addAttribute('integer-1', 1024)
->addAttribute('integer-2', 0)
->addAttribute('float', '1.2345')
->addAttribute('boolean-1', true)
->addAttribute('boolean-2', false)
->addAttribute('list-of-strings', $listOfStrings)
->addAttribute('list-of-numbers', $listOfNumbers)
->addAttribute('list-of-booleans', $listOfBooleans)
->addAttribute('list-of-random', $listOfRandoms);
$tags = (new SpanConverter())->convert([$span])[0]['tags'];
// Check that we can convert all attributes to tags
$this->assertCount(12, $tags);
// Tags destined for Zipkin must be pairs of strings
foreach ($tags as $tagKey => $tagValue) {
$this->assertIsString($tagKey);
$this->assertIsString($tagValue);
}
$this->assertSame('string', $tags['string']);
$this->assertSame('1024', $tags['integer-1']);
$this->assertSame('0', $tags['integer-2']);
$this->assertSame('1.2345', $tags['float']);
$this->assertSame('true', $tags['boolean-1']);
$this->assertSame('false', $tags['boolean-2']);
// Lists must be casted to strings and joined with a separator
$this->assertSame(implode(',', $listOfStrings), $tags['list-of-strings']);
$this->assertSame(implode(',', $listOfNumbers), $tags['list-of-numbers']);
$this->assertSame('true,true,false,true', $tags['list-of-booleans']);
// This currently works, but OpenTelemetry\Trace\Span should stop arrays
// containing multiple value types from being passed to the Exporter.
$this->assertSame('true,1,2,3,false,string-1,3.1415', $tags['list-of-random']);
}
}

View File

@ -51,7 +51,6 @@ class FactoryRegistryTest extends TestCase
return [
['otlp'],
['zipkin'],
['newrelic'],
['console'],
['memory'],
];

View File

@ -107,14 +107,12 @@ class ExporterFactoryTest extends TestCase
public function invalidEnvProvider(): array
{
return [
'newrelic' => ['newrelic'],
'zipkintonewrelic' => ['zipkintonewrelic'],
'otlp+invalid protocol' => [
'otlp',
['OTEL_EXPORTER_OTLP_PROTOCOL' => 'foo'],
],
'unknown exporter' => ['foo'],
'multiple exporters' => ['newrelic,zipkin'],
'multiple exporters' => ['console,zipkin'],
];
}
}