Skip to content
This repository has been archived by the owner on Jul 31, 2023. It is now read-only.

fixing hexdec on a 16 char hex number, which could actually exceed INT64 #8

Merged
merged 29 commits into from
Oct 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6145db1
fixing hexdec on a 16 char hex number, which could actually exceed INT64
dragoscirjan Oct 3, 2018
214572a
Updated method names to camel case
dragoscirjan Oct 3, 2018
9f2fd8e
Update SpanConverter.php
dragoscirjan Oct 3, 2018
1c195a4
Update SpanConverter.php
dragoscirjan Oct 3, 2018
dc38d67
added pre-install-* script limiter + unit tests for bc and gmp math
dragoscirjan Oct 5, 2018
69565fc
fixed typo
dragoscirjan Oct 5, 2018
456014b
lint fixes
dragoscirjan Oct 5, 2018
aed10eb
fixed integration test
dragoscirjan Oct 5, 2018
ff90764
linter fix
dragoscirjan Oct 5, 2018
a0e17cf
linter fix
dragoscirjan Oct 5, 2018
bad181b
better way of handling big math
dragoscirjan Oct 5, 2018
a998864
brought back missing big math code
dragoscirjan Oct 5, 2018
3f991fe
fixed bcmath prezence test
dragoscirjan Oct 5, 2018
16760e9
removed un-necessary checks since they were made @ install anyways
dragoscirjan Oct 5, 2018
36c796d
no cache
dragoscirjan Oct 5, 2018
61876e2
fixed tests
dragoscirjan Oct 5, 2018
abd0193
converting SpanConverter to interface & implementations
dragoscirjan Oct 8, 2018
e493b09
overzealous replace - const
dragoscirjan Oct 8, 2018
dc8cd10
removed old code
dragoscirjan Oct 8, 2018
96ab6b0
additional tests for bcmath
dragoscirjan Oct 8, 2018
9dddc91
code clean & lint fix
dragoscirjan Oct 8, 2018
0e8fcbf
test fix
dragoscirjan Oct 8, 2018
d3a6854
test fixes
dragoscirjan Oct 8, 2018
a8ebc7c
Merge pull request #1 from dragoscirjan/feat/span-converter-interface
dragoscirjan Oct 8, 2018
49a462b
moved hexdec converter methods into their own classes having their ow…
dragoscirjan Oct 8, 2018
2890505
Merge pull request #2 from dragoscirjan/feat/span-converter-interface
dragoscirjan Oct 8, 2018
ae081aa
lint fix
dragoscirjan Oct 8, 2018
bd80057
comments and interface removal
dragoscirjan Oct 9, 2018
d38bbc5
added variable declaration for `spanConverter`
dragoscirjan Oct 9, 2018
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
7 changes: 4 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
unit-config: &unit-config
steps:
# library requires sockets extension
- run: sudo docker-php-ext-install sockets
- run: sudo apt-get install -y libgmp-dev re2c libmhash-dev libmcrypt-dev file && sudo ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/local/include/
- run: sudo docker-php-ext-install bcmath gmp sockets

- checkout

# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "composer.json" }}
- v1-dependencies-{{ checksum "composer.json" }}-v1
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- v1-dependencies-v1-

- run: composer install -n --prefer-dist

Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ WORKDIR /workspace

# current user is circleci
RUN sudo chown -R $(whoami) /workspace
RUN sudo docker-php-ext-install sockets
RUN sudo apt-get update && sudo apt-get install -y libgmp-dev re2c libmhash-dev libmcrypt-dev file && sudo ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/local/include/
RUN sudo docker-php-ext-install bcmath gmp sockets

RUN composer install -n --prefer-dist

ENTRYPOINT []
ENTRYPOINT []
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@
"psr-4": {
"OpenCensus\\Trace\\Exporter\\": "src/"
}
},
"scripts": {
"post-dependencies-solving": "OpenCensus\\Trace\\Exporter\\Installer::checkPhpExtDependency"
}
}
14 changes: 14 additions & 0 deletions src/Installer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace OpenCensus\Trace\Exporter;

class Installer
{
public static function checkPhpExtDependency()
{
if (!extension_loaded('bcmath') && !extension_loaded('gmp')) {
throw new \Exception('`opencensus-php-exporter-jaeger` requires one of the two extensions to be '
. 'installed: `php-bcmath` or `php-gmp`');
}
}
}
50 changes: 50 additions & 0 deletions src/Jaeger/HexdecConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* Copyright 2018 OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace OpenCensus\Trace\Exporter\Jaeger;

