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

Defer loading of PDO, Memcached, Slim, WordPress, and Yii integrations until first usage #1006

Merged
merged 10 commits into from
Oct 13, 2020
1 change: 0 additions & 1 deletion bridge/_files.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@
__DIR__ . '/../src/DDTrace/Integrations/Laravel/LaravelIntegration.php',
__DIR__ . '/../src/DDTrace/Integrations/Lumen/LumenIntegration.php',
__DIR__ . '/../src/DDTrace/Integrations/Guzzle/GuzzleIntegration.php',
__DIR__ . '/../src/DDTrace/Integrations/Yii/V2/YiiIntegrationLoader.php',
__DIR__ . '/../src/DDTrace/Integrations/Yii/YiiIntegration.php',
__DIR__ . '/../src/DDTrace/Integrations/WordPress/WordPressIntegration.php',
__DIR__ . '/../src/DDTrace/Integrations/WordPress/V4/WordPressIntegrationLoader.php',
Expand Down
1 change: 1 addition & 0 deletions dockerfiles/ci/xfail_tests/5.5.list
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ ext/standard/tests/serialize/bug21957.phpt
ext/standard/tests/serialize/bug27469.phpt
ext/standard/tests/serialize/bug30234.phpt
ext/standard/tests/serialize/bug62836_1.phpt
ext/standard/tests/serialize/bug64146.phpt
ext/standard/tests/serialize/bug67072_2.phpt
ext/standard/tests/serialize/bug68976.phpt
ext/standard/tests/serialize/bug70219_1.phpt
Expand Down
1 change: 1 addition & 0 deletions dockerfiles/ci/xfail_tests/5.6.list
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ ext/standard/tests/serialize/bug21957.phpt
ext/standard/tests/serialize/bug27469.phpt
ext/standard/tests/serialize/bug30234.phpt
ext/standard/tests/serialize/bug62836_1.phpt
ext/standard/tests/serialize/bug64146.phpt
ext/standard/tests/serialize/bug68976.phpt
ext/standard/tests/serialize/bug69210.phpt
ext/standard/tests/serialize/bug69425.phpt
Expand Down
24 changes: 12 additions & 12 deletions src/DDTrace/Integrations/IntegrationsLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,31 @@ public function __construct(array $integrations)
'\DDTrace\Integrations\Laravel\LaravelIntegration';
$this->integrations[LumenIntegration::NAME] =
'\DDTrace\Integrations\Lumen\LumenIntegration';
$this->integrations[MemcachedIntegration::NAME] =
'\DDTrace\Integrations\Memcached\MemcachedIntegration';
$this->integrations[MongoIntegration::NAME] =
'\DDTrace\Integrations\Mongo\MongoIntegration';
$this->integrations[MysqliIntegration::NAME] =
'\DDTrace\Integrations\Mysqli\MysqliIntegration';
$this->integrations[PDOIntegration::NAME] =
'\DDTrace\Integrations\PDO\PDOIntegration';
$this->integrations[SlimIntegration::NAME] =
'\DDTrace\Integrations\Slim\SlimIntegration';
$this->integrations[SymfonyIntegration::NAME] =
'\DDTrace\Integrations\Symfony\SymfonyIntegration';
$this->integrations[WordPressIntegration::NAME] =
'\DDTrace\Integrations\WordPress\WordPressIntegration';
$this->integrations[YiiIntegration::NAME] =
'\DDTrace\Integrations\Yii\YiiIntegration';
$this->integrations[ZendFrameworkIntegration::NAME] =
'\DDTrace\Integrations\ZendFramework\ZendFrameworkIntegration';

// For PHP 7.0+ use C level deferred integration loader
if (\PHP_MAJOR_VERSION < 7) {
$this->integrations[PredisIntegration::NAME] =
'\DDTrace\Integrations\Predis\PredisIntegration';
$this->integrations[ElasticSearchIntegration::NAME] =
'\DDTrace\Integrations\ElasticSearch\V1\ElasticSearchIntegration';
$this->integrations[MemcachedIntegration::NAME] =
'\DDTrace\Integrations\Memcached\MemcachedIntegration';
$this->integrations[PDOIntegration::NAME] =
'\DDTrace\Integrations\PDO\PDOIntegration';
$this->integrations[PredisIntegration::NAME] =
'\DDTrace\Integrations\Predis\PredisIntegration';
$this->integrations[SlimIntegration::NAME] =
'\DDTrace\Integrations\Slim\SlimIntegration';
$this->integrations[YiiIntegration::NAME] =
'\DDTrace\Integrations\Yii\YiiIntegration';
$this->integrations[WordPressIntegration::NAME] =
'\DDTrace\Integrations\WordPress\WordPressIntegration';
}
}

Expand Down
21 changes: 2 additions & 19 deletions src/DDTrace/Integrations/WordPress/WordPressIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,6 @@ class WordPressIntegration extends Integration
{
const NAME = 'wordpress';

/**
* @var self
*/
private static $instance;

/**
* @return self
*/
public static function getInstance()
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}

/**
* @return string The integration name.
*/
Expand All @@ -50,10 +34,10 @@ public function init()
return self::NOT_AVAILABLE;
}

$integration = self::getInstance();
$integration = $this;

