diff --git a/src/Context/SpanContext.php b/src/Context/SpanContext.php index c80e832..3917107 100644 --- a/src/Context/SpanContext.php +++ b/src/Context/SpanContext.php @@ -3,6 +3,7 @@ use Ipunkt\LaravelJaeger\Context\Exceptions\NoSpanException; use Ipunkt\LaravelJaeger\Context\Exceptions\NoTracerException; use Ipunkt\LaravelJaeger\Context\TracerBuilder\TracerBuilder; +use Ipunkt\LaravelJaeger\LogCleaner\LogCleaner; use Ipunkt\LaravelJaeger\SpanExtractor\SpanExtractor; use Ipunkt\LaravelJaeger\TagPropagator\TagPropagator; use Jaeger\Jaeger; @@ -45,19 +46,26 @@ class SpanContext implements Context * @var TracerBuilder */ private $tracerBuilder; + /** + * @var LogCleaner + */ + private $logCleaner; /** * MessageContext constructor. * @param TagPropagator $tagPropagator * @param SpanExtractor $spanExtractor * @param TracerBuilder $tracerBuilder + * @param LogCleaner $logCleaner */ public function __construct(TagPropagator $tagPropagator, SpanExtractor $spanExtractor, - TracerBuilder $tracerBuilder) { + TracerBuilder $tracerBuilder, + LogCleaner $logCleaner) { $this->tagPropagator = $tagPropagator; $this->spanExtractor = $spanExtractor; $this->tracerBuilder = $tracerBuilder; + $this->logCleaner = $logCleaner; } public function start() @@ -125,7 +133,8 @@ public function inject(array &$messageData) } public function log( array $fields ) { - $this->messageSpan->log($fields); + $this->logCleaner->setLogs($fields)->clean(); + $this->messageSpan->log($this->logCleaner->getLogs()); } private function assertHasTracer() { diff --git a/src/LogCleaner/LogCleaner.php b/src/LogCleaner/LogCleaner.php new file mode 100644 index 0000000..d7fc2af --- /dev/null +++ b/src/LogCleaner/LogCleaner.php @@ -0,0 +1,79 @@ +trimToMaxLength(); + + return $this; + } + + protected function trimToMaxLength() { + $this->trimToMaxLengthRecursive($this->logs); + } + + protected function trimToMaxLengthRecursive(&$logs) { + foreach ($logs as &$value) { + if( is_array($value) ) { + $this->trimToMaxLengthRecursive($value); + continue; + } + + if( !is_string($value) ) { + continue; + } + + $isLonger = strlen($value) > $this->maxLength; + if( !$isLonger ) + continue; + + $value = substr($value, 0, $this->maxLength); + $value .= $this->cutoffIndicator; + } + } + + public function setMaxLength( int $maxLength ): LogCleaner { + $this->maxLength = $maxLength; + return $this; + } + + public function setLogs(array $logs): LogCleaner { + $this->logs = $logs; + return $this; + } + + /** + * @param string $cutoffIndicator + * @return LogCleaner + */ + public function setCutoffIndicator( string $cutoffIndicator ): LogCleaner { + $this->cutoffIndicator = $cutoffIndicator; + return $this; + } + + /** + * @return array + */ + public function getLogs(): array { + return $this->logs; + } +} \ No newline at end of file diff --git a/src/Provider.php b/src/Provider.php index 23c7aa0..6f149bd 100644 --- a/src/Provider.php +++ b/src/Provider.php @@ -10,6 +10,7 @@ use Event; use DB; use Ipunkt\LaravelJaeger\Context\TracerBuilder\TracerBuilder; +use Ipunkt\LaravelJaeger\LogCleaner\LogCleaner; use Jaeger\Config; use Log; @@ -26,20 +27,13 @@ public function register() __DIR__.'/config/jaeger.php' => config_path('jaeger.php'), ]); - $this->app->singleton(Config::class, function() { - $config = Config::getInstance(); - $config->gen128bit(); - return $config; - }); + $this->mergeConfigFrom(__DIR__.'/config/jaeger.php', 'jaeger'); + $this->registerConfig(); - $this->app->resolving(TracerBuilder::class, function(TracerBuilder $tracerBuilder) { - $tracerBuilder - ->setName(config('app.name')) - ->setJaegerHost(config('jaeger.host')); - return $tracerBuilder; - }); + $this->registerSettingTracerBuilderConfig(); + $this->registerSettingLogCleanerConfig(); - // Setup a unique ID for each request. This will allow us to find + // Setup a unique ID for each request. This will allow us to find // the request trace in the jaeger ui $this->app->instance('context', app(EmptyContext::class) ); } @@ -128,4 +122,28 @@ private function disabledInConsole() return !config('jaeger.enable-for-console'); } + private function registerSettingTracerBuilderConfig(): void { + $this->app->resolving( TracerBuilder::class, function ( TracerBuilder $tracerBuilder ) { + $tracerBuilder + ->setName( config( 'app.name' ) ) + ->setJaegerHost( config( 'jaeger.host' ) ); + return $tracerBuilder; + } ); + } + + private function registerConfig(): void { + $this->app->singleton( Config::class, function () { + $config = Config::getInstance(); + $config->gen128bit(); + return $config; + } ); + } + + private function registerSettingLogCleanerConfig() { + $this->app->resolving(LogCleaner::class, function(LogCleaner $logCleaner) { + $logCleaner->setMaxLength( config('jaeger.log.max-string-length') ); + $logCleaner->setCutoffIndicator( config('jaeger.log.cutoff-indicator') ); + }); + } + } \ No newline at end of file diff --git a/src/config/jaeger.php b/src/config/jaeger.php index 38f013f..8081eaf 100644 --- a/src/config/jaeger.php +++ b/src/config/jaeger.php @@ -1,5 +1,9 @@ [ + 'max-string-length' => 300, + 'cutoff-indicator' => '...' + ], 'host' => env('JAEGER_AGENT_HOST', 'jaeger').':'.env('JAEGER_AGENT_PORT', 6831), diff --git a/tests/LogCleaner/LogCleanerTest.php b/tests/LogCleaner/LogCleanerTest.php new file mode 100644 index 0000000..e88ac19 --- /dev/null +++ b/tests/LogCleaner/LogCleanerTest.php @@ -0,0 +1,86 @@ +logCleaner = new LogCleaner(); + } + + /** + * @test + */ + public function reducesStringSize() { + $this->logCleaner + ->setMaxLength(10) + ->setCutoffIndicator('...') + ->setLogs([ + 'message' => '1234567890acbdefgh' + ])->clean(); + + $logs = $this->logCleaner->getLogs(); + $this->assertEquals('1234567890...', $logs['message']); + } + /** + * @test + */ + public function reducesStringSizeInSubarrays() { + $this->logCleaner + ->setMaxLength(10) + ->setCutoffIndicator('...') + ->setLogs([ + 'subarray' => [ + 'toolong' => '1234567890abcdefg' + ] + ])->clean(); + + $logs = $this->logCleaner->getLogs(); + $this->assertEquals('1234567890...', $logs['subarray']['toolong']); + } + + /** + * @test + */ + public function honorsCutoffIndicator() { + $this->logCleaner + ->setMaxLength(1) + ->setCutoffIndicator('+++') + ->setLogs([ + 'message' => '123' + ])->clean(); + + $logs = $this->logCleaner->getLogs(); + $this->assertEquals('1+++', $logs['message']); + } + + + /** + * @test + */ + public function doesNotErrorOnObjectEntries() { + $this->logCleaner + ->setMaxLength(1) + ->setCutoffIndicator('+++') + ->setLogs([ + 'object' => new \stdClass(), + 'subarray' => [ + 'anotherobject' => new \stdClass() + ], + 'message' => '123' + ])->clean(); + + $logs = $this->logCleaner->getLogs(); + $this->assertEquals('1+++', $logs['message']); + } +} \ No newline at end of file diff --git a/tests/SpanContext/SpanContextTest.php b/tests/SpanContext/SpanContextTest.php index 5538a6a..476bb9b 100644 --- a/tests/SpanContext/SpanContextTest.php +++ b/tests/SpanContext/SpanContextTest.php @@ -4,6 +4,7 @@ use Ipunkt\LaravelJaeger\Context\Exceptions\NoTracerException; use Ipunkt\LaravelJaeger\Context\SpanContext; use Ipunkt\LaravelJaeger\Context\TracerBuilder\TracerBuilder; +use Ipunkt\LaravelJaeger\LogCleaner\LogCleaner; use Ipunkt\LaravelJaeger\SpanExtractor\SpanExtractor; use Ipunkt\LaravelJaeger\TagPropagator\TagPropagator; use Ipunkt\LaravelJaegerTests\TestCase; @@ -49,12 +50,18 @@ class SpanContextTest extends TestCase { */ protected $span; + /** + * @var LogCleaner + */ + protected $logCleaner; + public function setUp(): void { parent::setUp(); $this->buildMocks(); - $this->context = new SpanContext(new TagPropagator(), new SpanExtractor(), $this->tracerBuilder); + $this->logCleaner = new LogCleaner(); + $this->context = new SpanContext(new TagPropagator(), new SpanExtractor(), $this->tracerBuilder, $this->logCleaner); } @@ -214,6 +221,22 @@ public function injectWithoutParseThrowsNoSpanException( ) { $this->context->inject($data); } + /** + * @test + */ + public function cleansLogs() { + $this->setUpContext(); + + $fields = [ + 'message' => '1234567890' + ]; + $this->logCleaner->setMaxLength(5)->setCutoffIndicator('...'); + $this->span->shouldReceive('log')->once()->with([ + 'message' => '12345...' + ]); + $this->context->log($fields); + } + private function buildMocks() { $this->spanExtractor = Mockery::mock(SpanExtractor::class); $this->spanExtractor->shouldIgnoreMissing($this->spanExtractor); @@ -251,5 +274,8 @@ private function useGenericTracer() { $this->tracerBuilder->shouldReceive('build')->andReturn($this->tracer); } + private function expectLogCleanerCalled( array $fields ) { + } + } \ No newline at end of file