use OpenCensus\Trace\Exporter\Jaeger\HexdecConverterInterface;

/**
* Hexdec converter class. Used for converting hex string values into numbers by using
* `gmp` as large numbers library.
*/
class HexdecConverter implements HexdecConverterInterface
dragoscirjan marked this conversation as resolved.
Show resolved Hide resolved
{

const MAX_INT_64S = '9223372036854775807';

/**
* Hexdec convertion method for large numbers with limitation to PhP's signed INT64, using gmp.
* Warning: Method may not work with hex numbers larger than 8 'digits'.
*
* @param str $hex
* @return number
*/
public function convert($hex)
{
$dec = 0;
$len = strlen($hex);
for ($i = 1; $i <= $len; $i++) {
$dec = gmp_add($dec, gmp_mul(strval(hexdec($hex[$i - 1])), gmp_pow('16', strval($len - $i))));
}
if (gmp_cmp($dec, self::MAX_INT_64S) > 0) {
$dec = gmp_sub(gmp_and($dec, self::MAX_INT_64S), gmp_add(self::MAX_INT_64S, '1'));
}
return intval($dec);
}
}
50 changes: 50 additions & 0 deletions src/Jaeger/HexdecConverterBcMath.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* Copyright 2018 OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace OpenCensus\Trace\Exporter\Jaeger;

use OpenCensus\Trace\Exporter\Jaeger\HexdecConverterInterface;