// This call happens right after WP registers an autoloader for the first time
\DDTrace\trace_method('Requests', 'set_certificate_path', function () use ($integration) {
\DDTrace\hook_method('Requests', 'set_certificate_path', null, function () use ($integration) {
if (!isset($GLOBALS['wp_version']) || !is_string($GLOBALS['wp_version'])) {
return false;
}
Expand All @@ -62,7 +46,6 @@ public function init()
$loader = new WordPressIntegrationLoader();
$loader->load($integration);
}
return false; // Drop this span to reduce noise
});

return self::LOADED;
Expand Down
120 changes: 0 additions & 120 deletions src/DDTrace/Integrations/Yii/V2/YiiIntegrationLoader.php

This file was deleted.

130 changes: 109 additions & 21 deletions src/DDTrace/Integrations/Yii/YiiIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,19 @@

namespace DDTrace\Integrations\Yii;

use DDTrace\Contracts\Scope;
use DDTrace\GlobalTracer;
use DDTrace\Integrations\Integration;
use DDTrace\SpanData;
use DDTrace\Tag;
use DDTrace\Type;
use DDTrace\Util\Versions;
use yii\helpers\Url;

class YiiIntegration extends Integration
{
const NAME = 'yii';

/**
* @var self
*/
private static $instance;

/**
* @return self
*/
public static function getInstance()
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}

/**
* @return string The integration name.
*/
Expand All @@ -50,17 +40,115 @@ public function init()
return self::NOT_AVAILABLE;
}

$integration = self::getInstance();
$integration = $this;

// This happens somewhat early in the setup, though there may be a better candidate
\DDTrace\trace_method('yii\di\Container', '__construct', function () use ($integration) {
\DDTrace\hook_method('yii\di\Container', '__construct', null, function () use ($integration) {
if (Versions::versionMatches('2.0', \Yii::getVersion())) {
$loader = new V2\YiiIntegrationLoader();
$loader->load($integration);
$integration->loadV2();
}
return false; // Drop this span to reduce noise
});

return self::LOADED;
}

public function loadV2()
{
$scope = GlobalTracer::get()->getRootScope();
if (!$scope instanceof Scope) {
return;
}
$root = $scope->getSpan();
$this->addTraceAnalyticsIfEnabledLegacy($root);
$service = \ddtrace_config_app_name(YiiIntegration::NAME);

\DDTrace\trace_method(
'yii\web\Application',
'run',
function (SpanData $span) use ($service) {
$span->name = $span->resource = \get_class($this) . '.run';
$span->type = Type::WEB_SERVLET;
$span->service = $service;
}
);

// We assume the first controller is the one to assign to app.endpoint
$firstController = null;
\DDTrace\hook_method(
'yii\web\Application',
'createController',
null,
function ($app, $appClass, $args, $retval) use (&$firstController) {
if ($firstController === null && isset($args[0], $retval) && \is_array($retval) && !empty($retval)) {
$firstController = $retval[0];
}
}
);

/* Note that Applications are Modules, so this will also trace Application::runAction, but
* modules are worth tracing independently, as multiple modules can trigger per
* application, such as in the event of an unhandled exception.
*/
\DDTrace\trace_method(
'yii\base\Module',
'runAction',
function (SpanData $span, $args) use ($service) {
$span->name = \get_class($this) . '.runAction';
$span->type = Type::WEB_SERVLET;
$span->service = $service;
$span->resource = isset($args[0]) && \is_string($args[0]) ? $args[0] : $span->name;
}
);

\DDTrace\trace_method(
'yii\base\Controller',
'runAction',
function (SpanData $span, $args) use (&$firstController, $service, $root) {
$span->name = \get_class($this) . '.runAction';
$span->type = Type::WEB_SERVLET;
$span->service = $service;
$span->resource = isset($args[0]) && \is_string($args[0]) ? $args[0] : $span->name;

if (
$firstController === $this
&& $root->getTag('app.endpoint') === null
&& isset($this->action->actionMethod)
) {
$controller = \get_class($this);
$endpoint = "{$controller}::{$this->action->actionMethod}";
$root->setTag("app.endpoint", $endpoint);
$root->setTag(Tag::HTTP_URL, Url::base(true) . Url::current());
}

if ($root->getTag('app.route.path') === null) {
$route = $this->module->requestedRoute;
$namedParams = [$route];
$placeholders = [$route];
if (isset($args[1]) && \is_array($args[1]) && !empty($args[1])) {
foreach ($args[1] as $param => $unused) {
$namedParams[$param] = ":{$param}";
$placeholders[$param] = '?';
}
}

$routePath = \urldecode(Url::toRoute($namedParams));
$root->setTag('app.route.path', $routePath);

$resourceName = \urldecode(Url::toRoute($placeholders));
$root->setTag(Tag::RESOURCE_NAME, "{$_SERVER['REQUEST_METHOD']} {$resourceName}", true);
}
}
);

\DDTrace\trace_method(
'yii\base\View',
'renderFile',
function (SpanData $span, $args) use ($service) {
$span->name = \get_class($this) . '.renderFile';
$span->type = Type::WEB_SERVLET;
$span->service = $service;
$span->resource = isset($args[0]) && \is_string($args[0]) ? $args[0] : $span->name;
}
);
}
}