diff --git a/src/Integrations/Integrations/Memcache/MemcacheIntegration.php b/src/Integrations/Integrations/Memcache/MemcacheIntegration.php index dcb4edcc677..6ac2fe1b4e0 100644 --- a/src/Integrations/Integrations/Memcache/MemcacheIntegration.php +++ b/src/Integrations/Integrations/Memcache/MemcacheIntegration.php @@ -2,6 +2,7 @@ namespace DDTrace\Integrations\Memcache; +use DDTrace\Integrations\DatabaseIntegrationHelper; use DDTrace\Integrations\Integration; use DDTrace\Obfuscation; use DDTrace\SpanData; @@ -83,6 +84,9 @@ public function init() $span->meta['memcache.cas_token'] = $args[4]; } $span->meta['memcache.query'] = 'cas ?'; + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } $integration->setServerTags($span, $this); }; @@ -105,7 +109,9 @@ public function traceCommand($command) $integration->setServerTags($span, $this); $span->meta['memcache.query'] = $command . ' ' . Obfuscation::toObfuscatedString($args[0]); } - + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } $integration->markForTraceAnalytics($span, $command); }; \DDTrace\trace_method('Memcache', $command, $trace); diff --git a/src/Integrations/Integrations/Memcached/MemcachedIntegration.php b/src/Integrations/Integrations/Memcached/MemcachedIntegration.php index f8105aed65c..5d281df364f 100644 --- a/src/Integrations/Integrations/Memcached/MemcachedIntegration.php +++ b/src/Integrations/Integrations/Memcached/MemcachedIntegration.php @@ -2,6 +2,7 @@ namespace DDTrace\Integrations\Memcached; +use DDTrace\Integrations\DatabaseIntegrationHelper; use DDTrace\Integrations\Integration; use DDTrace\Obfuscation; use DDTrace\SpanData; @@ -94,12 +95,19 @@ public function init() \DDTrace\trace_method('Memcached', 'flush', function (SpanData $span) use ($integration) { $integration->setCommonData($span, 'flush'); + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } + $integration->setServerTags($span, $this); }); \DDTrace\trace_method('Memcached', 'cas', function (SpanData $span, $args) use ($integration) { $integration->setCommonData($span, 'cas'); $span->meta['memcached.cas_token'] = $args[0]; $span->meta['memcached.query'] = 'cas ?'; + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } $integration->setServerTags($span, $this); }); @@ -108,6 +116,7 @@ public function init() $span->meta['memcached.cas_token'] = $args[0]; $span->meta['memcached.query'] = 'casByKey ?'; $span->meta['memcached.server_key'] = $args[1]; + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; $integration->setServerTags($span, $this); }); @@ -130,6 +139,9 @@ function (SpanData $span, $args, $retval) use ($integration, $command) { $integration->setServerTags($span, $this); $span->meta['memcached.query'] = $command . ' ' . Obfuscation::toObfuscatedString($args[0]); } + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } $integration->markForTraceAnalytics($span, $command); } @@ -152,6 +164,9 @@ function (SpanData $span, $args, $retval) use ($integration, $command) { $span->meta['memcached.query'] = $command . ' ' . Obfuscation::toObfuscatedString($args[0]); $span->meta['memcached.server_key'] = $args[0]; } + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } $integration->markForTraceAnalytics($span, $command); } @@ -169,10 +184,11 @@ function (SpanData $span, $args, $retval) use ($integration, $command) { if ($command === 'getMulti') { $span->metrics[Tag::DB_ROW_COUNT] = isset($retval) ? (is_array($retval) ? count($retval) : 1) : 0; } - if (!is_array($args[0])) { - $integration->setServerTags($span, $this); - } + $integration->setServerTags($span, $this); $span->meta['memcached.query'] = $command . ' ' . Obfuscation::toObfuscatedString($args[0], ','); + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } $integration->markForTraceAnalytics($span, $command); } ); @@ -193,6 +209,9 @@ function (SpanData $span, $args, $retval) use ($integration, $command) { $integration->setServerTags($span, $this); $query = "$command " . Obfuscation::toObfuscatedString($args[1], ','); $span->meta['memcached.query'] = $query; + if (\PHP_MAJOR_VERSION > 5) { + $span->peerServiceSources = DatabaseIntegrationHelper::PEER_SERVICE_SOURCES; + } $integration->markForTraceAnalytics($span, $command); } ); diff --git a/tests/Integrations/Memcache/MemcacheTest.php b/tests/Integrations/Memcache/MemcacheTest.php index a3097e547a1..c7dc30fb311 100644 --- a/tests/Integrations/Memcache/MemcacheTest.php +++ b/tests/Integrations/Memcache/MemcacheTest.php @@ -30,6 +30,13 @@ protected function ddSetUp() }); } + protected function envsToCleanUpAtTearDown() + { + return [ + 'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED', + ]; + } + public function testAdd() { $traces = $this->isolateTracer(function () { @@ -254,13 +261,60 @@ public function testCas() ]); } - private static function baseTags() + public function testCommandPeerServiceEnabled() { - return [ + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $traces = $this->isolateTracer(function () { + $this->client->add('key', 'value'); + }); + $this->assertSpans($traces, [ + SpanAssertion::build('Memcache.add', 'memcache', 'memcached', 'add') + ->setTraceAnalyticsCandidate() + ->withExactTags(array_merge(self::baseTags(true), [ + 'memcache.query' => 'add ' . Obfuscation::toObfuscatedString('key'), + 'memcache.command' => 'add', + Tag::SPAN_KIND => 'client', + ])) + ]); + } + + public function testCasPeerServiceEnabled() + { + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $this->client->set('ip_block', 'some_value'); + $flags = 0; + $result = $this->client->get('ip_block', $flags, $cas); + $traces = $this->isolateTracer(function () use ($cas) { + $this->client->cas('ip_block', 'value', 0, 0, $cas); + }); + $this->assertSpans($traces, [ + SpanAssertion::build('Memcache.cas', 'memcache', 'memcached', 'cas') + ->setTraceAnalyticsCandidate() + ->withExactTags(array_merge(self::baseTags(true), [ + 'memcache.query' => 'cas ' . Obfuscation::toObfuscatedString('key'), + 'memcache.command' => 'cas', + Tag::SPAN_KIND => 'client', + ])) + ->withExistingTagsNames(['memcache.cas_token']), + ]); + } + + private static function baseTags($expectPeerService = false) + { + $tags = [ 'out.host' => self::$host, 'out.port' => self::$port, Tag::COMPONENT => 'memcache', Tag::DB_SYSTEM => 'memcached', ]; + + if ($expectPeerService) { + $tags['peer.service'] = 'memcached_integration'; + $tags['_dd.peer.service.source'] = 'out.host'; + } + + return $tags; } } diff --git a/tests/Integrations/Memcached/MemcachedTest.php b/tests/Integrations/Memcached/MemcachedTest.php index e9cb6cb9dbd..e215cad24b2 100644 --- a/tests/Integrations/Memcached/MemcachedTest.php +++ b/tests/Integrations/Memcached/MemcachedTest.php @@ -17,7 +17,6 @@ final class MemcachedTest extends IntegrationTestCase private static $host = 'memcached_integration'; private static $port = '11211'; - protected function ddSetUp() { parent::ddSetUp(); @@ -30,6 +29,13 @@ protected function ddSetUp() }); } + protected function envsToCleanUpAtTearDown() + { + return [ + 'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED', + ]; + } + public function testAdd() { $traces = $this->isolateTracer(function () { @@ -236,13 +242,10 @@ public function testDeleteMulti() SpanAssertion::exists('Memcached.get'), SpanAssertion::exists('Memcached.get'), SpanAssertion::build('Memcached.deleteMulti', 'memcached', 'memcached', 'deleteMulti') - ->withExactTags([ + ->withExactTags(array_merge($this->baseTags(), [ 'memcached.query' => 'deleteMulti ' . Obfuscation::toObfuscatedString(['key1', 'key2'], ','), 'memcached.command' => 'deleteMulti', - Tag::SPAN_KIND => 'client', - Tag::COMPONENT => 'memcached', - Tag::DB_SYSTEM => 'memcached', - ]), + ])), SpanAssertion::exists('Memcached.get'), SpanAssertion::exists('Memcached.get'), ]); @@ -454,12 +457,9 @@ public function testFlush() SpanAssertion::exists('Memcached.add'), SpanAssertion::exists('Memcached.get'), SpanAssertion::build('Memcached.flush', 'memcached', 'memcached', 'flush') - ->withExactTags([ + ->withExactTags(array_merge($this->baseTags(), [ 'memcached.command' => 'flush', - Tag::SPAN_KIND => 'client', - Tag::COMPONENT => 'memcached', - Tag::DB_SYSTEM => 'memcached', - ]), + ])), SpanAssertion::exists('Memcached.get'), ]); } @@ -518,13 +518,10 @@ public function testGetMulti() SpanAssertion::exists('Memcached.add'), SpanAssertion::exists('Memcached.add'), SpanAssertion::build('Memcached.getMulti', 'memcached', 'memcached', 'getMulti') - ->withExactTags([ + ->withExactTags(array_merge($this->baseTags(), [ 'memcached.query' => 'getMulti ' . Obfuscation::toObfuscatedString(['key1', 'key2'], ','), 'memcached.command' => 'getMulti', - Tag::SPAN_KIND => 'client', - Tag::COMPONENT => 'memcached', - Tag::DB_SYSTEM => 'memcached', - ])->withExactMetrics([ + ]))->withExactMetrics([ Tag::DB_ROW_COUNT => 2, ]), ]); @@ -542,13 +539,10 @@ public function testGetMultiNotAllExist() SpanAssertion::exists('Memcached.add'), SpanAssertion::exists('Memcached.add'), SpanAssertion::build('Memcached.getMulti', 'memcached', 'memcached', 'getMulti') - ->withExactTags([ + ->withExactTags(array_merge($this->baseTags(), [ 'memcached.query' => 'getMulti ' . Obfuscation::toObfuscatedString(['key1', 'missing_key'], ','), 'memcached.command' => 'getMulti', - Tag::SPAN_KIND => 'client', - Tag::COMPONENT => 'memcached', - Tag::DB_SYSTEM => 'memcached', - ])->withExactMetrics([ + ]))->withExactMetrics([ Tag::DB_ROW_COUNT => 1, ]), ]); @@ -561,13 +555,10 @@ public function testGetMultiNoneExist() }); $this->assertSpans($traces, [ SpanAssertion::build('Memcached.getMulti', 'memcached', 'memcached', 'getMulti') - ->withExactTags([ + ->withExactTags(array_merge($this->baseTags(), [ 'memcached.query' => 'getMulti ' . Obfuscation::toObfuscatedString(['key1', 'key2'], ','), 'memcached.command' => 'getMulti', - Tag::SPAN_KIND => 'client', - Tag::COMPONENT => 'memcached', - Tag::DB_SYSTEM => 'memcached', - ])->withExactMetrics([ + ]))->withExactMetrics([ Tag::DB_ROW_COUNT => 0, ]), ]); @@ -703,13 +694,10 @@ public function testSetMulti() }); $this->assertSpans($traces, [ SpanAssertion::build('Memcached.setMulti', 'memcached', 'memcached', 'setMulti') - ->withExactTags([ + ->withExactTags(array_merge($this->baseTags(), [ 'memcached.query' => 'setMulti ' . Obfuscation::toObfuscatedString(['key1', 'key2'], ','), 'memcached.command' => 'setMulti', - Tag::SPAN_KIND => 'client', - Tag::COMPONENT => 'memcached', - Tag::DB_SYSTEM => 'memcached', - ]), + ])), SpanAssertion::exists('Memcached.getMulti'), ]); } @@ -833,13 +821,162 @@ public function testResultCodeIsError() }); } - private static function baseTags() + public function testCommandPeerServiceEnabled() { - return [ + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $traces = $this->isolateTracer(function () { + $this->client->add('key', 'value'); + }); + $this->assertSpans($traces, [ + SpanAssertion::build('Memcached.add', 'memcached', 'memcached', 'add') + ->setTraceAnalyticsCandidate() + ->withExactTags(array_merge(self::baseTags(true), [ + 'memcached.query' => 'add ' . Obfuscation::toObfuscatedString('key'), + 'memcached.command' => 'add', + Tag::SPAN_KIND => 'client', + ])) + ]); + } + + public function testCommandByKeyPeerServiceEnabled() + { + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $traces = $this->isolateTracer(function () { + $this->client->addByKey('my_server', 'key', 'value'); + }); + $this->assertSpans($traces, [ + SpanAssertion::build('Memcached.addByKey', 'memcached', 'memcached', 'addByKey') + ->setTraceAnalyticsCandidate() + ->withExactTags(array_merge(self::baseTags(true), [ + 'memcached.query' => 'addByKey ' . Obfuscation::toObfuscatedString('key'), + 'memcached.command' => 'addByKey', + 'memcached.server_key' => 'my_server', + Tag::SPAN_KIND => 'client', + ])) + ]); + } + + public function testMultiPeerServiceEnabled() + { + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $traces = $this->isolateTracer(function () { + $this->client->add('key1', 'value1'); + $this->client->add('key2', 'value2'); + + $this->assertEquals(['key1' => 'value1', 'key2' => 'value2'], $this->client->getMulti(['key1', 'key2'])); + }); + $this->assertSpans($traces, [ + SpanAssertion::exists('Memcached.add'), + SpanAssertion::exists('Memcached.add'), + SpanAssertion::build('Memcached.getMulti', 'memcached', 'memcached', 'getMulti') + ->withExactTags(array_merge($this->baseTags(true), [ + 'memcached.query' => 'getMulti ' . Obfuscation::toObfuscatedString(['key1', 'key2'], ','), + 'memcached.command' => 'getMulti', + ]))->withExactMetrics([ + Tag::DB_ROW_COUNT => 2, + ]), + ]); + } + + public function testMultiByKeyPeerServiceEnabled() + { + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $traces = $this->isolateTracer(function () { + $this->client->addByKey('my_server', 'key1', 'value1'); + $this->client->addByKey('my_server', 'key2', 'value2'); + + $this->assertEquals( + ['key1' => 'value1', 'key2' => 'value2'], + $this->client->getMultiByKey('my_server', ['key1', 'key2']) + ); + }); + $this->assertSpans($traces, [ + SpanAssertion::exists('Memcached.addByKey'), + SpanAssertion::exists('Memcached.addByKey'), + SpanAssertion::build('Memcached.getMultiByKey', 'memcached', 'memcached', 'getMultiByKey') + ->withExactTags(array_merge(self::baseTags(true), [ + 'memcached.query' => 'getMultiByKey ' . Obfuscation::toObfuscatedString(['key1', 'key2'], ','), + 'memcached.command' => 'getMultiByKey', + 'memcached.server_key' => 'my_server', + Tag::SPAN_KIND => 'client', + ]))->withExactMetrics([ + Tag::DB_ROW_COUNT => 2, + ]), + ]); + } + + public function testFlushPeerServiceEnabled() + { + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $traces = $this->isolateTracer(function () { + $this->client->add('key', 'value'); + + $this->assertSame('value', $this->client->get('key')); + + $this->client->flush(); + + $this->assertFalse($this->client->get('key')); + }); + $this->assertSpans($traces, [ + SpanAssertion::exists('Memcached.add'), + SpanAssertion::exists('Memcached.get'), + SpanAssertion::build('Memcached.flush', 'memcached', 'memcached', 'flush') + ->withExactTags(array_merge(self::baseTags(true), [ + 'memcached.command' => 'flush', + Tag::SPAN_KIND => 'client', + ])), + SpanAssertion::exists('Memcached.get'), + ]); + } + + + public function testCasPeerServiceEnabled() + { + $this->putEnvAndReloadConfig(['DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED=true']); + + $this->client->set('ip_block', 'some_value'); + if (\PHP_MAJOR_VERSION === 5) { + $cas = null; + $this->client->get('ip_block', null, $cas); + } else { + $result = $this->client->get('ip_block', null, \Memcached::GET_EXTENDED); + $cas = $result['cas']; + } + $traces = $this->isolateTracer(function () use ($cas) { + $this->client->cas($cas, 'key', 'value'); + }); + $this->assertSpans($traces, [ + SpanAssertion::build('Memcached.cas', 'memcached', 'memcached', 'cas') + ->setTraceAnalyticsCandidate() + ->withExactTags(array_merge(self::baseTags(true), [ + 'memcached.query' => 'cas ' . Obfuscation::toObfuscatedString('key'), + 'memcached.command' => 'cas', + Tag::SPAN_KIND => 'client', + ])) + ->withExistingTagsNames(['memcached.cas_token']), + ]); + } + + private static function baseTags($expectPeerService = false) + { + $tags = [ 'out.host' => self::$host, 'out.port' => self::$port, + Tag::SPAN_KIND => 'client', Tag::COMPONENT => 'memcached', Tag::DB_SYSTEM => 'memcached', ]; + + if ($expectPeerService) { + $tags['peer.service'] = 'memcached_integration'; + $tags['_dd.peer.service.source'] = 'out.host'; + } + + return $tags; } }