From 1acecf10ad99d6817345ab0672f988548c641248 Mon Sep 17 00:00:00 2001
From: AA2512 <58102909+AA2512@users.noreply.github.com>
Date: Fri, 3 May 2024 05:31:12 +0530
Subject: [PATCH] Feature/auto instrumentation/cake php (#253)
---
.gitattributes | 13 ++++++
.gitignore | 1 +
.php-cs-fixer.php | 43 ++++++++++++++++++
README.md | 18 ++++++++
_register.php | 18 ++++++++
composer.json | 50 +++++++++++++++++++++
phpstan.neon.dist | 11 +++++
phpunit.xml.dist | 47 +++++++++++++++++++
psalm.xml.dist | 15 +++++++
src/CakePHPInstrumentation.php | 82 ++++++++++++++++++++++++++++++++++
tests/Integration/.gitkeep | 0
tests/Unit/.gitkeep | 0
12 files changed, 298 insertions(+)
create mode 100644 .gitattributes
create mode 100644 .gitignore
create mode 100644 .php-cs-fixer.php
create mode 100644 README.md
create mode 100644 _register.php
create mode 100644 composer.json
create mode 100644 phpstan.neon.dist
create mode 100644 phpunit.xml.dist
create mode 100644 psalm.xml.dist
create mode 100644 src/CakePHPInstrumentation.php
create mode 100644 tests/Integration/.gitkeep
create mode 100644 tests/Unit/.gitkeep
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..ac40e9f
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,13 @@
+* text=auto
+
+*.md diff=markdown
+*.php diff=php
+
+/.gitattributes export-ignore
+/.gitignore export-ignore
+/.phan export-ignore
+/.php-cs-fixer.php export-ignore
+/phpstan.neon.dist export-ignore
+/phpunit.xml.dist export-ignore
+/psalm.xml.dist export-ignore
+/tests export-ignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..57872d0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/vendor/
diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
new file mode 100644
index 0000000..248b4b9
--- /dev/null
+++ b/.php-cs-fixer.php
@@ -0,0 +1,43 @@
+exclude('vendor')
+ ->exclude('var/cache')
+ ->in(__DIR__);
+
+$config = new PhpCsFixer\Config();
+return $config->setRules([
+ 'concat_space' => ['spacing' => 'one'],
+ 'declare_equal_normalize' => ['space' => 'none'],
+ 'is_null' => true,
+ 'modernize_types_casting' => true,
+ 'ordered_imports' => true,
+ 'php_unit_construct' => true,
+ 'single_line_comment_style' => true,
+ 'yoda_style' => false,
+ '@PSR2' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'blank_line_after_opening_tag' => true,
+ 'blank_line_before_statement' => true,
+ 'cast_spaces' => true,
+ 'declare_strict_types' => true,
+ 'function_typehint_space' => true,
+ 'include' => true,
+ 'lowercase_cast' => true,
+ 'new_with_braces' => true,
+ 'no_extra_blank_lines' => true,
+ 'no_leading_import_slash' => true,
+ 'echo_tag_syntax' => true,
+ 'no_unused_imports' => true,
+ 'no_useless_else' => true,
+ 'no_useless_return' => true,
+ 'phpdoc_order' => true,
+ 'phpdoc_scalar' => true,
+ 'phpdoc_types' => true,
+ 'short_scalar_cast' => true,
+ 'single_blank_line_before_namespace' => true,
+ 'single_quote' => true,
+ 'trailing_comma_in_multiline' => true,
+ ])
+ ->setRiskyAllowed(true)
+ ->setFinder($finder);
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3b08b02
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+
+This is a read-only subtree split of https://github.com/open-telemetry/opentelemetry-php-contrib.
+
+# OpenTelemetry Slim Framework auto-instrumentation
+Please read https://opentelemetry.io/docs/instrumentation/php/automatic/ for instructions on how to
+install and configure the extension and SDK.
+
+## Overview
+Auto-instrumentation hooks are registered via composer, and spans will automatically be created for:
+- `::handle()` - root span
+
+## Configuration
+
+The extension can be disabled via [runtime configuration](https://opentelemetry.io/docs/instrumentation/php/sdk/#configuration):
+
+```shell
+OTEL_PHP_DISABLED_INSTRUMENTATIONS=cakephp
+```
diff --git a/_register.php b/_register.php
new file mode 100644
index 0000000..2f46d14
--- /dev/null
+++ b/_register.php
@@ -0,0 +1,18 @@
+=4.0",
+ "open-telemetry/api": "^1.0",
+ "open-telemetry/sem-conv": "^1.23"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3",
+ "mockery/mockery": "^1.5",
+ "nyholm/psr7": "*",
+ "phan/phan": "^5.0",
+ "php-http/mock-client": "*",
+ "phpstan/phpstan-mockery": "^1.1.0",
+ "phpstan/phpstan": "^1.1",
+ "phpstan/phpstan-phpunit": "^1.0",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "open-telemetry/sdk": "^1.0",
+ "phpunit/phpunit": "^9.5",
+ "vimeo/psalm": "^5.24"
+ },
+ "autoload": {
+ "psr-4": {
+ "OpenTelemetry\\Contrib\\Instrumentation\\CakePHP\\": "src/"
+ },
+ "files": [
+ "_register.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "OpenTelemetry\\Tests\\Instrumentation\\CakePHP\\": "tests/"
+ }
+ },
+ "config": {
+ "allow-plugins": {
+ "php-http/discovery": true
+ }
+ }
+}
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..4033c4d
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,11 @@
+includes:
+ - vendor/phpstan/phpstan-phpunit/extension.neon
+
+parameters:
+ tmpDir: var/cache/phpstan
+ level: 5
+ paths:
+ - src
+ - tests
+ excludePaths:
+ - tests/*
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..d854885
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ src
+
+
+
+
+
+
+
+
+
+
+
+
+ tests/Unit
+
+
+ tests/Integration
+
+
+
+
diff --git a/psalm.xml.dist b/psalm.xml.dist
new file mode 100644
index 0000000..1557117
--- /dev/null
+++ b/psalm.xml.dist
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/CakePHPInstrumentation.php b/src/CakePHPInstrumentation.php
new file mode 100644
index 0000000..bd71d8f
--- /dev/null
+++ b/src/CakePHPInstrumentation.php
@@ -0,0 +1,82 @@
+getRequest();
+ /** @psalm-suppress ArgumentTypeCoercion */
+ $builder = $instrumentation->tracer()
+ ->spanBuilder($request->getMethod())
+ ->setSpanKind(SpanKind::KIND_SERVER)
+ ->setAttribute(TraceAttributes::CODE_FUNCTION, $function)
+ ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
+ ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
+ ->setAttribute(TraceAttributes::CODE_LINENO, $lineno);
+
+ $parent = Globals::propagator()->extract($request->getHeaders());
+ $span = $builder
+ ->setParent($parent)
+ ->setAttribute(TraceAttributes::URL_FULL, $request->getUri()->__toString())
+ ->setAttribute(TraceAttributes::HTTP_REQUEST_METHOD, $request->getMethod())
+ ->setAttribute(TraceAttributes::HTTP_REQUEST_BODY_SIZE, $request->getHeaderLine('Content-Length'))
+ ->setAttribute(TraceAttributes::USER_AGENT_ORIGINAL, $request->getHeaderLine('User-Agent'))
+ ->setAttribute(TraceAttributes::SERVER_ADDRESS, $request->getUri()->getHost())
+ ->setAttribute(TraceAttributes::SERVER_PORT, $request->getUri()->getPort())
+ ->setAttribute(TraceAttributes::URL_SCHEME, $request->getUri()->getScheme())
+ ->setAttribute(TraceAttributes::URL_PATH, $request->getUri()->getPath())
+ ->startSpan();
+
+ Context::storage()->attach($span->storeInContext($parent));
+ },
+ post: static function (Controller $app, array $params, ?ResponseInterface $response, ?Throwable $exception) {
+ $scope = Context::storage()->scope();
+ if (!$scope) {
+ return;
+ }
+ $scope->detach();
+ $span = Span::fromContext($scope->context());
+ $response = $app->getResponse();
+ if ($exception) {
+ $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]);
+ $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage());
+ }
+ /** @var ResponseInterface|null $response */
+ if ($response) {
+ if ($response->getStatusCode() >= 400) {
+ $span->setStatus(StatusCode::STATUS_ERROR);
+ }
+ $span->setAttribute(TraceAttributes::HTTP_RESPONSE_STATUS_CODE, $response->getStatusCode());
+ $span->setAttribute(TraceAttributes::NETWORK_PROTOCOL_VERSION, $response->getProtocolVersion());
+ $span->setAttribute(TraceAttributes::HTTP_RESPONSE_BODY_SIZE, $response->getHeaderLine('Content-Length') ?: null);
+ }
+
+ $span->end();
+ },
+ );
+ }
+}
diff --git a/tests/Integration/.gitkeep b/tests/Integration/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/Unit/.gitkeep b/tests/Unit/.gitkeep
new file mode 100644
index 0000000..e69de29