TracerFactory implementation (#38)

* implement TracerFactory, begin migration to recommended library layout, use docker-compose and make to simplify development

* add tests for all TracerFactory method, move TraceFactory configuration in constructor

* run phan in travis-ci build

* rename namespace Tracing into Trace
This commit is contained in:
Beniamin 2020-01-07 15:39:14 +02:00 committed by Bob Strecansky
parent cf85f7d5f7
commit 0991f72146
24 changed files with 254 additions and 48 deletions

6
.phpcs.xml Normal file
View File

@ -0,0 +1,6 @@
<ruleset name="PSR2 extended">
<rule ref="PSR2" />
<rule ref="Squiz.Strings.DoubleQuoteUsage.NotRequired" />
<rule ref="Generic.Arrays.DisallowLongArraySyntax" />
<rule ref="PEAR.ControlStructures.MultiLineCondition" />
</ruleset>

View File

@ -13,10 +13,12 @@ cache:
- $HOME/.composer/cache
before_script:
- pecl install ast-1.0.4
- travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist
script:
- vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover
- vendor/bin/phan
after_script:
- |

13
Makefile Normal file
View File

@ -0,0 +1,13 @@
DC_RUN_PHP = docker-compose run php
install:
$(DC_RUN_PHP) composer install
test:
$(DC_RUN_PHP) php ./vendor/bin/phpunit --colors=always
phan:
$(DC_RUN_PHP) php ./vendor/bin/phan
examples: FORCE
$(DC_RUN_PHP) php ./examples/AlwaysOnTraceExample.php
bash:
$(DC_RUN_PHP) bash
FORCE:

8
docker-compose.yaml Normal file
View File

@ -0,0 +1,8 @@
version: '3.7'
services:
php:
build:
context: .
dockerfile: docker/Dockerfile
volumes:
- ./:/usr/src/myapp

11
docker/Dockerfile Normal file
View File

@ -0,0 +1,11 @@
FROM php:7.1-buster
RUN apt-get -y update && apt-get -y install git zip && \
curl -sS https://getcomposer.org/installer | php && \
mv composer.phar /usr/local/bin/composer && \
chmod +x /usr/local/bin/composer && \
pecl install ast-1.0.4 && \
echo "extension=ast.so" >> /usr/local/etc/php/conf.d/docker-php-ext-ast.ini
WORKDIR /usr/src/myapp

View File

@ -1,14 +1,15 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\Tracing\SpanContext;
use OpenTelemetry\Tracing\Sampler\AlwaysOffSampler;
use OpenTelemetry\Tracing\Tracer;
use OpenTelemetry\Context\SpanContext;
use OpenTelemetry\Trace\Sampler\AlwaysOffSampler;
use OpenTelemetry\Trace\Tracer;
use OpenTelemetry\Trace\TracerFactory;
$sampler = AlwaysOffSampler::shouldSample();
if ($sampler) {
$spanContext = SpanContext::generate(); // or extract from headers
$tracer = new Tracer($spanContext);
$tracer = TracerFactory::getInstance()
->getTracer('io.opentelemetry.contrib.php');
// start a span, register some events
$span = $tracer->createSpan('session.generate');

View File

@ -1,30 +1,29 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\Tracing\SpanContext;
use OpenTelemetry\Tracing\Sampler\AlwaysOnSampler;
use OpenTelemetry\Tracing\Tracer;
use OpenTelemetry\Trace\TracerFactory;
use OpenTelemetry\Trace\Sampler\AlwaysOnSampler;
$sampler = AlwaysOnSampler::shouldSample();
if ($sampler) {
$spanContext = SpanContext::generate(); // or extract from headers
$tracer = new Tracer($spanContext);
$tracer = (TracerFactory::getInstance())
->getTracer('io.opentelemetry.contrib.php');
// start a span, register some events
$span = $tracer->createSpan('session.generate');
$span->setAttributes(['remote_ip' => '1.2.3.4']);
$span->setAttribute('country', 'USA');
// start a span, register some events
$span = $tracer->createSpan('session.generate');
$span->setAttributes(['remote_ip' => '1.2.3.4']);
$span->setAttribute('country', 'USA');
$span->addEvent('found_login', [
$span->addEvent('found_login', [
'id' => 12345,
'username' => 'otuser',
]);
$span->addEvent('generated_session', [
]);
$span->addEvent('generated_session', [
'id' => md5(microtime(true))
]);
]);
$span->end(); // pass status as an optional argument
print_r($span); // print the span as a resulting output
$span->end(); // pass status as an optional argument
print_r($span); // print the span as a resulting output
} else {
echo "Sampling is not enabled";
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace OpenTelemetry\Tracing;
namespace OpenTelemetry\Context;
class SpanContext
{
@ -60,6 +60,6 @@ class SpanContext
/* TODO : Finish this function */
public function IsRemote() : bool
{
return false;
return false;
}
}

View File

@ -4,8 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Exporter;
use OpenTelemetry\Exporter\ExporterInterface;
use OpenTelemetry\Tracing\Span;
use OpenTelemetry\Trace\Span;
class BasisExporter implements ExporterInterface
{

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Exporter;
use OpenTelemetry\Tracing\Span;
use OpenTelemetry\Trace\Span;
/**
* A simple Exporter interface

View File

@ -4,8 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Exporter;
use OpenTelemetry\Exporter\ExporterInterface;
use OpenTelemetry\Tracing\Span;
use OpenTelemetry\Trace\Span;
/**
* Class ZipkinExporter - implements the export interface for data transfer via Zipkin protocol

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace OpenTelemetry\Tracing;
namespace OpenTelemetry\Trace;
class Event
{

View File

@ -1,5 +1,5 @@
<?php
namespace OpenTelemetry\Tracing\Sampler;
namespace OpenTelemetry\Trace\Sampler;
/**
* This implementation of the SamplerInterface always returns false.

View File

@ -1,5 +1,5 @@
<?php
namespace OpenTelemetry\Tracing\Sampler;
namespace OpenTelemetry\Trace\Sampler;
/**
* This implementation of the SamplerInterface always returns true.

View File

@ -1,5 +1,5 @@
<?php
namespace OpenTelemetry\Tracing\Sampler;
namespace OpenTelemetry\Trace\Sampler;
/**
* This interface is used to organize sampling logic.

View File

@ -1,10 +1,10 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tracing;
namespace OpenTelemetry\Trace;
use Exception;
use OpenTelemetry\Context\SpanContext;
class Span
{
@ -31,9 +31,9 @@ class Span
// describes the relationship between the Span, its parents, and its children in a Trace. SpanKind describes two independent properties that benefit tracing systems during analysis.
// This was also updated recently -> https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#spankind
// Links
// Links
// A Span may be linked to zero or more other Spans (defined by SpanContext) that are causally related. Links can point to SpanContexts inside a single Trace
// or across different Traces. Links can be used to represent batched operations where a Span was initiated by multiple initiating Spans,
// or across different Traces. Links can be used to represent batched operations where a Span was initiated by multiple initiating Spans,
// each representing a single incoming item being processed in the batch.
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/overview.md#links-between-spans
@ -89,7 +89,7 @@ class Span
return Status::new($this->statusCode, $this->statusDescription);
}
// I think this is too simple, see: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#isrecording
// I think this is too simple, see: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#isrecording
// -> This had an update this past month: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#isrecording
public function isRecording(): bool
{
@ -181,4 +181,4 @@ class Span
throw new Exception("Span is readonly");
}
}
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace OpenTelemetry;
namespace OpenTelemetry\Trace;
use OpenTelemetry\Tracing\Span;
use OpenTelemetry\Trace\Span;
interface SpanProcessorInterface
{

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace OpenTelemetry\Tracing;
namespace OpenTelemetry\Trace;
class Status
{

View File

@ -2,7 +2,9 @@
declare(strict_types=1);
namespace OpenTelemetry\Tracing;
namespace OpenTelemetry\Trace;
use OpenTelemetry\Context\SpanContext;
class Tracer
{

View File

@ -0,0 +1,74 @@
<?php
namespace OpenTelemetry\Trace;
use InvalidArgumentException;
use OpenTelemetry\Context\SpanContext;
use OpenTelemetry\Trace\SpanProcessorInterface;
class TracerFactory
{
/**
* @var self
*/
protected static $instance;
/**
* @var Tracer[]
*/
protected $tracers;
/**
* @var SpanProcessorInterface[]
*/
protected $spanProcessors;
/**
* TracerFactory constructor.
*
* @param SpanProcessorInterface[] $spanProcessors
*/
final private function __construct(array $spanProcessors = [])
{
foreach ($spanProcessors as $spanProcessor) {
if (!$spanProcessor instanceof SpanProcessorInterface) {
throw new InvalidArgumentException(
sprintf(
"Span Processors should be of type %s, but object of type %s provided",
SpanProcessorInterface::class,
gettype($spanProcessor) == "object" ? get_class($spanProcessor) : gettype($spanProcessor)
)
);
}
}
$this->spanProcessors = $spanProcessors;
}
/**
* @param SpanProcessorInterface[] $spanProcessors
*
* @return static
*/
public static function getInstance(array $spanProcessors = []): self
{
if (self::$instance instanceof TracerFactory) {
return self::$instance;
}
$instance = new TracerFactory($spanProcessors);
return self::$instance = $instance;
}
public function getTracer(string $name, string $version = ""): Tracer
{
if ($this->tracers[$name] instanceof Tracer) {
return $this->tracers[$name];
}
$spanContext = SpanContext::generate();
return $this->tracers[$name] = new Tracer($spanContext);
}
}

View File

@ -6,11 +6,9 @@ namespace OpenTelemetry\Tests;
use OpenTelemetry\Exporter\BasisExporter;
use OpenTelemetry\Exporter\ZipkinExporter;
use OpenTelemetry\Tracing\Builder;
use OpenTelemetry\Tracing\SpanContext;
use OpenTelemetry\Tracing\Status;
use OpenTelemetry\Tracing\Tracer;
use OpenTelemetry\Transport\TarantoolQueueTransport;
use OpenTelemetry\Context\SpanContext;
use OpenTelemetry\Trace\Status;
use OpenTelemetry\Trace\Tracer;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;

View File

@ -0,0 +1,94 @@
<?php
namespace OpenTelemetry\Tests\Trace;
use Error;
use InvalidArgumentException;
use OpenTelemetry\Trace\SpanProcessorInterface;
use OpenTelemetry\Trace\TracerFactory;
use PHPUnit\Framework\TestCase;
use ReflectionProperty;
use StdClass;
class TracerFactoryTest extends TestCase
{
public function tearDown()
{
// since a singleton is tested we need to reset instance after every test
$refProperty = new ReflectionProperty(TracerFactory::class, 'instance');
$refProperty->setAccessible(true);
$refProperty->setValue(null);
}
/**
* @test
* @expectedException Error
*/
public function shouldNotBeAbleToInstantiateDirectly()
{
new TracerFactory();
}
/**
* @test
*/
public function gettingSameTracerMultipleTimesShouldReturnSameObject()
{
$tracer1 = TracerFactory::getInstance()->getTracer('test_tracer');
$tracer2 = TracerFactory::getInstance()->getTracer('test_tracer');
$this->assertTrue($tracer1 === $tracer2);
}
/**
* @test
*/
public function callingSameInstanceMultipleTimesShouldReturnSameFactoryObject()
{
$instance1 = TracerFactory::getInstance();
$instance2 = TracerFactory::getInstance();
$this->assertTrue($instance1 === $instance2);
}
/**
* @test
*/
public function shouldInstantiateWithoutErrorIfConfigurationIsOk()
{
$factory = TracerFactory::getInstance([
$this->createMock(SpanProcessorInterface::class),
$this->createMock(SpanProcessorInterface::class)
]);
$this->assertInstanceOf(TracerFactory::class, $factory);
}
/**
* @test
* @dataProvider wrongConfigurationDataProvider
* @expectedException InvalidArgumentException
*/
public function shouldThrowExceptionIfConfigurationParamsAreInvalid($spanProcessors)
{
TracerFactory::getInstance($spanProcessors);
}
public function wrongConfigurationDataProvider()
{
return [
'array of numbers' => [
'spanProcessors' => [1, -1, 0.1, -0.1, 0]
],
'array of strings' => [
'spanProcessors' => ['aaa', 'bbb', '']
],
'array of standardObjects' => [
'spanProcessors' => [new StdClass(), new StdClass()]
],
'array of boolean' => [
'spanProcessors' => [true, false, null]
]
];
}
}

View File

@ -1,7 +1,7 @@
<?php
namespace OpenTelemetry\Tests\Unit\Tracing\Sampler;
use OpenTelemetry\Tracing\Sampler\AlwaysOffSampler;
use OpenTelemetry\Trace\Sampler\AlwaysOffSampler;
use PHPUnit\Framework\TestCase;
class AlwaysOffSamplerTest extends TestCase
{

View File

@ -2,7 +2,7 @@
namespace OpenTelemetry\Tests\Unit\Tracing\Sampler;
use OpenTelemetry\Tracing\Sampler\AlwaysOnSampler;
use OpenTelemetry\Trace\Sampler\AlwaysOnSampler;
use PHPUnit\Framework\TestCase;
class AlwaysOnTest extends TestCase