Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tune up the Samplers #60

Merged
merged 6 commits into from
Aug 23, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
.settings
.buildpath
.project
.idea
# Please do not use this ignore file to define platform specific files.
#
# For these purposes create a global .gitignore file, which is a list of rules
# for ignoring files in every Git repository on your computer.
#
# https://help.github.com/articles/ignoring-files/#create-a-global-gitignore

jaeger-idl
vendor
Expand Down
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

# Jaeger Bindings for PHP OpenTracing API

This is a client-side library that can be used to instrument PHP apps for distributed trace collection, and to send those traces to Jaeger. See the [OpenTracing PHP API](https://github.com/opentracing/opentracing-php) for additional detail.
This is a client-side library that can be used to instrument PHP apps for distributed trace collection,
and to send those traces to Jaeger. See the [OpenTracing PHP API](https://github.com/opentracing/opentracing-php)
for additional detail.

## Contributing and Developing

Please see [CONTRIBUTING.md](./CONTRIBUTING.md).

## Installation

```json
{
"require": {
"jonahgeorge/jaeger-client-php": "0.3.0"
}
}
Install [Composer](https://getcomposer.org) in a common location or in your project. Then run the installer as follows:

```bash
php composer.phar require jonahgeorge/jaeger-client-php
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really just the smallest nit: Can we get rid of the composer install instruction and do

composer require <>

instead of the phar

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed! :)

```

## Getting Started
Expand Down Expand Up @@ -54,7 +54,6 @@ Tests are located in the `tests` directory. See [tests/README.md](./tests/README

## Roadmap

- [Support Span logging](https://github.com/jonahgeorge/jaeger-client-php/issues/1)
- [Support Span baggage](https://github.com/jonahgeorge/jaeger-client-php/issues/5)
- [Support PHP Version 5.6](https://github.com/jonahgeorge/jaeger-client-php/issues/11)
- [Support Tracer metrics](https://github.com/jonahgeorge/jaeger-client-php/issues/12)
Expand Down
2 changes: 1 addition & 1 deletion src/Jaeger/Codec/TextCodec.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private function spanContextFromString($value): array
$parts = explode(':', $value);

if (count($parts) != 4) {
throw new Exception('Malformed tracer state string');
throw new Exception('Malformed tracer state string.');
}

return [
Expand Down
2 changes: 1 addition & 1 deletion src/Jaeger/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function __construct(array $config, string $serviceName = null, LoggerInt

$this->serviceName = $config['service_name'] ?? $serviceName;
if ($this->serviceName === null) {
throw new Exception('service_name required in the config or param');
throw new Exception('service_name required in the config or param.');
}

$this->logger = $logger ?: new NullLogger();
Expand Down
24 changes: 21 additions & 3 deletions src/Jaeger/Sampler/ConstSampler.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,28 @@

/**
* ConstSampler always returns the same decision.
*
* @package Jaeger\Sampler
*/
class ConstSampler implements SamplerInterface
{
/**
* Whether or not the new trace should be sampled.
*
* @var bool
*/
private $decision;

/**
* A list of the sampler tags.
*
* @var array
*/
private $tags = [];

/**
* ConstSampler constructor.
*
* @param bool $decision
*/
public function __construct(bool $decision = true)
Expand All @@ -31,20 +38,31 @@ public function __construct(bool $decision = true)
SAMPLER_TYPE_TAG_KEY => SAMPLER_TYPE_CONST,
SAMPLER_PARAM_TAG_KEY => $decision,
];

$this->decision = $decision;
}

/**
* @param string $traceId
* @param string $operation
* {@inheritdoc}
*
* @param string $traceId The traceId on the span.
* @param string $operation The operation name set on the span.
* @return array
*/
public function isSampled(string $traceId, string $operation = ''): array
{
return array($this->decision, $this->tags);
return [$this->decision, $this->tags];
}

/**
* {@inheritdoc}
*
* Only implemented to satisfy the sampler interface.
*
* @return void
*/
public function close()
{
// nothing to do
}
}
31 changes: 25 additions & 6 deletions src/Jaeger/Sampler/ProbabilisticSampler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,45 @@

namespace Jaeger\Sampler;

use Exception;
use OutOfBoundsException;
use const Jaeger\SAMPLER_PARAM_TAG_KEY;
use const Jaeger\SAMPLER_TYPE_PROBABILISTIC;
use const Jaeger\SAMPLER_TYPE_TAG_KEY;

/**
* A sampler that randomly samples a certain percentage of traces specified
* by the samplingRate, in the range between 0.0 and 1.0.
*
* @package Jaeger\Sampler
*/
class ProbabilisticSampler implements SamplerInterface
{
/**
* The sampling rate rate between 0.0 and 1.0.
*
* @var float
*/
private $rate;

/**
* A list of the sampler tags.
*
* @var array
*/
private $tags = [];

/**
* @var float|int
* The boundary of the sample sampling rate.
*
* @var float
*/
private $boundary;

/**
* ProbabilisticSampler constructor.
*
* @param float $rate
* @throws Exception
* @throws OutOfBoundsException
*/
public function __construct(float $rate)
{
Expand All @@ -41,24 +50,34 @@ public function __construct(float $rate)
];

if ($rate <= 0.0 || $rate >= 1.0) {
throw new Exception('Sampling rate must be between 0.0 and 1.0');
throw new OutOfBoundsException('Sampling rate must be between 0.0 and 1.0.');
}

$this->rate = $rate;
$this->boundary = $rate * PHP_INT_MAX;
}

/**
* @param string $traceId
* @param string $operation
* {@inheritdoc}
*
* @param string $traceId The traceId on the span.
* @param string $operation The operation name set on the span.
* @return array
*/
public function isSampled(string $traceId, string $operation = ''): array
{
return [($traceId < $this->boundary), $this->tags];
}

/**
* {@inheritdoc}
*
* Only implemented to satisfy the sampler interface.
*
* @return void
*/
public function close()
{
// nothing to do
}
}
20 changes: 20 additions & 0 deletions src/Jaeger/Sampler/SamplerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,28 @@

namespace Jaeger\Sampler;

/**
* Sampler is responsible for deciding if a new trace should be sampled and captured for storage.
*
* @package Jaeger\Sampler
*/
interface SamplerInterface
{
/**
* Whether or not the new trace should be sampled.
*
* Implementations should return an array in the format [$decision, $tags].
*
* @param string $traceId The traceId on the span.
* @param string $operation The operation name set on the span.
* @return array
*/
public function isSampled(string $traceId, string $operation);

/**
* Release any resources used by the sampler.
*
* @return void
*/
public function close();
}
2 changes: 1 addition & 1 deletion tests/Jaeger/Codec/TextCodecTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function testSpanContextParsingFromHeader()

/**
* @expectedException \Exception
* @expectedExceptionMessage Malformed tracer state string
* @expectedExceptionMessage Malformed tracer state string.
*/
public function testInvalidSpanContextParsingFromHeader()
{
Expand Down
2 changes: 1 addition & 1 deletion tests/Jaeger/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function testCreateTracer()

/**
* @expectedException Exception
* @expectedExceptionMessage service_name required in the config or param
* @expectedExceptionMessage service_name required in the config or param.
*/
function testThrowExceptionWhenServiceNameIsNotDefined()
{
Expand Down
46 changes: 27 additions & 19 deletions tests/Jaeger/Sampler/ConstSamplerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,40 @@

use Jaeger\Sampler\ConstSampler;
use PHPUnit\Framework\TestCase;
use const Jaeger\SAMPLER_PARAM_TAG_KEY;
use const Jaeger\SAMPLER_TYPE_CONST;
use const Jaeger\SAMPLER_TYPE_TAG_KEY;

class ConstSamplerTest extends TestCase
{
private function getTags($type, $param)
/**
* @test
* @dataProvider samplerProvider
* @param bool $decision
* @param mixed $traceId
*/
public function shouldDetermineWhetherOrTraceShouldBeSampled($decision, $traceId)
{
return [
'sampler.type' => $type,
'sampler.param' => $param,
];
}
$sampler = new ConstSampler($decision);

public function testConstSampler()
{
$sampler = new ConstSampler(True);
list($sampled, $tags) = $sampler->isSampled(1);
$this->assertTrue($sampled);
list($sampled, $tags) = $sampler->isSampled($traceId);

list($sampled, $tags) = $sampler->isSampled(PHP_INT_MAX);
$this->assertTrue($sampled);
$this->assertEquals($decision, $sampled);
$this->assertEquals([
SAMPLER_TYPE_TAG_KEY => SAMPLER_TYPE_CONST,
SAMPLER_PARAM_TAG_KEY => $decision,
], $tags);

$sampler = new ConstSampler(False);
list($sampled, $tags) = $sampler->isSampled(1);
$this->assertFalse($sampled);
$sampler->close();
}

list($sampled, $tags) = $sampler->isSampled(PHP_INT_MAX);
$this->assertFalse($sampled);
$this->assertEquals($tags, $this->getTags('const', False));
public function samplerProvider()
{
return [
[true, 1],
[true, PHP_INT_MAX],
[false, 1],
[false, PHP_INT_MAX],
];
}
}
58 changes: 46 additions & 12 deletions tests/Jaeger/Sampler/ProbablisticSamplerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,61 @@

use Jaeger\Sampler\ProbabilisticSampler;
use PHPUnit\Framework\TestCase;
use const Jaeger\SAMPLER_PARAM_TAG_KEY;
use const Jaeger\SAMPLER_TYPE_PROBABILISTIC;
use const Jaeger\SAMPLER_TYPE_TAG_KEY;

class ProbablisticSamplerTest extends TestCase
{
private function getTags($type, $param)
/**
* @test
* @dataProvider samplerProvider
* @param float $rate
* @param mixed $traceId
* @param bool $decision
*/
public function shouldDetermineWhetherOrTraceShouldBeSampled($rate, $traceId, $decision)
{
$sampler = new ProbabilisticSampler($rate);

list($sampled, $tags) = $sampler->isSampled($traceId);

$this->assertEquals($decision, $sampled);
$this->assertEquals([
SAMPLER_TYPE_TAG_KEY => SAMPLER_TYPE_PROBABILISTIC,
SAMPLER_PARAM_TAG_KEY => $rate,
], $tags);

$sampler->close();
}

public function samplerProvider()
{
return [
'sampler.type' => $type,
'sampler.param' => $param,
[0.5, PHP_INT_MIN + 10, true],
[0.5, PHP_INT_MAX - 10, false],
];
}

public function testProbabilisticSampler()
/**
* @test
* @dataProvider rateProvider
* @param mixed $rate
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Sampling rate must be between 0.0 and 1.0.
*/
public function shouldThrowOutOfBoundsExceptionInCaseOfInvalidRate($rate)
{
$sampler = new ProbabilisticSampler(0.5);

list($sampled, $tags) = $sampler->isSampled(PHP_INT_MIN + 10);
$this->assertTrue($sampled);
$this->assertEquals($tags, $this->getTags('probabilistic', 0.5));
new ProbabilisticSampler($rate);
}

list($sampled, $tags) = $sampler->isSampled(PHP_INT_MAX - 10);
$this->assertFalse($sampled);
$sampler->close();
public function rateProvider()
{
return [
[1.1],
[-0.1],
[PHP_INT_MAX],
[PHP_INT_MIN],
];
}
}