Skip to content

Commit

Permalink
[#21] Adds mock tracer.
Browse files Browse the repository at this point in the history
  • Loading branch information
jcchavezs committed Feb 1, 2018
1 parent 8a7ab2d commit 0be21c3
Show file tree
Hide file tree
Showing 10 changed files with 383 additions and 6 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,15 @@ Tracers will throw an exception if the requested format is not handled by them.
- `Tracer::FORMAT_BINARY` makes no assumptions about the data format other than it is
proprietary and each Tracer can handle it as it wants.

## Mock implementation

OpenTracing PHP comes with a mock implementation, it has three purposes:

1. Helps to iron the API.
2. Works as a reference implementation.
3. Enhances vendor agnostic unit testing as it allows developers to inspect the tracing objects
in order to do assertions about them.

## Coding Style

Opentracing PHP follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
Expand Down
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
"psr-4": {
"OpenTracing\\": "./src/OpenTracing/"
},
"files": ["./src/OpenTracing/Ext/Tags.php", "./src/OpenTracing/Formats.php"]
"files": ["./src/OpenTracing/Tags.php", "./src/OpenTracing/Formats.php"]
},
"autoload-dev": {
"psr-4": {
"OpenTracingTests\\": "./tests/"
"OpenTracing\\Tests\\": "./tests/OpenTracing",
"OpenTracingMock\\": "./src/OpenTracingMock",
"OpenTracingMock\\Tests\\": "./tests/OpenTracingMock"
}
},
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/OpenTracing/Span.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function overwriteOperationName($newOperationName);
* Sets tags to the Span in key:value format, key must be a string and tag must be either
* a string, a boolean value, or a numeric type.
*
* As an implementor, consider using "standard tags" listed in {@see \OpenTracing\Ext\Tags}
* As an implementor, consider using "standard tags" listed in {@see \OpenTracing\Tags}
*
* If the span is already finished, a warning should be logged.
*
Expand Down
2 changes: 1 addition & 1 deletion src/OpenTracing/Ext/Tags.php → src/OpenTracing/Tags.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace OpenTracing\Ext\Tags;
namespace OpenTracing\Tags;

/**
* SpanKind hints at relationship between spans, e.g. client/server
Expand Down
144 changes: 144 additions & 0 deletions src/OpenTracingMock/Span.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace OpenTracingMock;

use OpenTracing\Span as OTSpan;

final class Span implements OTSpan
{
/**
* @var string
*/
private $operationName;

/**
* @var SpanContext
*/
private $context;

/**
* @var array
*/
private $tags;

/**
* @var array
*/
private $logs;

/**
* @var int
*/
private $startTime;

/**
* @var int|null
*/
private $duration;

private function __construct($operationName, SpanContext $context, $startTime)
{
$this->operationName = $operationName;
$this->context = $context;
$this->startTime = $startTime;
}

public static function create($operationName, SpanContext $context, $startTime = null)
{
return new self($operationName, $context, $startTime ?: time());
}

/**
* {@inheritdoc}
*/
public function getOperationName()
{
return $this->operationName;
}

/**
* {@inheritdoc}
*/
public function getContext()
{
return $this->context;
}

public function getStartTime()
{
return $this->startTime;
}

/**
* {@inheritdoc}
*/
public function finish($finishTime = null, array $logRecords = [])
{
$finishTime = ($finishTime ?: time());
$this->log($logRecords, $finishTime);
$this->duration = $finishTime - $this->startTime;
}

public function isFinished()
{
return $this->duration !== null;
}

public function getDuration()
{
return $this->duration;
}

/**
* {@inheritdoc}
*/
public function overwriteOperationName($newOperationName)
{
$this->operationName = (string) $newOperationName;
}

/**
* {@inheritdoc}
*/
public function setTags(array $tags)
{
$this->tags = array_merge($this->tags, $tags);
}

public function getTags()
{
return $this->tags;
}

/**
* {@inheritdoc}
*/
public function log(array $fields = [], $timestamp = null)
{
$this->logs[] = [
'timestamp' => $timestamp ?: time(),
'fields' => $fields,
];
}

public function getLogs()
{
return $this->logs;
}

