Skip to content

Commit

Permalink
Sandbox eloquent integration
Browse files Browse the repository at this point in the history
  • Loading branch information
labbati committed Sep 18, 2019
1 parent 8ca3874 commit c6c3b53
Show file tree
Hide file tree
Showing 41 changed files with 834 additions and 72 deletions.
3 changes: 2 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ aliases:
name: memcached_integration

- &IMAGE_DOCKER_MYSQL
image: mysql:5.6
image: docker.pkg.github.com/datadog/dd-trace-php/mysql_integration:5.6
name: mysql_integration
<<: *DD_TRACE_CI_DOCKER_CREDENTIALS
environment:
- MYSQL_ROOT_PASSWORD=test
- MYSQL_PASSWORD=test
Expand Down
1 change: 1 addition & 0 deletions bridge/dd_require_all.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
require __DIR__ . '/../src/DDTrace/Integrations/PDO/PDOIntegration.php';
require __DIR__ . '/../src/DDTrace/Integrations/PDO/PDOSandboxedIntegration.php';
require __DIR__ . '/../src/DDTrace/Integrations/Eloquent/EloquentIntegration.php';
require __DIR__ . '/../src/DDTrace/Integrations/Eloquent/EloquentSandboxedIntegration.php';
require __DIR__ . '/../src/DDTrace/Integrations/Memcached/MemcachedIntegration.php';
require __DIR__ . '/../src/DDTrace/Integrations/Curl/CurlIntegration.php';
require __DIR__ . '/../src/DDTrace/Integrations/Mysqli/MysqliIntegration.php';
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@
"laravel-42-test": "@composer test -- tests/Integrations/Laravel/V4",

"laravel-57-update": "@composer --working-dir=tests/Frameworks/Laravel/Version_5_7 update",
"laravel-57-test": "@composer test -- tests/Integrations/Laravel/V5_7/CommonScenariosTest.php",
"laravel-57-test": "@composer test -- tests/Integrations/Laravel/V5_7",

"laravel-58-update": "@composer --working-dir=tests/Frameworks/Laravel/Version_5_8 update",
"laravel-58-test": "@composer test -- --testsuite=laravel-58-test",
Expand Down
2 changes: 1 addition & 1 deletion config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if test "$PHP_DDTRACE" != "no"; then
PHP_SUBST(EXTRA_CFLAGS)
fi

PHP_NEW_EXTENSION(ddtrace, src/ext/ddtrace.c src/ext/memory_limit.c src/ext/configuration.c src/ext/configuration_php_iface.c src/ext/circuit_breaker.c src/ext/dispatch_setup.c src/ext/dispatch.c src/ext/third-party/mt19937-64.c src/ext/random.c src/ext/coms.c src/ext/coms_curl.c src/ext/coms_debug.c src/ext/request_hooks.c src/ext/compat_zend_string.c src/ext/dispatch_compat_php5.c src/ext/dispatch_compat_php7.c src/ext/backtrace.c src/ext/logging.c src/ext/env_config.c src/ext/serializer.c src/ext/span.c src/ext/trace.c src/ext/mpack/mpack.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -Wall -std=gnu11)
PHP_NEW_EXTENSION(ddtrace, src/ext/ddtrace.c src/ext/memory_limit.c src/ext/configuration.c src/ext/configuration_php_iface.c src/ext/circuit_breaker.c src/ext/dispatch_setup.c src/ext/dispatch.c src/ext/third-party/mt19937-64.c src/ext/random.c src/ext/coms.c src/ext/coms_curl.c src/ext/coms_debug.c src/ext/request_hooks.c src/ext/compat_string.c src/ext/dispatch_compat_php5.c src/ext/dispatch_compat_php7.c src/ext/backtrace.c src/ext/logging.c src/ext/env_config.c src/ext/serializer.c src/ext/span.c src/ext/trace.c src/ext/mpack/mpack.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -Wall -std=gnu11)
PHP_ADD_BUILD_DIR($ext_builddir/src/ext, 1)