/**
* Hexdec converter class. Used for converting hex string values into numbers by using
* `bcmath` as large numbers library.
*/
class HexdecConverterBcMath implements HexdecConverterInterface
dragoscirjan marked this conversation as resolved.
Show resolved Hide resolved
{

const MAX_INT_64S = '9223372036854775807';

/**
* Hexdec convertion method for big data with limitation to PhP's signed INT64, using bcmath.
* Warning: Method may not work with hex numbers larger than 8 'digits'.
*
* @param str $hex
* @return number
*/
public function convert($hex)
{
$dec = 0;
$len = strlen($hex);
for ($i = 1; $i <= $len; $i++) {
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
}
if (bccomp($dec, self::MAX_INT_64S) > 0) {
$dec = bcsub(bcsub($dec, self::MAX_INT_64S), bcadd(self::MAX_INT_64S, '2'));
}
return intval($dec);
}
}
33 changes: 33 additions & 0 deletions src/Jaeger/HexdecConverterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
/**
* Copyright 2018 OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace OpenCensus\Trace\Exporter\Jaeger;

/**
* Hexdec converter interface. Used for converting hex string values into numbers by using
* large numbers math libraries like Gmp or BCMath.
*/
interface HexdecConverterInterface
{
/**
* Hexdec convertion method for large numbers with limitation to PhP's signed INT64.
*
* @param str $hex
* @return number
*/
public function convert($hex);
}
80 changes: 57 additions & 23 deletions src/Jaeger/SpanConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,37 @@
*/
class SpanConverter
{

/**
* Convert an OpenCensus Span to its Jaeger Thrift representation.
*@var HexdecConverterInterface
*/
private $hexdec = null;

/**
* Create a new Span Converter.
*
* @access private
* @param array $options [optional] {
* @type HexdecConvertor convertor for hex values
* }
*/
public function __construct(array $options = [])
{
$this->hexdec = empty($options['hexdecConverter']) ? new HexdecConverter() : $options['hexdecConverter'];
}

/**
* Convert an OpenCensus Span to its Jaeger Thrift representation.
*
* @param SpanData $span The span to convert.
* @return Span The Jaeger Thrift Span representation.
*/
public static function convertSpan(SpanData $span)
public function convertSpan(SpanData $span)
{
$startTime = self::convertTimestamp($span->startTime());
$endTime = self::convertTimestamp($span->endTime());
$spanId = hexdec($span->spanId());
$parentSpanId = hexdec($span->parentSpanId());
list($highTraceId, $lowTraceId) = self::convertTraceId($span->traceId());
$startTime = $this->convertTimestamp($span->startTime());
$endTime = $this->convertTimestamp($span->endTime());
$spanId = $this->hexdec->convert($span->spanId());
$parentSpanId = $this->hexdec->convert($span->parentSpanId());
list($highTraceId, $lowTraceId) = $this->convertTraceId($span->traceId());

return new Span([
'traceIdLow' => $lowTraceId,
Expand All @@ -61,15 +77,15 @@ public static function convertSpan(SpanData $span)
'flags' => 0,
'startTime' => $startTime,
'duration' => $endTime - $startTime,
'tags' => self::convertTags($span->attributes()),
'logs' => self::convertLogs($span->timeEvents())
'tags' => $this->convertTags($span->attributes()),
'logs' => $this->convertLogs($span->timeEvents())
]);
}

/**
* Convert an associative array of $key => $value to Jaeger Tags.
*/
public static function convertTags(array $attributes)
public function convertTags(array $attributes)
{
$tags = [];
foreach ($attributes as $key => $value) {
Expand All @@ -82,33 +98,48 @@ public static function convertTags(array $attributes)
return $tags;
}

private static function convertLogs(array $timeEvents)
/**
*
* @param array $timeEvents
* @return array
*/
private function convertLogs(array $timeEvents)
{
return array_map(function (TimeEvent $timeEvent) {
if ($timeEvent instanceof Annotation) {
return self::convertAnnotation($timeEvent);
return $this->convertAnnotation($timeEvent);
} elseif ($timeEvent instanceof MessageEvent) {
return self::convertMessageEvent($timeEvent);
return $this->convertMessageEvent($timeEvent);
} else {
}
}, $timeEvents);
}

private static function convertAnnotation(Annotation $annotation)
/**
*
* @param Annotation $annotation
* @return Log
*/
private function convertAnnotation(Annotation $annotation)
{
return new Log([
'timestamp' => self::convertTimestamp($annotation->time()),
'fields' => self::convertTags($annotation->attributes() + [
'timestamp' => $this->convertTimestamp($annotation->time()),
'fields' => $this->convertTags($annotation->attributes() + [
'description' => $annotation->description()
])
]);
}

private static function convertMessageEvent(MessageEvent $messageEvent)
/**
*
* @param MessageEvent $messageEvent
* @return Log
*/
private function convertMessageEvent(MessageEvent $messageEvent)
{
return new Log([
'timestamp' => self::convertTimestamp($messageEvent->time()),
'fields' => self::convertTags([
'timestamp' => $this->convertTimestamp($messageEvent->time()),
'fields' => $this->convertTags([
'type' => $messageEvent->type(),
'id' => $messageEvent->id(),
'uncompressedSize' => $messageEvent->uncompressedSize(),
Expand All @@ -120,20 +151,23 @@ private static function convertMessageEvent(MessageEvent $messageEvent)
/**
* Return the given timestamp as an int in milliseconds.
*/
private static function convertTimestamp(\DateTimeInterface $dateTime)
private function convertTimestamp(\DateTimeInterface $dateTime)
{
return (int)((float) $dateTime->format('U.u') * 1000 * 1000);
}

/**
* Split the provided hexId into 2 64-bit integers (16 hex chars each).
* Returns array of 2 int values.
*
* @param str $hexId
* @return array
*/
private static function convertTraceId($hexId)
private function convertTraceId($hexId)
{
return array_slice(
array_map(
'hexdec',
[$this->hexdec, 'convert'],
str_split(
substr(
str_pad($hexId, 32, "0", STR_PAD_LEFT),
Expand Down
18 changes: 12 additions & 6 deletions src/JaegerExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,27 @@ class JaegerExporter implements ExporterInterface
/**
* @var string
*/
protected $host;
private $host;

/**
* @var int
*/
protected $port;
private $port;

/**
* @var Process
*/
protected $process;
private $process;

/**
* @var AgentIf
*/
protected $client;
private $client;

/**
* @var SpanConverter
*/
private $spanConverter;

/**
* Create a new Jaeger Exporter.
Expand All @@ -76,9 +81,10 @@ public function __construct($serviceName, array $options = [])
];
$this->host = $options['host'];
$this->port = (int) $options['port'];
$this->spanConverter = empty($options['spanConverter']) ? new SpanConverter() : $options['spanConverter'];
dragoscirjan marked this conversation as resolved.
Show resolved Hide resolved
$this->process = new Process([
'serviceName' => $serviceName,
'tags' => SpanConverter::convertTags($options['tags'])
'tags' => $this->spanConverter->convertTags($options['tags'])
]);
$this->client = $options['client'];
}
Expand All @@ -98,7 +104,7 @@ public function export(array $spans)
$client = $this->client ?: new UDPClient($this->host, $this->port);
$batch = new Batch([
'process' => $this->process,
'spans' => array_map([SpanConverter::class, 'convertSpan'], $spans)
'spans' => array_map([$this->spanConverter, 'convertSpan'], $spans)
]);

$client->emitBatch($batch);
Expand Down
Loading