/**
* {@inheritdoc}
*/
public function addBaggageItem($key, $value)
{
$this->context = $this->context->withBaggageItem($key, $value);
}

/**
* {@inheritdoc}
*/
public function getBaggageItem($key)
{
return $this->context->getBaggageItem($key);
}
}
98 changes: 98 additions & 0 deletions src/OpenTracingMock/SpanContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

namespace OpenTracingMock;

use ArrayIterator;
use OpenTracing\SpanContext as OTSpanContext;

final class SpanContext implements OTSpanContext
{
/**
* @var int
*/
private $traceId;

/**
* @var int
*/
private $spanId;

/**
* @var bool
*/
private $isSampled;

/**
* @var array
*/
private $items;

private function __construct($traceId, $spanId, $isSampled, array $items)
{
$this->traceId = $traceId;
$this->spanId = $spanId;
$this->isSampled = $isSampled;
$this->items = $items;
}

public static function create($traceId, $spanId, $sampled = true, array $items = [])
{
return new self($traceId, $spanId, $sampled, $items);
}

public static function createAsRoot($sampled = true, array $items = [])
{
$traceId = $spanId = self::nextId();
return new self($traceId, $spanId, $sampled, $items);
}

public static function createAsChildOf(SpanContext $spanContext)
{
$spanId = self::nextId();
return new self($spanContext->traceId, $spanId, $spanContext->isSampled, $spanContext->items);
}

public function getTraceId()
{
return $this->traceId;
}

public function getSpanId()
{
return $this->spanId;
}

public function isSampled()
{
return $this->isSampled;
}

/**
* {@inheritdoc}
*/
public function getIterator()
{
return new ArrayIterator($this->items);
}

/**
* {@inheritdoc}
*/
public function getBaggageItem($key)
{
return array_key_exists($key, $this->items) ? $this->items[$key] : null;
}

/**
* {@inheritdoc}
*/
public function withBaggageItem($key, $value)
{
return new self(array_merge($this->items, [$key => $value]));
}

private static function nextId()
{
return mt_rand(0, 99999);
}
}
95 changes: 95 additions & 0 deletions src/OpenTracingMock/Tracer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace OpenTracingMock;

use OpenTracing\Exceptions\UnsupportedFormat;
use OpenTracing\SpanOptions;
use OpenTracing\Tracer as OTTracer;
use OpenTracing\SpanContext as OTSpanContext;

final class Tracer implements OTTracer
{
/**
* @var array|Span[]
*/
private $spans = [];

/**
* @var array|callable[]
*/
private $injectors;

/**
* @var array|callable[]
*/
private $extractors;

private function __construct(array $injectors, array $extractors)
{
$this->injectors = $injectors;
$this->extractors = $extractors;
}

public static function create(array $injectors = [], array $extractors = [])
{
return new self($injectors, $extractors);
}

/**
* {@inheritdoc}
*/
public function startSpan($operationName, $options = [])
{
if (!($options instanceof SpanOptions)) {
$options = SpanOptions::create($options);
}

if ($options->getReferences()) {
$spanContext = SpanContext::createAsRoot();
} else {
$spanContext = SpanContext::createAsChildOf($options->getReferences()[0]);
}

$span = Span::create(
$operationName,
$spanContext,
$options->getStartTime()
);

$span->setTags($options->getTags());

$this->spans[] = $span;
}

/**
* {@inheritdoc}
*/
public function inject(OTSpanContext $spanContext, $format, &$carrier)
{
if (!array_key_exists($format, $this->injectors)) {
throw UnsupportedFormat::forFormat($format);
}

call_user_func($this->injectors[$format], $spanContext, $carrier);
}

/**
* {@inheritdoc}
*/
public function extract($format, $carrier)
{
if (!array_key_exists($format, $this->injectors)) {
throw UnsupportedFormat::forFormat($format);
}

return call_user_func($this->extractors[$format], $carrier);
}

/**
* {@inheritdoc}
*/
public function flush()
{
$this->spans = [];
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace OpenTracingTests\Unit;
namespace OpenTracing\Tests;

use OpenTracing\Exceptions\InvalidReferenceArgument;
use OpenTracing\NoopSpanContext;
Expand Down
Loading

0 comments on commit 0be21c3

Please sign in to comment.