PHP_CHECK_LIBRARY(rt, shm_open, [EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lrt"])
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ services:
'fpm': { <<: *base_php_service, image: 'circleci/ruby:2.5', depends_on: [] }

mysql_integration:
image: mysql:5.6
image: docker.pkg.github.com/datadog/dd-trace-php/mysql_integration:5.6
ports:
- "3306:3306"
environment:
Expand Down
2 changes: 2 additions & 0 deletions dockerfiles/ci/Dockerfile_mysql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM mysql:5.6
COPY mysql /docker-entrypoint-initdb.d
5 changes: 5 additions & 0 deletions dockerfiles/ci/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,8 @@ services:
# build:
# <<: *build_base
# args: { VERSION: v5_4, VARIANT: asan }
mysql_integration:
image: 'docker.pkg.github.com/datadog/dd-trace-php/mysql_integration:5.6'
build:
context: ./
dockerfile: Dockerfile_mysql
9 changes: 9 additions & 0 deletions dockerfiles/ci/mysql/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
create table users (
id integer not null primary key auto_increment,
email varchar(100) not null unique,
name varchar(100),
password varchar(100),
remember_token varchar(100),
updated_at timestamp,
created_at timestamp
);
4 changes: 2 additions & 2 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
<dir name="ext">
<file name="backtrace.c" role="src" />
<file name="backtrace.h" role="src" />
<file name="compat_zend_string.c" role="src" />
<file name="compat_zend_string.h" role="src" />
<file name="compat_string.c" role="src" />
<file name="compat_string.h" role="src" />
<file name="configuration.h" role="src" />
<file name="configuration.c" role="src" />
<file name="configuration_render.h" role="src" />
Expand Down
68 changes: 68 additions & 0 deletions src/DDTrace/Integrations/Eloquent/EloquentSandboxedIntegration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace DDTrace\Integrations\Eloquent;

use DDTrace\Integrations\Integration;
use DDTrace\Integrations\SandboxedIntegration;
use DDTrace\SpanData;
use DDTrace\Tag;
use DDTrace\Type;

class EloquentSandboxedIntegration extends SandboxedIntegration
{
const NAME = 'eloquent';

/**
* @return string The integration name.
*/
public function getName()
{
return self::NAME;
}

/**
* Add instrumentation to PDO requests
*/
public function init()
{
dd_trace_method('Illuminate\Database\Eloquent\Builder', 'getModels', function (SpanData $span, array $args) {
$span->name = 'eloquent.get';
$sql = $this->getQuery()->toSql();
$span->type = Type::SQL;
$span->resource = $sql;
$span->meta[Tag::DB_STATEMENT] = $sql;
});

dd_trace_method('Illuminate\Database\Eloquent\Model', 'performInsert', function (SpanData $span, array $args) {
$span->name = 'eloquent.insert';
$span->type = Type::SQL;
$span->resource = get_class($this);
});

dd_trace_method('Illuminate\Database\Eloquent\Model', 'performUpdate', function (SpanData $span, array $args) {
$span->name = 'eloquent.update';
$span->type = Type::SQL;
$span->resource = get_class($this);
});

dd_trace_method('Illuminate\Database\Eloquent\Model', 'delete', function (SpanData $span, array $args) {
$span->name = 'eloquent.delete';
$span->type = Type::SQL;
$span->resource = get_class($this);
});

dd_trace_method('Illuminate\Database\Eloquent\Model', 'destroy', function (SpanData $span) {
$span->name = 'eloquent.destroy';
$span->type = Type::SQL;
$span->resource = get_called_class();
});

dd_trace_method('Illuminate\Database\Eloquent\Model', 'refresh', function (SpanData $span) {
$span->name = 'eloquent.refresh';
$span->type = Type::SQL;
$span->resource = get_class($this);
});

return Integration::LOADED;
}
}
1 change: 0 additions & 1 deletion src/DDTrace/Integrations/Integration.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ abstract class Integration
*/
abstract public function getName();


public function __construct()
{
$this->configuration = $this->buildConfiguration();
Expand Down
6 changes: 5 additions & 1 deletion src/DDTrace/Integrations/IntegrationsLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use DDTrace\Integrations\Curl\CurlIntegration;
use DDTrace\Integrations\ElasticSearch\V1\ElasticSearchIntegration;
use DDTrace\Integrations\Eloquent\EloquentIntegration;
use DDTrace\Integrations\Eloquent\EloquentSandboxedIntegration;
use DDTrace\Integrations\Guzzle\GuzzleIntegration;
use DDTrace\Integrations\Laravel\LaravelIntegration;
use DDTrace\Integrations\Lumen\LumenIntegration;
Expand Down Expand Up @@ -74,7 +75,10 @@ public function __construct(array $integrations)
$this->integrations = $integrations;
// Sandboxed integrations get loaded with a feature flag
if (Configuration::get()->isSandboxEnabled()) {
$this->integrations[PDOSandboxedIntegration::NAME] = '\DDTrace\Integrations\PDO\PDOSandboxedIntegration';
$this->integrations[EloquentSandboxedIntegration::NAME] =
'\DDTrace\Integrations\Eloquent\EloquentSandboxedIntegration';
$this->integrations[PDOSandboxedIntegration::NAME] =
'\DDTrace\Integrations\PDO\PDOSandboxedIntegration';
}
}

Expand Down
182 changes: 182 additions & 0 deletions src/ext/compat_string.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#include "compat_string.h"

#include <Zend/zend_API.h>
#include <php.h>
#include <php_version.h>

#if PHP_VERSION_ID < 70000
int ddtrace_spprintf(char **message, size_t max_len, char *format, ...) {
va_list arg;
int len;

va_start(arg, format);
len = vspprintf(message, max_len, format, arg);
va_end(arg);
return len;
}
#else
size_t ddtrace_spprintf(char **message, size_t max_len, char *format, ...) {
va_list arg;
size_t len;

va_start(arg, format);
len = vspprintf(message, max_len, format, arg);
va_end(arg);
return len;
}
#endif

#if PHP_VERSION_ID < 70000
void ddtrace_downcase_zval(zval *src) {
if (!src || Z_TYPE_P(src) != IS_STRING) {
return;
}

zend_str_tolower(Z_STRVAL_P(src), Z_STRLEN_P(src));
}

#else
void ddtrace_downcase_zval(zval *src) {
if (!src || Z_TYPE_P(src) != IS_STRING) {
return;
}
zend_string *str = Z_STR_P(src);

ZVAL_STR(src, zend_string_tolower(str));
zend_string_release(str);
}
#endif

#if PHP_VERSION_ID < 70000
void ddtrace_try_get_string(zval *dst, zval *src ZEND_FILE_LINE_DC TSRMLS_DC) {
switch (Z_TYPE_P(src)) {
case IS_BOOL:
if (Z_LVAL_P(src)) {
Z_STRVAL_P(src) = estrndup_rel("1", 1);
Z_STRLEN_P(src) = 1;
break;
}
/* fall through */

case IS_NULL:
Z_STRVAL_P(dst) = STR_EMPTY_ALLOC();
Z_STRLEN_P(dst) = 0;
break;

case IS_RESOURCE:
Z_STRLEN_P(dst) = ddtrace_spprintf(&Z_STRVAL_P(dst), 0, "Resource id #%ld", Z_LVAL_P(src));
break;

case IS_LONG:
Z_STRLEN_P(dst) = ddtrace_spprintf(&Z_STRVAL_P(dst), 0, "%ld", Z_LVAL_P(src));
break;

case IS_DOUBLE:
Z_STRLEN_P(dst) = ddtrace_spprintf(&Z_STRVAL_P(dst), 0, "%.*G", (int)EG(precision), Z_DVAL_P(src));
break;

case IS_ARRAY:
Z_STRVAL_P(dst) = estrndup_rel("Array", sizeof("Array") - 1);
Z_STRLEN_P(dst) = sizeof("Array") - 1;
break;

case IS_OBJECT: {
if (Z_OBJ_HANDLER_P(src, cast_object)) {
if (Z_OBJ_HANDLER_P(src, cast_object)(src, dst, IS_STRING TSRMLS_CC) == SUCCESS) {
return;
}
} else if (Z_OBJ_HANDLER_P(src, get)) {
zval *newop = Z_OBJ_HANDLER_P(src, get)(src TSRMLS_CC);
if (Z_TYPE_P(newop) != IS_OBJECT) {
/* for safety - avoid loop */
ddtrace_try_get_string(dst, newop ZEND_FILE_LINE_CC TSRMLS_CC);

// I think?
zval_dtor(newop);
return;
}
}
ZVAL_NULL(dst);
return;
}

case IS_CONSTANT:
case IS_STRING:
ZVAL_COPY_VALUE(dst, src);
_zval_copy_ctor_func(dst ZEND_FILE_LINE_CC);
return;

EMPTY_SWITCH_DEFAULT_CASE()
}
Z_TYPE_P(src) = IS_STRING;
}

#else
static zend_string *_try_get_string(zval *op) {
try_again:
switch (Z_TYPE_P(op)) {
case IS_UNDEF:
case IS_NULL:
case IS_FALSE:
return ZSTR_EMPTY_ALLOC();

case IS_TRUE:
#if PHP_VERSION_ID < 70200
return CG(one_char_string)['1'] ? CG(one_char_string)['1'] : zend_string_init("1", 1, 0);
#else
return ZSTR_CHAR('1');
#endif

case IS_RESOURCE:
return strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));

case IS_LONG:
return zend_long_to_str(Z_LVAL_P(op));

case IS_DOUBLE:
return strpprintf(0, "%.*G", (int)EG(precision), Z_DVAL_P(op));

case IS_ARRAY:
#if PHP_VERSION_ID < 70400
return zend_string_init("Array", sizeof("Array") - 1, 0);
#else
return ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
#endif

case IS_OBJECT: {
zval tmp;
if (Z_OBJ_HT_P(op)->cast_object) {
if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
return Z_STR(tmp);
}
} else if (Z_OBJ_HT_P(op)->get) {
zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
if (Z_TYPE_P(z) != IS_OBJECT) {
zend_string *str = _try_get_string(z);
zval_ptr_dtor(z);
return str;
}
}
return NULL;
}

case IS_REFERENCE:
op = Z_REFVAL_P(op);
goto try_again;

case IS_STRING:
return zend_string_copy(Z_STR_P(op));

EMPTY_SWITCH_DEFAULT_CASE()
}
}

void ddtrace_try_get_string(zval *dst, zval *src) {
zend_string *str = _try_get_string(src);
if (str) {
ZVAL_STR(dst, str);
} else {
ZVAL_NULL(dst);
}
}
#endif
25 changes: 25 additions & 0 deletions src/ext/compat_string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef COMPAT_STRING_H
#define COMPAT_STRING_H
#include <Zend/zend.h>
#include <Zend/zend_types.h>
#include <php_version.h>

#include "compatibility.h"

void ddtrace_downcase_zval(zval *src);

// ddtrace_spprintf is a replacement for zend_spprintf, since it is not exported in many versions
#if PHP_VERSION_ID < 70000
int ddtrace_spprintf(char **message, size_t max_len, char *format, ...);
#else
size_t ddtrace_spprintf(char **message, size_t max_len, char *format, ...);
#endif

/* dst will either be IS_STRING or IS_NULL; caller must dtor */
#if PHP_VERSION_ID < 70000
void ddtrace_try_get_string(zval *dst, zval *src ZEND_FILE_LINE_DC TSRMLS_DC);
#else
void ddtrace_try_get_string(zval *dst, zval *src);
#endif

#endif // COMPAT_STRING_H

0 comments on commit c6c3b53

Please sign in to comment.