diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index dffd46f91..ab56e2006 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: ['7.4', '8.0', '8.1', '8.2', '8.3'] + php-version: ['8.0', '8.1', '8.2', '8.3'] # Sorted alphabetically to ease finding the desired run in the GitHub Workflow UI. project: [ 'Aws', @@ -55,34 +55,6 @@ jobs: 'Symfony', ] exclude: - - project: 'Instrumentation/Guzzle' - php-version: 7.4 - - project: 'Instrumentation/HttpAsyncClient' - php-version: 7.4 - - project: 'Instrumentation/Slim' - php-version: 7.4 - - project: 'Instrumentation/Psr3' - php-version: 7.4 - - project: 'Instrumentation/Psr6' - php-version: 7.4 - - project: 'Instrumentation/Psr14' - php-version: 7.4 - - project: 'Instrumentation/Psr15' - php-version: 7.4 - - project: 'Instrumentation/Psr16' - php-version: 7.4 - - project: 'Instrumentation/Psr18' - php-version: 7.4 - - project: 'Instrumentation/IO' - php-version: 7.4 - - project: 'Instrumentation/Symfony' - php-version: 7.4 - - project: 'Instrumentation/Laravel' - php-version: 7.4 - - project: 'Instrumentation/CodeIgniter' - php-version: 7.4 - - project: 'Instrumentation/Yii' - php-version: 7.4 - project: 'Instrumentation/IO' php-version: 8.0 - project: 'Instrumentation/IO' @@ -99,14 +71,12 @@ jobs: php-version: 8.0 - project: 'Instrumentation/MySqli' php-version: 8.1 - - project: 'Instrumentation/PDO' - php-version: 7.4 - project: 'Instrumentation/PDO' php-version: 8.0 - project: 'Instrumentation/PDO' php-version: 8.1 - - project: 'Instrumentation/ExtAmqp' - php-version: 7.4 + - project: 'Instrumentation/Psr3' + php-version: 8.0 - project: 'Instrumentation/ExtAmqp' php-version: 8.0 - project: 'Instrumentation/ExtAmqp' @@ -117,22 +87,12 @@ jobs: php-version: 8.0 - project: 'Instrumentation/ExtRdKafka' php-version: 8.1 - - project: 'Instrumentation/OpenAIPHP' - php-version: 7.4 - project: 'Instrumentation/OpenAIPHP' php-version: 8.0 - - project: 'Instrumentation/CakePHP' - php-version: 7.4 - - project: 'Propagation/ServerTiming' - php-version: 7.4 - - project: 'ResourceDetectors/Container' - php-version: 7.4 - - project: 'Sampler/RuleBased' - php-version: 7.4 + - project: 'Logs/Monolog' + php-version: 8.0 - project: 'Sampler/RuleBased' php-version: 8.0 - - project: 'Symfony' - php-version: 7.4 - project: 'Symfony' php-version: 8.0 steps: diff --git a/Makefile b/Makefile index 33e0c6e65..de4792958 100644 --- a/Makefile +++ b/Makefile @@ -19,9 +19,9 @@ build: ## Build image install: ## Install dependencies $(DC_RUN_PHP) env XDEBUG_MODE=off composer install update: ## Update dependencies - $(DC_RUN_PHP) env XDEBUG_MODE=off composer update + $(DC_RUN_PHP) env XDEBUG_MODE=off composer update --no-plugins update-lowest: ## Update dependencies to lowest supported versions - $(DC_RUN_PHP) env XDEBUG_MODE=off composer update --prefer-lowest + $(DC_RUN_PHP) env XDEBUG_MODE=off composer update --no-plugins --prefer-lowest test: ## Run all tests $(DC_RUN_PHP) env XDEBUG_MODE=off vendor/bin/phpunit --testdox --colors=always test-unit: ## Run unit tests @@ -39,7 +39,7 @@ psalm-info: ## Run psalm with info phpstan: ## Run phpstan $(DC_RUN_PHP) env XDEBUG_MODE=off vendor/bin/phpstan analyse --memory-limit=256M validate: ## Validate composer file - $(DC_RUN_PHP) env XDEBUG_MODE=off composer validate + $(DC_RUN_PHP) env XDEBUG_MODE=off composer validate --no-plugins packages-composer: ## Validate all composer packages $(DC_RUN) php env XDEBUG_MODE=off vendor/bin/otel packages:composer:validate bash: ## Bash shell diff --git a/src/Instrumentation/CakePHP/composer.json b/src/Instrumentation/CakePHP/composer.json index 5debc7a5f..e559c368c 100644 --- a/src/Instrumentation/CakePHP/composer.json +++ b/src/Instrumentation/CakePHP/composer.json @@ -13,7 +13,7 @@ "ext-opentelemetry": "*", "cakephp/cakephp": "^4 || ^5", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", diff --git a/src/Instrumentation/CakePHP/src/CakePHPInstrumentation.php b/src/Instrumentation/CakePHP/src/CakePHPInstrumentation.php index 9ad4c68c2..6442723f5 100644 --- a/src/Instrumentation/CakePHP/src/CakePHPInstrumentation.php +++ b/src/Instrumentation/CakePHP/src/CakePHPInstrumentation.php @@ -18,7 +18,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.cakephp', null, - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0', ); Server::hook($instrumentation); Controller::hook($instrumentation); diff --git a/src/Instrumentation/CakePHP/src/Hooks/Cake/Command/Command.php b/src/Instrumentation/CakePHP/src/Hooks/Cake/Command/Command.php index 9838963b1..138cf84eb 100644 --- a/src/Instrumentation/CakePHP/src/Hooks/Cake/Command/Command.php +++ b/src/Instrumentation/CakePHP/src/Hooks/Cake/Command/Command.php @@ -26,10 +26,10 @@ public function instrument(): void $builder = $this->instrumentation ->tracer() ->spanBuilder(sprintf('Command %s', $command->getName() ?: 'unknown')) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); $span = $builder->startSpan(); @@ -52,9 +52,7 @@ public function instrument(): void $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/CakePHP/src/Hooks/Cake/Controller/Controller.php b/src/Instrumentation/CakePHP/src/Hooks/Cake/Controller/Controller.php index 090f53f40..e41acd06d 100644 --- a/src/Instrumentation/CakePHP/src/Hooks/Cake/Controller/Controller.php +++ b/src/Instrumentation/CakePHP/src/Hooks/Cake/Controller/Controller.php @@ -35,7 +35,7 @@ public function instrument(): void $scope->detach(); $span = \OpenTelemetry\API\Trace\Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } $response = $app->getResponse(); diff --git a/src/Instrumentation/CakePHP/src/Hooks/Cake/Http/Server.php b/src/Instrumentation/CakePHP/src/Hooks/Cake/Http/Server.php index c7f05ad87..a90fd38c5 100644 --- a/src/Instrumentation/CakePHP/src/Hooks/Cake/Http/Server.php +++ b/src/Instrumentation/CakePHP/src/Hooks/Cake/Http/Server.php @@ -49,7 +49,7 @@ public function instrument(): void $span->setAttribute(TraceAttributes::HTTP_ROUTE, $route); } if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } if ($response) { diff --git a/src/Instrumentation/CakePHP/src/Hooks/CakeHookTrait.php b/src/Instrumentation/CakePHP/src/Hooks/CakeHookTrait.php index 110efc6f4..cbbb9eb44 100644 --- a/src/Instrumentation/CakePHP/src/Hooks/CakeHookTrait.php +++ b/src/Instrumentation/CakePHP/src/Hooks/CakeHookTrait.php @@ -57,10 +57,10 @@ protected function buildSpan(?ServerRequestInterface $request, string $class, st : sprintf('%s', $request?->getMethod() ?? 'unknown') ) ->setSpanKind(SpanKind::KIND_SERVER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); if (!$root && $request) { $this->isRoot = true; diff --git a/src/Instrumentation/CakePHP/tests/Integration/CakePHPInstrumentationTest.php b/src/Instrumentation/CakePHP/tests/Integration/CakePHPInstrumentationTest.php index bf7468eeb..c64f39fb8 100644 --- a/src/Instrumentation/CakePHP/tests/Integration/CakePHPInstrumentationTest.php +++ b/src/Instrumentation/CakePHP/tests/Integration/CakePHPInstrumentationTest.php @@ -45,7 +45,7 @@ public function test_index(): void $this->assertSame(SpanKind::KIND_SERVER, $serverSpan->getKind()); $this->assertGreaterThan(0, $serverSpan->getAttributes()->count()); $attributes = $serverSpan->getAttributes()->toArray(); - $this->assertSame('run', $attributes['code.function']); + $this->assertSame('run', $attributes['code.function.name']); $this->assertSame('GET', $attributes['http.request.method']); $this->assertSame(200, $attributes['http.response.status_code']); $this->assertSame(self::TRACE_ID, $serverSpan->getParentContext()->getTraceId()); @@ -58,7 +58,7 @@ public function test_index(): void $this->assertSame(SpanKind::KIND_INTERNAL, $controllerSpan->getKind()); $this->assertGreaterThan(0, $controllerSpan->getAttributes()->count()); $attributes = $controllerSpan->getAttributes()->toArray(); - $this->assertSame('invokeAction', $attributes['code.function']); + $this->assertSame('invokeAction', $attributes['code.function.name']); $this->assertSame($serverSpan->getTraceId(), $controllerSpan->getParentContext()->getTraceId()); $this->assertSame($serverSpan->getSpanId(), $controllerSpan->getParentContext()->getSpanId()); } diff --git a/src/Instrumentation/CakePHP/tests/Integration/CommandTest.php b/src/Instrumentation/CakePHP/tests/Integration/CommandTest.php index 8473058ea..a1f77f186 100644 --- a/src/Instrumentation/CakePHP/tests/Integration/CommandTest.php +++ b/src/Instrumentation/CakePHP/tests/Integration/CommandTest.php @@ -12,6 +12,9 @@ class CommandTest extends TestCase public function test_command_tracing(): void { + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped(); + } $this->assertCount(0, $this->storage); $this->exec('dummy'); diff --git a/src/Instrumentation/CodeIgniter/composer.json b/src/Instrumentation/CodeIgniter/composer.json index 2e8664707..8053360b6 100644 --- a/src/Instrumentation/CodeIgniter/composer.json +++ b/src/Instrumentation/CodeIgniter/composer.json @@ -13,7 +13,7 @@ "ext-opentelemetry": "*", "codeigniter4/framework": "^4.3", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.50", diff --git a/src/Instrumentation/CodeIgniter/src/CodeIgniterInstrumentation.php b/src/Instrumentation/CodeIgniter/src/CodeIgniterInstrumentation.php index ba8c183d0..9345190e1 100644 --- a/src/Instrumentation/CodeIgniter/src/CodeIgniterInstrumentation.php +++ b/src/Instrumentation/CodeIgniter/src/CodeIgniterInstrumentation.php @@ -26,7 +26,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.codeigniter', null, - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0', ); // The method that creates request/response/controller objects is in the same class as the method @@ -60,10 +60,10 @@ public static function register(): void /** @phan-suppress-next-line PhanDeprecatedFunction */ ->spanBuilder(\sprintf('%s', $request?->getMethod() ?? 'unknown')) ->setSpanKind(SpanKind::KIND_SERVER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); @@ -146,7 +146,7 @@ public static function register(): void } if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/CodeIgniter/tests/Integration/CodeIgniterInstrumentationTest.php b/src/Instrumentation/CodeIgniter/tests/Integration/CodeIgniterInstrumentationTest.php index 9b6692036..5512397f8 100644 --- a/src/Instrumentation/CodeIgniter/tests/Integration/CodeIgniterInstrumentationTest.php +++ b/src/Instrumentation/CodeIgniter/tests/Integration/CodeIgniterInstrumentationTest.php @@ -76,6 +76,5 @@ public function test_exception() $this->assertEquals('Exception', $eventAttributes->get('exception.type')); $this->assertEquals('Threw', $eventAttributes->get('exception.message')); $this->assertNotNull($eventAttributes->get('exception.stacktrace')); - $this->assertTrue($eventAttributes->get('exception.escaped')); } } diff --git a/src/Instrumentation/Curl/.phan/config.php b/src/Instrumentation/Curl/.phan/config.php new file mode 100644 index 000000000..6bf6f35c4 --- /dev/null +++ b/src/Instrumentation/Curl/.phan/config.php @@ -0,0 +1,371 @@ + '8.2', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/Curl/composer.json b/src/Instrumentation/Curl/composer.json index 3021c7543..441f9f794 100644 --- a/src/Instrumentation/Curl/composer.json +++ b/src/Instrumentation/Curl/composer.json @@ -20,7 +20,7 @@ "ext-curl": "*", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", diff --git a/src/Instrumentation/Curl/phpstan.neon.dist b/src/Instrumentation/Curl/phpstan.neon.dist index ed94c13da..3ecab5902 100644 --- a/src/Instrumentation/Curl/phpstan.neon.dist +++ b/src/Instrumentation/Curl/phpstan.neon.dist @@ -7,3 +7,8 @@ parameters: paths: - src - tests + ignoreErrors: + - + message: "#Right side of .* is always false.#" + paths: + - src/CurlInstrumentation.php diff --git a/src/Instrumentation/Curl/psalm.xml.dist b/src/Instrumentation/Curl/psalm.xml.dist index 5a04b34d7..1a83afc1a 100644 --- a/src/Instrumentation/Curl/psalm.xml.dist +++ b/src/Instrumentation/Curl/psalm.xml.dist @@ -14,4 +14,11 @@ + + + + + + + diff --git a/src/Instrumentation/Curl/src/CurlInstrumentation.php b/src/Instrumentation/Curl/src/CurlInstrumentation.php index 27bef1272..f18475355 100644 --- a/src/Instrumentation/Curl/src/CurlInstrumentation.php +++ b/src/Instrumentation/Curl/src/CurlInstrumentation.php @@ -16,6 +16,7 @@ use function OpenTelemetry\Instrumentation\hook; use OpenTelemetry\SDK\Common\Configuration\Configuration; use OpenTelemetry\SemConv\TraceAttributes; +use OpenTelemetry\SemConv\Version; use WeakMap; use WeakReference; @@ -28,7 +29,7 @@ public static function register(): void /** @var WeakMap */ $curlHandleToAttributes = new WeakMap(); - /** @var WeakMap > + /** @var WeakMap $curlMultiToHandle * * curlMultiToHandle -> array('started'=>bool, * 'handles'=> @@ -40,13 +41,12 @@ public static function register(): void */ $curlMultiToHandle = new WeakMap(); - /** @var bool */ $curlSetOptInstrumentationSuppressed = false; $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.curl', null, - 'https://opentelemetry.io/schemas/1.24.0' + Version::VERSION_1_30_0->url(), ); hook( @@ -149,9 +149,9 @@ public static function register(): void ->spanBuilder($spanName) ->setParent($parent) ->setSpanKind(SpanKind::KIND_CLIENT) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttributes($curlHandleToAttributes[$params[0]]->getAttributes()); $span = $builder->startSpan(); @@ -283,7 +283,7 @@ public static function register(): void ->spanBuilder($spanName) ->setParent($parent) ->setSpanKind(SpanKind::KIND_CLIENT) - ->setAttribute(TraceAttributes::CODE_FUNCTION, 'curl_multi_exec') + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, 'curl_multi_exec') ->setAttributes($curlHandleToAttributes[$cHandle]->getAttributes()); $span = $builder->startSpan(); @@ -417,7 +417,7 @@ private static function setAttributesFromCurlGetInfo(CurlHandle $handle, SpanInt $span->setAttribute(TraceAttributes::HTTP_RESPONSE_STATUS_CODE, $value); } if (($value = $info['download_content_length']) > -1) { - $span->setAttribute(TraceAttributes::HTTP_RESPONSE_CONTENT_LENGTH, $value); + $span->setAttribute(TraceAttributes::HTTP_RESPONSE_HEADER . '.content_length', $value); } if (($value = $info['upload_content_length']) > -1) { $span->setAttribute(TraceAttributes::HTTP_REQUEST_BODY_SIZE, $value); diff --git a/src/Instrumentation/Curl/tests/Integration/CurlMultiInstrumentationTest.php b/src/Instrumentation/Curl/tests/Integration/CurlMultiInstrumentationTest.php index ebdd71503..13f825659 100644 --- a/src/Instrumentation/Curl/tests/Integration/CurlMultiInstrumentationTest.php +++ b/src/Instrumentation/Curl/tests/Integration/CurlMultiInstrumentationTest.php @@ -93,7 +93,7 @@ public function test_curl_multi_error() $this->assertCount(1, $this->storage); $span = $this->storage->offsetGet(0); - $this->assertEquals('curl_multi_exec', $span->getAttributes()->get(TraceAttributes::CODE_FUNCTION)); + $this->assertEquals('curl_multi_exec', $span->getAttributes()->get(TraceAttributes::CODE_FUNCTION_NAME)); $this->assertEquals('unknown://scheme.com/', actual: $span->getAttributes()->get(TraceAttributes::URL_FULL)); $this->assertSame('GET', $span->getName()); } diff --git a/src/Instrumentation/ExtAmqp/.phan/config.php b/src/Instrumentation/ExtAmqp/.phan/config.php new file mode 100644 index 000000000..6bf6f35c4 --- /dev/null +++ b/src/Instrumentation/ExtAmqp/.phan/config.php @@ -0,0 +1,371 @@ + '8.2', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/ExtAmqp/composer.json b/src/Instrumentation/ExtAmqp/composer.json index 3c2918ce2..e1e20dd24 100644 --- a/src/Instrumentation/ExtAmqp/composer.json +++ b/src/Instrumentation/ExtAmqp/composer.json @@ -13,7 +13,7 @@ "ext-amqp": "*", "ext-opentelemetry": "*", "open-telemetry/api": "^1", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", diff --git a/src/Instrumentation/ExtAmqp/src/ExtAmqpInstrumentation.php b/src/Instrumentation/ExtAmqp/src/ExtAmqpInstrumentation.php index 2802163a5..d6fd972ad 100644 --- a/src/Instrumentation/ExtAmqp/src/ExtAmqpInstrumentation.php +++ b/src/Instrumentation/ExtAmqp/src/ExtAmqpInstrumentation.php @@ -18,6 +18,11 @@ use OpenTelemetry\SemConv\TraceAttributes; use Throwable; +/** + * This uses SemConv 1.24, until messaging SemConv becomes stable. + * @see https://opentelemetry.io/docs/specs/semconv/messaging/rabbitmq/ + * @phan-file-suppress PhanDeprecatedClassConstant + */ final class ExtAmqpInstrumentation { public const NAME = 'ext_amqp'; @@ -57,14 +62,14 @@ public static function register(): void ->setAttribute(TraceAttributes::MESSAGING_SYSTEM, 'amqp') ->setAttribute(TraceAttributes::MESSAGING_OPERATION, 'publish') - ->setAttribute(TraceAttributes::MESSAGING_DESTINATION, $routingKey) + ->setAttribute('messaging.destination', $routingKey) ->setAttribute(TraceAttributes::MESSAGING_DESTINATION_NAME, $routingKey) - ->setAttribute(TraceAttributes::MESSAGING_DESTINATION_PUBLISH_NAME, sprintf('%s%s', $exchange->getName() != '' ? $exchange->getName() . ' ': '', $routingKey)) + ->setAttribute('messaging.destination_publish.name', sprintf('%s%s', $exchange->getName() != '' ? $exchange->getName() . ' ': '', $routingKey)) - ->setAttribute(TraceAttributes::MESSAGING_DESTINATION_KIND, $exchange->getType() !== '' ? $exchange->getType() : 'unknown') + ->setAttribute('messaging.destination.kind', $exchange->getType() !== '' ? $exchange->getType() : 'unknown') - ->setAttribute(TraceAttributes::MESSAGING_RABBITMQ_ROUTING_KEY, $routingKey) - ->setAttribute(TraceAttributes::MESSAGING_RABBITMQ_DESTINATION_ROUTING_KEY, $routingKey) + ->setAttribute('messaging.rabbitmq.routing.key', $routingKey) + ->setAttribute('messaging.rabbitmq.destination.routing.key', $routingKey) // network ->setAttribute(TraceAttributes::NET_PROTOCOL_NAME, 'amqp') @@ -170,11 +175,11 @@ protected static function createInteractionWithQueueSpan(CachedInstrumentation $ ->setAttribute(TraceAttributes::MESSAGING_SYSTEM, 'amqp') ->setAttribute(TraceAttributes::MESSAGING_OPERATION, $method) - ->setAttribute(TraceAttributes::MESSAGING_DESTINATION_KIND, 'queue') + ->setAttribute('messaging.destination.kind', 'queue') - ->setAttribute(TraceAttributes::MESSAGING_RABBITMQ_ROUTING_KEY, $queueName) - ->setAttribute(TraceAttributes::MESSAGING_RABBITMQ_DESTINATION_ROUTING_KEY, $queueName) - ->setAttribute(TraceAttributes::MESSAGING_DESTINATION_PUBLISH_NAME, $queueName) + ->setAttribute('messaging.rabbitmq.routing.key', $queueName) + ->setAttribute('messaging.rabbitmq.destination.routing_key', $queueName) + ->setAttribute('messaging.destination_publish.name', $queueName) ->setAttribute(TraceAttributes::MESSAGING_CLIENT_ID, $queue->getConsumerTag()) diff --git a/src/Instrumentation/ExtAmqp/tests/Integration/ExtAmqpInstrumentationTest.php b/src/Instrumentation/ExtAmqp/tests/Integration/ExtAmqpInstrumentationTest.php index 02d85c4fa..f92b70f14 100644 --- a/src/Instrumentation/ExtAmqp/tests/Integration/ExtAmqpInstrumentationTest.php +++ b/src/Instrumentation/ExtAmqp/tests/Integration/ExtAmqpInstrumentationTest.php @@ -59,7 +59,7 @@ public function test_rabbit_basic_publish_without_args_works(): void $this->assertEquals('amqp', $span->getAttributes()->get(TraceAttributes::MESSAGING_SYSTEM)); $this->assertEquals(SpanKind::KIND_PRODUCER, $span->getKind()); $this->assertEquals('test_exchange ' . $routing_key, $span->getAttributes()->get(TraceAttributes::MESSAGING_DESTINATION_PUBLISH_NAME)); - $this->assertEquals('topic', $span->getAttributes()->get(TraceAttributes::MESSAGING_DESTINATION_KIND)); + $this->assertEquals('topic', $span->getAttributes()->get('messaging.destination.kind')); /** * Our message should be the first one in the queue @@ -93,7 +93,7 @@ public function test_rabbit_basic_publish(string $messageInteraction): void $this->assertEquals('amqp', $publishSpan->getAttributes()->get(TraceAttributes::MESSAGING_SYSTEM)); $this->assertEquals(SpanKind::KIND_PRODUCER, $publishSpan->getKind()); $this->assertEquals('test_exchange ' . $routing_key, $publishSpan->getAttributes()->get(TraceAttributes::MESSAGING_DESTINATION_PUBLISH_NAME)); - $this->assertEquals('topic', $publishSpan->getAttributes()->get(TraceAttributes::MESSAGING_DESTINATION_KIND)); + $this->assertEquals('topic', $publishSpan->getAttributes()->get('messaging.destination.kind')); /** * Our message should be the first one in the queue @@ -125,6 +125,9 @@ public function getRabbitMessageInteractions(): array ]; } + /** + * @psalm-suppress PossiblyNullArgument + */ protected function setUpQueue() { $routing_key = uniqid('test_queue_', true); diff --git a/src/Instrumentation/ExtRdKafka/.phan/config.php b/src/Instrumentation/ExtRdKafka/.phan/config.php index da2ac2d99..6bf6f35c4 100644 --- a/src/Instrumentation/ExtRdKafka/.phan/config.php +++ b/src/Instrumentation/ExtRdKafka/.phan/config.php @@ -42,7 +42,7 @@ // // Note that the **only** effect of choosing `'5.6'` is to infer that functions removed in php 7.0 exist. // (See `backward_compatibility_checks` for additional options) - 'target_php_version' => '8.0', + 'target_php_version' => '8.2', // If enabled, missing properties will be created when // they are first seen. If false, we'll report an diff --git a/src/Instrumentation/ExtRdKafka/composer.json b/src/Instrumentation/ExtRdKafka/composer.json index 0c23c0450..152f79261 100644 --- a/src/Instrumentation/ExtRdKafka/composer.json +++ b/src/Instrumentation/ExtRdKafka/composer.json @@ -13,7 +13,7 @@ "ext-rdkafka": "*", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "composer-runtime-api": "^2.0" }, "require-dev": { diff --git a/src/Instrumentation/ExtRdKafka/src/ExtRdKafkaInstrumentation.php b/src/Instrumentation/ExtRdKafka/src/ExtRdKafkaInstrumentation.php index 72104d5da..c0360c731 100644 --- a/src/Instrumentation/ExtRdKafka/src/ExtRdKafkaInstrumentation.php +++ b/src/Instrumentation/ExtRdKafka/src/ExtRdKafkaInstrumentation.php @@ -12,9 +12,10 @@ use OpenTelemetry\Context\Context; use function OpenTelemetry\Instrumentation\hook; use OpenTelemetry\SemConv\TraceAttributes; - use OpenTelemetry\SemConv\TraceAttributeValues; +use OpenTelemetry\SemConv\Version; + use RdKafka\KafkaConsumer; use RdKafka\Message; use RdKafka\ProducerTopic; @@ -29,7 +30,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.ext_rdkafka', InstalledVersions::getVersion('open-telemetry/opentelemetry-auto-ext-rdkafka'), - 'https://opentelemetry.io/schemas/1.25.0', + Version::VERSION_1_30_0->url(), ); // Start root span and propagate parent if it exists in headers, for each message consumed @@ -74,14 +75,14 @@ private static function addProductionHooks($instrumentation) /** @var CachedInstrumentation $instrumentation */ $builder = $instrumentation ->tracer() - ->spanBuilder(sprintf('%s %s', $exchange->getName(), TraceAttributeValues::MESSAGING_OPERATION_PUBLISH)) + ->spanBuilder(sprintf('%s %s', TraceAttributeValues::MESSAGING_OPERATION_TYPE_SEND, $exchange->getName())) ->setSpanKind(SpanKind::KIND_PRODUCER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttribute(TraceAttributes::MESSAGING_SYSTEM, TraceAttributeValues::MESSAGING_SYSTEM_KAFKA) - ->setAttribute(TraceAttributes::MESSAGING_OPERATION, TraceAttributeValues::MESSAGING_OPERATION_PUBLISH) + ->setAttribute(TraceAttributes::MESSAGING_OPERATION_TYPE, TraceAttributeValues::MESSAGING_OPERATION_TYPE_SEND) ; $parent = Context::getCurrent(); @@ -147,12 +148,12 @@ private static function addConsumeHooks($instrumentation) $builder = $instrumentation ->tracer() // @phan-suppress-next-line PhanTypeMismatchArgumentInternal - Doesn't seem to know this has to be a string - ->spanBuilder(sprintf('%s %s', $message->topic_name, TraceAttributeValues::MESSAGING_OPERATION_DELIVER)) + ->spanBuilder(sprintf('%s %s', TraceAttributeValues::MESSAGING_OPERATION_TYPE_SEND, $message->topic_name)) ->setSpanKind(SpanKind::KIND_CONSUMER) ->setAttribute(TraceAttributes::MESSAGING_SYSTEM, TraceAttributeValues::MESSAGING_SYSTEM_KAFKA) - ->setAttribute(TraceAttributes::MESSAGING_OPERATION, TraceAttributeValues::MESSAGING_OPERATION_DELIVER) + ->setAttribute(TraceAttributes::MESSAGING_OPERATION_TYPE, TraceAttributeValues::MESSAGING_OPERATION_TYPE_PROCESS) ->setAttribute(TraceAttributes::MESSAGING_KAFKA_MESSAGE_KEY, $message->key) - ->setAttribute(TraceAttributes::MESSAGING_KAFKA_MESSAGE_OFFSET, $message->offset) + ->setAttribute(TraceAttributes::MESSAGING_KAFKA_OFFSET, $message->offset) ; if (is_array($message->headers)) { diff --git a/src/Instrumentation/ExtRdKafka/tests/Integration/ExtRdKafkaInstrumentationTest.php b/src/Instrumentation/ExtRdKafka/tests/Integration/ExtRdKafkaInstrumentationTest.php index 55e0bac25..82d737af2 100644 --- a/src/Instrumentation/ExtRdKafka/tests/Integration/ExtRdKafkaInstrumentationTest.php +++ b/src/Instrumentation/ExtRdKafka/tests/Integration/ExtRdKafkaInstrumentationTest.php @@ -62,7 +62,7 @@ public function test_consume_creates_new_span(): void $this->assertCount(1, $this->storage); /** @var ImmutableSpan $span */ $span = $this->storage->offsetGet(0); - $this->assertEquals('test process', $span->getName()); + $this->assertEquals('send test', $span->getName()); } public function test_context_propagated_on_consumption(): void @@ -91,7 +91,7 @@ public function test_context_propagated_on_consumption(): void $this->assertCount(3, $this->storage); /** @var ImmutableSpan $span */ $span = $this->storage->offsetGet(2); - $this->assertEquals('test process', $span->getName()); + $this->assertEquals('send test', $span->getName()); $this->assertEquals($expectedTraceId, $span->getContext()->getTraceId()); } @@ -130,7 +130,7 @@ public function test_produce_creates_new_span() $this->assertCount(1, $this->storage); $span = $this->storage->offsetGet(0); - $this->assertEquals('test publish', $span->getName()); + $this->assertEquals('send test', $span->getName()); } private function produceMessage( diff --git a/src/Instrumentation/Guzzle/composer.json b/src/Instrumentation/Guzzle/composer.json index f6db43b41..a9edb66c9 100644 --- a/src/Instrumentation/Guzzle/composer.json +++ b/src/Instrumentation/Guzzle/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "guzzlehttp/guzzle": "^7" }, "require-dev": { diff --git a/src/Instrumentation/Guzzle/src/GuzzleInstrumentation.php b/src/Instrumentation/Guzzle/src/GuzzleInstrumentation.php index e258153c6..8327f8f4f 100644 --- a/src/Instrumentation/Guzzle/src/GuzzleInstrumentation.php +++ b/src/Instrumentation/Guzzle/src/GuzzleInstrumentation.php @@ -31,7 +31,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.guzzle', null, - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0', ); hook( @@ -58,10 +58,10 @@ public static function register(): void ->setAttribute(TraceAttributes::SERVER_ADDRESS, $request->getUri()->getHost()) ->setAttribute(TraceAttributes::SERVER_PORT, $request->getUri()->getPort()) ->setAttribute(TraceAttributes::URL_PATH, $request->getUri()->getPath()) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ; foreach ($propagator->fields() as $field) { @@ -94,7 +94,7 @@ public static function register(): void $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); $span->end(); } @@ -119,7 +119,7 @@ public static function register(): void return $response; }, onRejected: function (\Throwable $t) use ($span) { - $span->recordException($t, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($t); $span->setStatus(StatusCode::STATUS_ERROR, $t->getMessage()); $span->end(); diff --git a/src/Instrumentation/HttpAsyncClient/composer.json b/src/Instrumentation/HttpAsyncClient/composer.json index eaab6a1cc..4635cf403 100644 --- a/src/Instrumentation/HttpAsyncClient/composer.json +++ b/src/Instrumentation/HttpAsyncClient/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "php-http/httplug": "^2" }, "autoload": { diff --git a/src/Instrumentation/HttpAsyncClient/src/HttpAsyncClientInstrumentation.php b/src/Instrumentation/HttpAsyncClient/src/HttpAsyncClientInstrumentation.php index 33939f656..516eb4345 100644 --- a/src/Instrumentation/HttpAsyncClient/src/HttpAsyncClientInstrumentation.php +++ b/src/Instrumentation/HttpAsyncClient/src/HttpAsyncClientInstrumentation.php @@ -24,7 +24,10 @@ class HttpAsyncClientInstrumentation public static function register(): void { - $instrumentation = new CachedInstrumentation('io.opentelemetry.contrib.php.http-async-client', schemaUrl: TraceAttributes::SCHEMA_URL); + $instrumentation = new CachedInstrumentation( + 'io.opentelemetry.contrib.php.http-async-client', + schemaUrl: 'https://opentelemetry.io/schemas/1.30.0', + ); hook( HttpAsyncClient::class, @@ -53,10 +56,10 @@ public static function register(): void ->setAttribute(TraceAttributes::HTTP_REQUEST_BODY_SIZE, $request->getHeaderLine('Content-Length')) ->setAttribute(TraceAttributes::SERVER_ADDRESS, $request->getUri()->getHost()) ->setAttribute(TraceAttributes::SERVER_PORT, $request->getUri()->getPort()) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ; foreach ($propagator->fields() as $field) { @@ -89,7 +92,7 @@ public static function register(): void $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); $span->end(); } @@ -114,7 +117,7 @@ public static function register(): void return $response; }, onRejected: function (\Throwable $t) use ($span) { - $span->recordException($t, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($t); $span->setStatus(StatusCode::STATUS_ERROR, $t->getMessage()); $span->end(); diff --git a/src/Instrumentation/IO/.phan/config.php b/src/Instrumentation/IO/.phan/config.php new file mode 100644 index 000000000..6bf6f35c4 --- /dev/null +++ b/src/Instrumentation/IO/.phan/config.php @@ -0,0 +1,371 @@ + '8.2', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/IO/composer.json b/src/Instrumentation/IO/composer.json index 344d5825e..54182a66a 100644 --- a/src/Instrumentation/IO/composer.json +++ b/src/Instrumentation/IO/composer.json @@ -7,11 +7,12 @@ "readme": "./README.md", "license": "Apache-2.0", "minimum-stability": "dev", + "prefer-stable": true, "require": { "php": "^8.2", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", diff --git a/src/Instrumentation/IO/src/IOInstrumentation.php b/src/Instrumentation/IO/src/IOInstrumentation.php index 44496c38c..106ae7f9e 100644 --- a/src/Instrumentation/IO/src/IOInstrumentation.php +++ b/src/Instrumentation/IO/src/IOInstrumentation.php @@ -11,6 +11,7 @@ use OpenTelemetry\Context\Context; use function OpenTelemetry\Instrumentation\hook; use OpenTelemetry\SemConv\TraceAttributes; +use OpenTelemetry\SemConv\Version; use Throwable; class IOInstrumentation @@ -22,7 +23,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.io', null, - 'https://opentelemetry.io/schemas/1.24.0' + Version::VERSION_1_30_0->url(), ); self::_hook($instrumentation, null, 'fopen', 'fopen'); @@ -67,9 +68,9 @@ private static function makeBuilder( /** @psalm-suppress ArgumentTypeCoercion */ return $instrumentation->tracer() ->spanBuilder($name) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); } private static function end(?Throwable $exception): void { @@ -80,7 +81,7 @@ private static function end(?Throwable $exception): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Laravel/composer.json b/src/Instrumentation/Laravel/composer.json index 65372b3b1..bc5ba619f 100644 --- a/src/Instrumentation/Laravel/composer.json +++ b/src/Instrumentation/Laravel/composer.json @@ -14,7 +14,7 @@ "ext-opentelemetry": "*", "laravel/framework": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.50", diff --git a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Console/Command.php b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Console/Command.php index d45153904..171626c24 100644 --- a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Console/Command.php +++ b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Console/Command.php @@ -34,10 +34,10 @@ protected function hookExecute(): bool $builder = $this->instrumentation ->tracer() ->spanBuilder(sprintf('Command %s', $command->getName() ?: 'unknown')) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); $span = $builder->startSpan(); diff --git a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Console/Kernel.php b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Console/Kernel.php index edf961f91..70f23ef05 100644 --- a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Console/Kernel.php +++ b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Console/Kernel.php @@ -43,10 +43,10 @@ private function hookHandle(): bool ->tracer() ->spanBuilder('Artisan handler') ->setSpanKind(SpanKind::KIND_PRODUCER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); $span = $builder->startSpan(); diff --git a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Http/Kernel.php b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Http/Kernel.php index b5415cc23..0a0bc54ed 100644 --- a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Http/Kernel.php +++ b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Http/Kernel.php @@ -45,10 +45,10 @@ protected function hookHandle(): bool ->tracer() ->spanBuilder(sprintf('%s', $request?->method() ?? 'unknown')) ->setSpanKind(SpanKind::KIND_SERVER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); if ($request) { /** @phan-suppress-next-line PhanAccessMethodInternal */ diff --git a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Queue/Queue.php b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Queue/Queue.php index c58800db9..197c05e1f 100644 --- a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Queue/Queue.php +++ b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Contracts/Queue/Queue.php @@ -38,10 +38,10 @@ protected function hookBulk(): bool 'bulk', pre: function (QueueContract $queue, array $params, string $class, string $function, ?string $filename, ?int $lineno) { $attributes = array_merge([ - TraceAttributes::CODE_FUNCTION => $function, + TraceAttributes::CODE_FUNCTION_NAME => $function, TraceAttributes::CODE_NAMESPACE => $class, TraceAttributes::CODE_FILEPATH => $filename, - TraceAttributes::CODE_LINENO => $lineno, + TraceAttributes::CODE_LINE_NUMBER => $lineno, TraceAttributes::MESSAGING_BATCH_MESSAGE_COUNT => count($params[0] ?? []), ], $this->contextualMessageSystemAttributes($queue, [])); @@ -49,9 +49,9 @@ protected function hookBulk(): bool $span = $this->instrumentation ->tracer() ->spanBuilder(vsprintf('%s %s', [ + TraceAttributeValues::MESSAGING_OPERATION_TYPE_SEND, /** @phan-suppress-next-line PhanUndeclaredMethod */ method_exists($queue, 'getQueue') ? $queue->getQueue($params[2] ?? null) : $queue->getConnectionName(), - TraceAttributeValues::MESSAGING_OPERATION_PUBLISH, ])) ->setSpanKind(SpanKind::KIND_PRODUCER) ->setAttributes($attributes) @@ -81,10 +81,10 @@ protected function hookLater(): bool }; $attributes = [ - TraceAttributes::CODE_FUNCTION => $function, + TraceAttributes::CODE_FUNCTION_NAME => $function, TraceAttributes::CODE_NAMESPACE => $class, TraceAttributes::CODE_FILEPATH => $filename, - TraceAttributes::CODE_LINENO => $lineno, + TraceAttributes::CODE_LINE_NUMBER => $lineno, 'messaging.message.delivery_timestamp' => $estimateDeliveryTimestamp, ]; @@ -92,9 +92,9 @@ protected function hookLater(): bool $span = $this->instrumentation ->tracer() ->spanBuilder(vsprintf('%s %s', [ + TraceAttributeValues::MESSAGING_OPERATION_TYPE_CREATE, /** @phan-suppress-next-line PhanUndeclaredMethod */ method_exists($queue, 'getQueue') ? $queue->getQueue($params[2] ?? null) : $queue->getConnectionName(), - 'create', ])) ->setSpanKind(SpanKind::KIND_PRODUCER) ->setAttributes($attributes) @@ -124,8 +124,8 @@ protected function hookPushRaw(): bool $span = $this->instrumentation ->tracer() ->spanBuilder(vsprintf('%s %s', [ + TraceAttributeValues::MESSAGING_OPERATION_TYPE_CREATE, $attributes[TraceAttributes::MESSAGING_DESTINATION_NAME], - TraceAttributeValues::MESSAGING_OPERATION_CREATE, ])) ->setSpanKind(SpanKind::KIND_PRODUCER) ->setAttributes($attributes) diff --git a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/SyncQueue.php b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/SyncQueue.php index 19d85cc2e..ed21dadba 100644 --- a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/SyncQueue.php +++ b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/SyncQueue.php @@ -40,10 +40,10 @@ protected function hookPush(): bool ])) ->setSpanKind(SpanKind::KIND_INTERNAL) ->setAttributes([ - TraceAttributes::CODE_FUNCTION => $function, + TraceAttributes::CODE_FUNCTION_NAME => $function, TraceAttributes::CODE_NAMESPACE => $class, TraceAttributes::CODE_FILEPATH => $filename, - TraceAttributes::CODE_LINENO => $lineno, + TraceAttributes::CODE_LINE_NUMBER => $lineno, ]) ->startSpan(); diff --git a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/Worker.php b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/Worker.php index 0e295a690..fb012cbae 100644 --- a/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/Worker.php +++ b/src/Instrumentation/Laravel/src/Hooks/Illuminate/Queue/Worker.php @@ -51,8 +51,8 @@ private function hookWorkerProcess(): bool $span = $this->instrumentation ->tracer() ->spanBuilder(vsprintf('%s %s', [ + TraceAttributeValues::MESSAGING_OPERATION_TYPE_PROCESS, $attributes[TraceAttributes::MESSAGING_DESTINATION_NAME], - 'process', ])) ->setSpanKind(SpanKind::KIND_CONSUMER) ->setParent($parent) @@ -98,8 +98,8 @@ private function hookWorkerGetNextJob(): bool $span = $this->instrumentation ->tracer() ->spanBuilder(vsprintf('%s %s', [ + TraceAttributeValues::MESSAGING_OPERATION_TYPE_RECEIVE, $attributes[TraceAttributes::MESSAGING_DESTINATION_NAME], - TraceAttributeValues::MESSAGING_OPERATION_RECEIVE, ])) ->setSpanKind(SpanKind::KIND_CONSUMER) ->setAttributes($attributes) diff --git a/src/Instrumentation/Laravel/src/Hooks/PostHookTrait.php b/src/Instrumentation/Laravel/src/Hooks/PostHookTrait.php index bd1e5a367..fa9c06ca7 100644 --- a/src/Instrumentation/Laravel/src/Hooks/PostHookTrait.php +++ b/src/Instrumentation/Laravel/src/Hooks/PostHookTrait.php @@ -7,7 +7,6 @@ use OpenTelemetry\API\Trace\Span; use OpenTelemetry\API\Trace\StatusCode; use OpenTelemetry\Context\Context; -use OpenTelemetry\SemConv\TraceAttributes; use Throwable; trait PostHookTrait @@ -23,9 +22,7 @@ private function endSpan(?Throwable $exception = null): void $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Laravel/src/LaravelInstrumentation.php b/src/Instrumentation/Laravel/src/LaravelInstrumentation.php index c49dcde3e..2af06f418 100644 --- a/src/Instrumentation/Laravel/src/LaravelInstrumentation.php +++ b/src/Instrumentation/Laravel/src/LaravelInstrumentation.php @@ -16,7 +16,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.laravel', null, - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0', ); Hooks\Illuminate\Console\Command::hook($instrumentation); diff --git a/src/Instrumentation/Laravel/src/Watchers/ExceptionWatcher.php b/src/Instrumentation/Laravel/src/Watchers/ExceptionWatcher.php index 7bbb2bdd4..176575a26 100644 --- a/src/Instrumentation/Laravel/src/Watchers/ExceptionWatcher.php +++ b/src/Instrumentation/Laravel/src/Watchers/ExceptionWatcher.php @@ -9,7 +9,6 @@ use OpenTelemetry\API\Trace\Span; use OpenTelemetry\API\Trace\StatusCode; use OpenTelemetry\Context\Context; -use OpenTelemetry\SemConv\TraceAttributes; use Throwable; class ExceptionWatcher extends Watcher @@ -37,7 +36,7 @@ public function recordException(MessageLogged $log): void return; } $span = Span::fromContext($scope->context()); - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } } diff --git a/src/Instrumentation/Laravel/src/Watchers/LogWatcher.php b/src/Instrumentation/Laravel/src/Watchers/LogWatcher.php index 7adcddd92..bdeb64588 100644 --- a/src/Instrumentation/Laravel/src/Watchers/LogWatcher.php +++ b/src/Instrumentation/Laravel/src/Watchers/LogWatcher.php @@ -32,6 +32,7 @@ public function register(Application $app): void /** * Record a log. + * @phan-suppress PhanDeprecatedFunction */ public function recordLog(MessageLogged $log): void { diff --git a/src/Instrumentation/Laravel/src/Watchers/QueryWatcher.php b/src/Instrumentation/Laravel/src/Watchers/QueryWatcher.php index ff1c82d50..cfd438096 100644 --- a/src/Instrumentation/Laravel/src/Watchers/QueryWatcher.php +++ b/src/Instrumentation/Laravel/src/Watchers/QueryWatcher.php @@ -44,13 +44,13 @@ public function recordQuery(QueryExecuted $query): void ->startSpan(); $attributes = [ - TraceAttributes::DB_SYSTEM => $query->connection->getDriverName(), - TraceAttributes::DB_NAME => $query->connection->getDatabaseName(), - TraceAttributes::DB_OPERATION => $operationName, - TraceAttributes::DB_USER => $query->connection->getConfig('username'), + TraceAttributes::DB_SYSTEM_NAME => $query->connection->getDriverName(), + TraceAttributes::DB_NAMESPACE => $query->connection->getDatabaseName(), + TraceAttributes::DB_OPERATION_NAME => $operationName, + //TraceAttributes::DB_USER => $query->connection->getConfig('username'), ]; - $attributes[TraceAttributes::DB_STATEMENT] = $query->sql; + $attributes[TraceAttributes::DB_QUERY_TEXT] = $query->sql; /** @psalm-suppress PossiblyInvalidArgument */ $span->setAttributes($attributes); $span->end($nowInNs); diff --git a/src/Instrumentation/Laravel/src/Watchers/RedisCommand/RedisCommandWatcher.php b/src/Instrumentation/Laravel/src/Watchers/RedisCommand/RedisCommandWatcher.php index 6e798d4e5..31de0a2b5 100644 --- a/src/Instrumentation/Laravel/src/Watchers/RedisCommand/RedisCommandWatcher.php +++ b/src/Instrumentation/Laravel/src/Watchers/RedisCommand/RedisCommandWatcher.php @@ -54,10 +54,10 @@ public function recordRedisCommand(CommandExecuted $event): void // See https://opentelemetry.io/docs/specs/semconv/database/redis/ $attributes = [ - TraceAttributes::DB_SYSTEM => TraceAttributeValues::DB_SYSTEM_REDIS, - TraceAttributes::DB_NAME => $this->fetchDbIndex($event->connection), - TraceAttributes::DB_OPERATION => $operationName, - TraceAttributes::DB_STATEMENT => Serializer::serializeCommand($event->command, $event->parameters), + TraceAttributes::DB_SYSTEM_NAME => TraceAttributeValues::DB_SYSTEM_REDIS, + TraceAttributes::DB_NAMESPACE => $this->fetchDbIndex($event->connection), + TraceAttributes::DB_OPERATION_NAME => $operationName, + TraceAttributes::DB_QUERY_TEXT => Serializer::serializeCommand($event->command, $event->parameters), TraceAttributes::SERVER_ADDRESS => $this->fetchDbHost($event->connection), ]; diff --git a/src/Instrumentation/Laravel/src/Watchers/RedisCommand/Serializer.php b/src/Instrumentation/Laravel/src/Watchers/RedisCommand/Serializer.php index a64c40813..e15b4db6f 100644 --- a/src/Instrumentation/Laravel/src/Watchers/RedisCommand/Serializer.php +++ b/src/Instrumentation/Laravel/src/Watchers/RedisCommand/Serializer.php @@ -70,7 +70,7 @@ public static function serializeCommand(string $command, array $params): string } // In some cases (for example when using LUA scripts) arrays are valid parameters - $paramsToSerialize = array_map(function($param) { return is_array($param) ? json_encode($param) : $param; }, $paramsToSerialize); + $paramsToSerialize = array_map(function ($param) { return is_array($param) ? json_encode($param) : $param; }, $paramsToSerialize); return $command . ' ' . implode(' ', $paramsToSerialize); } diff --git a/src/Instrumentation/Laravel/tests/Integration/LaravelInstrumentationTest.php b/src/Instrumentation/Laravel/tests/Integration/LaravelInstrumentationTest.php index c5096ff3e..8f9bd1355 100644 --- a/src/Instrumentation/Laravel/tests/Integration/LaravelInstrumentationTest.php +++ b/src/Instrumentation/Laravel/tests/Integration/LaravelInstrumentationTest.php @@ -58,10 +58,10 @@ public function test_cache_log_db(): void $span = $this->storage[1]; $this->assertSame('sql SELECT', $span->getName()); - $this->assertSame('SELECT', $span->getAttributes()->get('db.operation')); - $this->assertSame(':memory:', $span->getAttributes()->get('db.name')); - $this->assertSame('select 1', $span->getAttributes()->get('db.statement')); - $this->assertSame('sqlite', $span->getAttributes()->get('db.system')); + $this->assertSame('SELECT', $span->getAttributes()->get('db.operation.name')); + $this->assertSame(':memory:', $span->getAttributes()->get('db.namespace')); + $this->assertSame('select 1', $span->getAttributes()->get('db.query.text')); + $this->assertSame('sqlite', $span->getAttributes()->get('db.system.name')); /** @var \OpenTelemetry\SDK\Logs\ReadWriteLogRecord $logRecord */ $logRecord = $this->storage[0]; diff --git a/src/Instrumentation/Laravel/tests/Integration/Queue/QueueTest.php b/src/Instrumentation/Laravel/tests/Integration/Queue/QueueTest.php index 1d902e0b7..63991dccf 100644 --- a/src/Instrumentation/Laravel/tests/Integration/Queue/QueueTest.php +++ b/src/Instrumentation/Laravel/tests/Integration/Queue/QueueTest.php @@ -55,17 +55,17 @@ public function test_it_can_push_a_message_with_a_delay(): void $this->queue->later(new DateInterval('PT10M'), new DummyJob('DateInterval')); $this->queue->later(new DateTimeImmutable('2024-04-15 22:29:00.123Z'), new DummyJob('DateTime')); - $this->assertEquals('sync create', $this->storage[2]->getName()); + $this->assertEquals('create sync', $this->storage[2]->getName()); $this->assertIsInt( $this->storage[2]->getAttributes()->get('messaging.message.delivery_timestamp'), ); - $this->assertEquals('sync create', $this->storage[5]->getName()); + $this->assertEquals('create sync', $this->storage[5]->getName()); $this->assertIsInt( $this->storage[5]->getAttributes()->get('messaging.message.delivery_timestamp'), ); - $this->assertEquals('sync create', $this->storage[8]->getName()); + $this->assertEquals('create sync', $this->storage[8]->getName()); $this->assertIsInt( $this->storage[8]->getAttributes()->get('messaging.message.delivery_timestamp'), ); @@ -86,7 +86,7 @@ public function test_it_can_publish_in_bulk(): void /** @psalm-suppress PossiblyUndefinedMethod */ $mockQueue->bulk($jobs); - $this->assertEquals('dummy-queue publish', $this->storage[0]->getName()); + $this->assertEquals('send dummy-queue', $this->storage[0]->getName()); $this->assertEquals(10, $this->storage[0]->getAttributes()->get(TraceAttributes::MESSAGING_BATCH_MESSAGE_COUNT)); } @@ -107,7 +107,7 @@ public function test_it_can_create_with_redis(): void new DummyJob('B'), ]); - $this->assertEquals('queues:default publish', $this->storage[0]->getName()); + $this->assertEquals('send queues:default', $this->storage[0]->getName()); $this->assertEquals(2, $this->storage[0]->getAttributes()->get(TraceAttributes::MESSAGING_BATCH_MESSAGE_COUNT)); $this->assertEquals('redis', $this->storage[0]->getAttributes()->get(TraceAttributes::MESSAGING_SYSTEM)); } diff --git a/src/Instrumentation/MongoDB/.phan/config.php b/src/Instrumentation/MongoDB/.phan/config.php new file mode 100644 index 000000000..da2ac2d99 --- /dev/null +++ b/src/Instrumentation/MongoDB/.phan/config.php @@ -0,0 +1,371 @@ + '8.0', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/MongoDB/composer.json b/src/Instrumentation/MongoDB/composer.json index df7c245b8..24810b7ce 100644 --- a/src/Instrumentation/MongoDB/composer.json +++ b/src/Instrumentation/MongoDB/composer.json @@ -7,12 +7,12 @@ "readme": "./README.md", "license": "Apache-2.0", "require": { - "php": ">=7.4", + "php": ">=8.0", "ext-mongodb": "^1.13", "ext-json": "*", "mongodb/mongodb": "^1.15", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", diff --git a/src/Instrumentation/MongoDB/src/MongoDBInstrumentation.php b/src/Instrumentation/MongoDB/src/MongoDBInstrumentation.php index 7400da50e..148acc8d1 100644 --- a/src/Instrumentation/MongoDB/src/MongoDBInstrumentation.php +++ b/src/Instrumentation/MongoDB/src/MongoDBInstrumentation.php @@ -12,14 +12,14 @@ final class MongoDBInstrumentation public const NAME = 'mongodb'; /** - * @param callable(object):?string $commandSerializer + * @param ?callable(object):string $commandSerializer */ - public static function register(callable $commandSerializer = null): void + public static function register(?callable $commandSerializer = null): void { $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.mongodb', null, - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0', ); $commandSerializer ??= self::defaultCommandSerializer(); /** @psalm-suppress UnusedFunctionCall */ @@ -27,7 +27,7 @@ public static function register(callable $commandSerializer = null): void } /** - * @return callable(object):?string + * @return callable(object): string */ private static function defaultCommandSerializer(): callable { diff --git a/src/Instrumentation/MongoDB/src/MongoDBInstrumentationSubscriber.php b/src/Instrumentation/MongoDB/src/MongoDBInstrumentationSubscriber.php index b94f6cddd..8add3f2c0 100644 --- a/src/Instrumentation/MongoDB/src/MongoDBInstrumentationSubscriber.php +++ b/src/Instrumentation/MongoDB/src/MongoDBInstrumentationSubscriber.php @@ -28,11 +28,14 @@ use OpenTelemetry\SemConv\TraceAttributes; use Throwable; +/** + * @phan-file-suppress PhanTypeMismatchDeclaredParamNullable + */ final class MongoDBInstrumentationSubscriber implements CommandSubscriber, SDAMSubscriber { private CachedInstrumentation $instrumentation; /** - * @var Closure(object):?string + * @var Closure(object): string */ private Closure $commandSerializer; /** @@ -41,22 +44,23 @@ final class MongoDBInstrumentationSubscriber implements CommandSubscriber, SDAMS private array $serverAttributes = []; /** - * @param (callable(object):?string) $commandSerializer + * @param callable(object):string $commandSerializer */ public function __construct(CachedInstrumentation $instrumentation, callable $commandSerializer) { $this->instrumentation = $instrumentation; - $this->commandSerializer = static function (object $command) use ($commandSerializer): ?string { + $this->commandSerializer = static function (object $command) use ($commandSerializer): string { try { return $commandSerializer($command); } catch (Throwable $exception) { - return null; + return ''; } }; } /** * @psalm-suppress MixedAssignment,MixedArrayTypeCoercion,MixedArrayOffset,MixedArgument + * @phan-suppress PhanDeprecatedFunctionInternal */ public function commandStarted(CommandStartedEvent $event): void { @@ -81,14 +85,14 @@ public function commandStarted(CommandStartedEvent $event): void $builder = self::startSpan($this->instrumentation, 'MongoDB ' . $scopedCommand) ->setSpanKind(SpanKind::KIND_CLIENT) - ->setAttribute(TraceAttributes::DB_SYSTEM, 'mongodb') - ->setAttribute(TraceAttributes::DB_NAME, $databaseName) - ->setAttribute(TraceAttributes::DB_OPERATION, $commandName) + ->setAttribute(TraceAttributes::DB_SYSTEM_NAME, 'mongodb') + ->setAttribute(TraceAttributes::DB_NAMESPACE, $databaseName) + ->setAttribute(TraceAttributes::DB_OPERATION_NAME, $commandName) ->setAttribute(TraceAttributes::SERVER_ADDRESS, $isSocket ? null : $host) ->setAttribute(TraceAttributes::SERVER_PORT, $isSocket ? null : $port) ->setAttribute(TraceAttributes::NETWORK_TRANSPORT, $isSocket ? 'unix' : 'tcp') - ->setAttribute(TraceAttributes::DB_STATEMENT, ($this->commandSerializer)($command)) - ->setAttribute(TraceAttributes::DB_MONGODB_COLLECTION, $collectionName) + ->setAttribute(TraceAttributes::DB_QUERY_TEXT, ($this->commandSerializer)($command)) + ->setAttribute(TraceAttributes::DB_COLLECTION_NAME, $collectionName) ->setAttribute(MongoDBTraceAttributes::DB_MONGODB_REQUEST_ID, $event->getRequestId()) ->setAttribute(MongoDBTraceAttributes::DB_MONGODB_OPERATION_ID, $event->getOperationId()) ->setAttributes($attributes) @@ -127,9 +131,7 @@ private static function endSpan(?Throwable $exception = null): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/MongoDB/tests/Integration/MongoDBInstrumentationTest.php b/src/Instrumentation/MongoDB/tests/Integration/MongoDBInstrumentationTest.php index 6675495a7..692191e51 100644 --- a/src/Instrumentation/MongoDB/tests/Integration/MongoDBInstrumentationTest.php +++ b/src/Instrumentation/MongoDB/tests/Integration/MongoDBInstrumentationTest.php @@ -69,10 +69,10 @@ public function test_mongodb_find_one(): void self::assertSame('MongoDB coll.find', $this->span->getName()); self::assertSame(SpanKind::KIND_CLIENT, $this->span->getKind()); $attributes = $this->span->getAttributes(); - self::assertSame('mongodb', $attributes->get(TraceAttributes::DB_SYSTEM)); - self::assertSame(self::DATABASE_NAME, $attributes->get(TraceAttributes::DB_NAME)); - self::assertSame('find', $attributes->get(TraceAttributes::DB_OPERATION)); - self::assertSame(self::COLLECTION_NAME, $attributes->get(TraceAttributes::DB_MONGODB_COLLECTION)); + self::assertSame('mongodb', $attributes->get(TraceAttributes::DB_SYSTEM_NAME)); + self::assertSame(self::DATABASE_NAME, $attributes->get(TraceAttributes::DB_NAMESPACE)); + self::assertSame('find', $attributes->get(TraceAttributes::DB_OPERATION_NAME)); + self::assertSame(self::COLLECTION_NAME, $attributes->get(TraceAttributes::DB_COLLECTION_NAME)); self::assertSame($this->host, $attributes->get(TraceAttributes::SERVER_ADDRESS)); self::assertSame($this->port, $attributes->get(TraceAttributes::SERVER_PORT)); self::assertSame('tcp', $attributes->get(TraceAttributes::NETWORK_TRANSPORT)); diff --git a/src/Instrumentation/MySqli/.phan/config.php b/src/Instrumentation/MySqli/.phan/config.php new file mode 100644 index 000000000..6bf6f35c4 --- /dev/null +++ b/src/Instrumentation/MySqli/.phan/config.php @@ -0,0 +1,371 @@ + '8.2', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/MySqli/composer.json b/src/Instrumentation/MySqli/composer.json index a038ead32..e55f750ab 100644 --- a/src/Instrumentation/MySqli/composer.json +++ b/src/Instrumentation/MySqli/composer.json @@ -21,7 +21,7 @@ "ext-mysqli": "*", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.27.1", + "open-telemetry/sem-conv": "^1.30", "symfony/polyfill-mbstring": "^1.31" }, "suggest": { diff --git a/src/Instrumentation/MySqli/src/MySqliInstrumentation.php b/src/Instrumentation/MySqli/src/MySqliInstrumentation.php index 4ee60abc3..30bc32352 100644 --- a/src/Instrumentation/MySqli/src/MySqliInstrumentation.php +++ b/src/Instrumentation/MySqli/src/MySqliInstrumentation.php @@ -16,7 +16,11 @@ use OpenTelemetry\Context\Context; use function OpenTelemetry\Instrumentation\hook; use OpenTelemetry\SemConv\TraceAttributes; +use OpenTelemetry\SemConv\Version; +/** + * @phan-file-suppress PhanParamTooFewUnpack + */ class MySqliInstrumentation { use LogsMessagesTrait; @@ -33,7 +37,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.mysqli', null, - 'https://opentelemetry.io/schemas/1.27.1' + Version::VERSION_1_30_0->url(), ); $tracker = new MySqliTracker(); @@ -409,9 +413,9 @@ private static function constructPreHook(string $spanName, int $paramsOffset, Ca $attributes = []; $attributes[TraceAttributes::SERVER_ADDRESS] = $params[$paramsOffset + 0] ?? get_cfg_var('mysqli.default_host'); $attributes[TraceAttributes::SERVER_PORT] = $params[$paramsOffset + 4] ?? get_cfg_var('mysqli.default_port'); - $attributes[TraceAttributes::DB_USER] = $params[$paramsOffset + 1] ?? get_cfg_var('mysqli.default_user'); + //$attributes[TraceAttributes::DB_USER] = $params[$paramsOffset + 1] ?? get_cfg_var('mysqli.default_user'); $attributes[TraceAttributes::DB_NAMESPACE] = $params[$paramsOffset + 3] ?? null; - $attributes[TraceAttributes::DB_SYSTEM] = 'mysql'; + $attributes[TraceAttributes::DB_SYSTEM_NAME] = 'mysql'; self::startSpan($spanName, $instrumentation, $class, $function, $filename, $lineno, $attributes); } @@ -450,12 +454,11 @@ private static function queryPostHook(CachedInstrumentation $instrumentation, My $attributes = $tracker->getMySqliAttributes($mysqli); - $attributes[TraceAttributes::DB_STATEMENT] = mb_convert_encoding($query, 'UTF-8'); + $attributes[TraceAttributes::DB_QUERY_TEXT] = mb_convert_encoding($query, 'UTF-8'); $attributes[TraceAttributes::DB_OPERATION_NAME] = self::extractQueryCommand($query); if ($retVal === false || $exception) { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $mysqli->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $mysqli->errno; } $errorStatus = ($retVal === false && !$exception) ? $mysqli->error : null; @@ -473,13 +476,12 @@ private static function multiQueryPostHook(CachedInstrumentation $instrumentatio $tracker->storeMySqliMultiQuery($mysqli, $query); if ($currentQuery = $tracker->getNextMySqliMultiQuery($mysqli)) { - $attributes[TraceAttributes::DB_STATEMENT] = mb_convert_encoding($currentQuery, 'UTF-8'); + $attributes[TraceAttributes::DB_QUERY_TEXT] = mb_convert_encoding($currentQuery, 'UTF-8'); $attributes[TraceAttributes::DB_OPERATION_NAME] = self::extractQueryCommand($currentQuery); } if ($retVal === false || $exception) { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $mysqli->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $mysqli->errno; } else { $tracker->trackMySqliSpan($mysqli, Span::getCurrent()->getContext()); } @@ -521,13 +523,12 @@ private static function nextResultPostHook(CachedInstrumentation $instrumentatio } if ($currentQuery) { - $attributes[TraceAttributes::DB_STATEMENT] = mb_convert_encoding($currentQuery, 'UTF-8'); + $attributes[TraceAttributes::DB_QUERY_TEXT] = mb_convert_encoding($currentQuery, 'UTF-8'); $attributes[TraceAttributes::DB_OPERATION_NAME] = self::extractQueryCommand($currentQuery); } if ($retVal === false || $exception) { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $mysqli->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $mysqli->errno; } self::endSpan($attributes, $exception, $errorStatus); @@ -541,7 +542,7 @@ private static function changeUserPostHook(CachedInstrumentation $instrumentatio $mysqli = $obj ? $obj : $params[0]; - $tracker->addMySqliAttribute($mysqli, TraceAttributes::DB_USER, $params[$obj ? 0 : 1]); + //$tracker->addMySqliAttribute($mysqli, TraceAttributes::DB_USER, $params[$obj ? 0 : 1]); //deprecated, no replacment at this time if (($database = $params[$obj ? 2 : 3] ?? null) !== null) { $tracker->addMySqliAttribute($mysqli, TraceAttributes::DB_NAMESPACE, $database); } @@ -575,17 +576,16 @@ private static function preparePostHook(CachedInstrumentation $instrumentation, $operation = self::extractQueryCommand($query); $attributes = $tracker->getMySqliAttributes($mysqli); - $attributes[TraceAttributes::DB_STATEMENT] = $query; + $attributes[TraceAttributes::DB_QUERY_TEXT] = $query; $attributes[TraceAttributes::DB_OPERATION_NAME] = $operation; if (!$exception && $stmtRetVal instanceof mysqli_stmt) { $tracker->trackMySqliFromStatement($mysqli, $stmtRetVal); - $tracker->addStatementAttribute($stmtRetVal, TraceAttributes::DB_STATEMENT, $query); + $tracker->addStatementAttribute($stmtRetVal, TraceAttributes::DB_QUERY_TEXT, $query); $tracker->addStatementAttribute($stmtRetVal, TraceAttributes::DB_OPERATION_NAME, $operation); } else { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $mysqli->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $mysqli->errno; $errorStatus = !$exception ? $mysqli->error : null; } @@ -610,8 +610,7 @@ private static function beginTransactionPostHook(CachedInstrumentation $instrume } if ($retVal === false || $exception) { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $mysqli->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $mysqli->errno; } else { $tracker->trackMySqliTransaction($mysqli, Span::getCurrent()->getContext()); } @@ -640,8 +639,7 @@ private static function transactionPostHook(CachedInstrumentation $instrumentati } if ($retVal === false || $exception) { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $mysqli->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $mysqli->errno; } $tracker->untrackMySqliTransaction($mysqli); @@ -667,7 +665,7 @@ private static function stmtPreparePostHook(CachedInstrumentation $instrumentati } $query = $obj ? $params[0] : $params[1]; - $tracker->addStatementAttribute($obj ? $obj : $params[0], TraceAttributes::DB_STATEMENT, mb_convert_encoding($query, 'UTF-8')); + $tracker->addStatementAttribute($obj ? $obj : $params[0], TraceAttributes::DB_QUERY_TEXT, mb_convert_encoding($query, 'UTF-8')); $tracker->addStatementAttribute($obj ? $obj : $params[0], TraceAttributes::DB_OPERATION_NAME, self::extractQueryCommand($query)); } @@ -683,7 +681,7 @@ private static function stmtConstructPostHook(CachedInstrumentation $instrumenta $tracker->trackMySqliFromStatement($params[0], $stmt); if ($params[1] ?? null) { - $tracker->addStatementAttribute($stmt, TraceAttributes::DB_STATEMENT, mb_convert_encoding($params[1], 'UTF-8')); + $tracker->addStatementAttribute($stmt, TraceAttributes::DB_QUERY_TEXT, mb_convert_encoding($params[1], 'UTF-8')); $tracker->addStatementAttribute($stmt, TraceAttributes::DB_OPERATION_NAME, self::extractQueryCommand($params[1])); } } @@ -701,8 +699,7 @@ private static function stmtExecutePostHook(CachedInstrumentation $instrumentati $attributes = array_merge($tracker->getMySqliAttributesFromStatement($stmt), $tracker->getStatementAttributes($stmt)); if ($retVal === false || $exception) { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $stmt->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $stmt->errno; } $errorStatus = ($retVal === false && !$exception) ? $stmt->error : null; @@ -740,8 +737,7 @@ private static function stmtNextResultPostHook(CachedInstrumentation $instrument } if ($retVal === false || $exception) { - //TODO use constant from comment after sem-conv update - $attributes[/*TraceAttributes::DB_RESPONSE_STATUS_CODE*/ 'db.response.status_code'] = $stmt->errno; + $attributes[TraceAttributes::DB_RESPONSE_STATUS_CODE] = $stmt->errno; } $errorStatus = ($retVal === false && !$exception) ? $stmt->error : null; @@ -757,10 +753,10 @@ private static function startSpan(string $spanName, CachedInstrumentation $instr ->spanBuilder($spanName) ->setParent($parent) ->setSpanKind(SpanKind::KIND_CLIENT) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttributes($attributes); $span = $builder->startSpan(); @@ -788,7 +784,7 @@ private static function endSpan(iterable $attributes, ?\Throwable $exception, ?s } if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setAttribute(TraceAttributes::EXCEPTION_TYPE, $exception::class); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/MySqli/src/MySqliTracker.php b/src/Instrumentation/MySqli/src/MySqliTracker.php index ae2d9067e..5e67162a9 100644 --- a/src/Instrumentation/MySqli/src/MySqliTracker.php +++ b/src/Instrumentation/MySqli/src/MySqliTracker.php @@ -11,6 +11,9 @@ use WeakMap; use WeakReference; +/** + * @phan-file-suppress PhanNonClassMethodCall + */ final class MySqliTracker { @@ -51,10 +54,10 @@ public function getNextMySqliMultiQuery(mysqli $mysqli) : ?string public function storeMySqliAttributes(mysqli $mysqli, ?string $hostname = null, ?string $username = null, ?string $database = null, ?int $port = null, ?string $socket = null) { $attributes = []; - $attributes[TraceAttributes::DB_SYSTEM] = 'mysql'; + $attributes[TraceAttributes::DB_SYSTEM_NAME] = 'mysql'; $attributes[TraceAttributes::SERVER_ADDRESS] = $hostname ?? get_cfg_var('mysqli.default_host'); $attributes[TraceAttributes::SERVER_PORT] = $port ?? get_cfg_var('mysqli.default_port'); - $attributes[TraceAttributes::DB_USER] = $username ?? get_cfg_var('mysqli.default_user'); + //$attributes[TraceAttributes::DB_USER] = $username ?? get_cfg_var('mysqli.default_user'); //deprecated, no replacment at this time if ($database) { $attributes[TraceAttributes::DB_NAMESPACE] = $database; } @@ -82,7 +85,6 @@ public function trackMySqliFromStatement(mysqli $mysqli, mysqli_stmt $mysqli_stm public function getMySqliFromStatement(mysqli_stmt $mysqli_stmt) : ?mysqli { return ($this->statementToMySqli[$mysqli_stmt] ?? null)?->get(); - ; } public function getMySqliAttributesFromStatement(mysqli_stmt $stmt) : array diff --git a/src/Instrumentation/MySqli/tests/Integration/MySqliInstrumentationTest.php b/src/Instrumentation/MySqli/tests/Integration/MySqliInstrumentationTest.php index c187df3b0..7cf024ca2 100644 --- a/src/Instrumentation/MySqli/tests/Integration/MySqliInstrumentationTest.php +++ b/src/Instrumentation/MySqli/tests/Integration/MySqliInstrumentationTest.php @@ -63,9 +63,9 @@ private function assertDatabaseAttributes(int $offset) { $span = $this->storage->offsetGet($offset); $this->assertEquals($this->mysqlHost, $span->getAttributes()->get(TraceAttributes::SERVER_ADDRESS)); - $this->assertEquals($this->user, $span->getAttributes()->get(TraceAttributes::DB_USER)); + //$this->assertEquals($this->user, $span->getAttributes()->get(TraceAttributes::DB_USER)); $this->assertEquals($this->database, $span->getAttributes()->get(TraceAttributes::DB_NAMESPACE)); - $this->assertEquals('mysql', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('mysql', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); } private function assertDatabaseAttributesForAllSpans(int $offsets) @@ -121,7 +121,7 @@ public function test_mysqli_query_objective(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -131,7 +131,7 @@ public function test_mysqli_query_objective(): void } $this->assertSame('mysqli::real_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -145,7 +145,7 @@ public function test_mysqli_query_objective(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -162,7 +162,7 @@ public function test_mysqli_query_objective(): void $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -180,7 +180,7 @@ public function test_mysqli_query_objective(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -195,7 +195,7 @@ public function test_mysqli_query_objective(): void $this->assertSame('mysqli::real_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -225,7 +225,7 @@ public function test_mysqli_query_procedural(): void $this->assertSame('mysqli_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -235,7 +235,7 @@ public function test_mysqli_query_procedural(): void } $this->assertSame('mysqli_real_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -249,7 +249,7 @@ public function test_mysqli_query_procedural(): void $this->assertSame('mysqli_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -266,7 +266,7 @@ public function test_mysqli_query_procedural(): void $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -284,7 +284,7 @@ public function test_mysqli_query_procedural(): void $this->assertSame('mysqli_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -299,7 +299,7 @@ public function test_mysqli_query_procedural(): void $this->assertSame('mysqli_real_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -327,7 +327,7 @@ public function test_mysqli_execute_query_objective(): void $this->assertSame('mysqli::execute_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -341,7 +341,7 @@ public function test_mysqli_execute_query_objective(): void $this->assertSame('mysqli::execute_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -358,7 +358,7 @@ public function test_mysqli_execute_query_objective(): void $this->assertSame('mysqli::execute_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -385,7 +385,7 @@ public function test_mysqli_execute_query_procedural(): void $this->assertSame('mysqli_execute_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -399,7 +399,7 @@ public function test_mysqli_execute_query_procedural(): void $this->assertSame('mysqli_execute_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -416,7 +416,7 @@ public function test_mysqli_execute_query_procedural(): void $this->assertSame('mysqli_execute_query', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString('Unknown database', $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -458,21 +458,21 @@ public function test_mysqli_multi_query_objective(): void $offset++; $this->assertSame('mysqli::multi_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT email FROM users ORDER BY id;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT email FROM users ORDER BY id;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT name FROM products ORDER BY stock;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT name FROM products ORDER BY stock;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -480,7 +480,7 @@ public function test_mysqli_multi_query_objective(): void $this->assertSame('mysqli::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString("Table 'otel_db.unknown' doesn't exist", $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT test FROM unknown ORDER BY nothing;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT test FROM unknown ORDER BY nothing;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -505,21 +505,21 @@ public function test_mysqli_multi_query_objective(): void $offset++; $this->assertSame('mysqli::multi_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT email FROM users ORDER BY id;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT email FROM users ORDER BY id;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT name FROM products ORDER BY stock;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT name FROM products ORDER BY stock;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -527,7 +527,7 @@ public function test_mysqli_multi_query_objective(): void $this->assertSame('mysqli::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString("Table 'otel_db.unknown' doesn't exist", $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT test FROM unknown ORDER BY nothing;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT test FROM unknown ORDER BY nothing;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -569,21 +569,21 @@ public function test_mysqli_multi_query_procedural(): void $offset++; $this->assertSame('mysqli_multi_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT email FROM users ORDER BY id;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT email FROM users ORDER BY id;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT name FROM products ORDER BY stock;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT name FROM products ORDER BY stock;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -591,7 +591,7 @@ public function test_mysqli_multi_query_procedural(): void $this->assertSame('mysqli_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString("Table 'otel_db.unknown' doesn't exist", $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT test FROM unknown ORDER BY nothing;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT test FROM unknown ORDER BY nothing;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -616,21 +616,21 @@ public function test_mysqli_multi_query_procedural(): void $offset++; $this->assertSame('mysqli_multi_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT email FROM users ORDER BY id;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT email FROM users ORDER BY id;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); $offset++; $this->assertSame('mysqli_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT name FROM products ORDER BY stock;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT name FROM products ORDER BY stock;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -638,7 +638,7 @@ public function test_mysqli_multi_query_procedural(): void $this->assertSame('mysqli_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertStringContainsString("Table 'otel_db.unknown' doesn't exist", $this->storage->offsetGet($offset)->getStatus()->getDescription()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT test FROM unknown ORDER BY nothing;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT test FROM unknown ORDER BY nothing;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -663,7 +663,7 @@ public function test_mysqli_prepare_objective(): void $offset++; $this->assertSame('mysqli::prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -672,7 +672,7 @@ public function test_mysqli_prepare_objective(): void $this->assertSame('mysqli_stmt::execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -692,7 +692,7 @@ public function test_mysqli_prepare_objective(): void $this->assertSame('mysqli::prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -719,7 +719,7 @@ public function test_mysqli_prepare_procedural(): void $offset++; $this->assertSame('mysqli_prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -728,7 +728,7 @@ public function test_mysqli_prepare_procedural(): void $this->assertSame('mysqli_stmt_execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM otel_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM otel_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -747,7 +747,7 @@ public function test_mysqli_prepare_procedural(): void $this->assertSame('mysqli_prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM unknown_db.users', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM unknown_db.users', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::EXCEPTION_TYPE => \PHPUnit\Framework\Error\Warning::class, ]); @@ -787,7 +787,7 @@ public function test_mysqli_transaction_rollback_objective(): void $offset++; $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 42000123)", + TraceAttributes::DB_QUERY_TEXT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 42000123)", TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -798,7 +798,7 @@ public function test_mysqli_transaction_rollback_objective(): void $offset++; $this->assertSame('mysqli::prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -810,7 +810,7 @@ public function test_mysqli_transaction_rollback_objective(): void $offset++; $this->assertSame('mysqli_stmt::execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -857,7 +857,7 @@ public function test_mysqli_transaction_rollback_procedural(): void $offset++; $this->assertSame('mysqli_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 76000001)", + TraceAttributes::DB_QUERY_TEXT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 76000001)", TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -868,7 +868,7 @@ public function test_mysqli_transaction_rollback_procedural(): void $offset++; $this->assertSame('mysqli_prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -880,7 +880,7 @@ public function test_mysqli_transaction_rollback_procedural(): void $offset++; $this->assertSame('mysqli_stmt_execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -929,7 +929,7 @@ public function test_mysqli_transaction_commit_objective(): void $offset++; $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 76000001)", + TraceAttributes::DB_QUERY_TEXT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 76000001)", TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -941,7 +941,7 @@ public function test_mysqli_transaction_commit_objective(): void $offset++; $this->assertSame('mysqli::prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -951,7 +951,7 @@ public function test_mysqli_transaction_commit_objective(): void $offset++; $this->assertSame('mysqli_stmt::execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -1000,7 +1000,7 @@ public function test_mysqli_transaction_commit_procedural(): void $offset++; $this->assertSame('mysqli_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 76000001)", + TraceAttributes::DB_QUERY_TEXT => "INSERT INTO language(Code, Speakers) VALUES ('DE', 76000001)", TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -1011,7 +1011,7 @@ public function test_mysqli_transaction_commit_procedural(): void $offset++; $this->assertSame('mysqli_prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -1021,7 +1021,7 @@ public function test_mysqli_transaction_commit_procedural(): void $offset++; $this->assertSame('mysqli_stmt_execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', + TraceAttributes::DB_QUERY_TEXT => 'INSERT INTO language(Code, Speakers) VALUES (?,?)', TraceAttributes::DB_OPERATION_NAME => 'INSERT', ]); @@ -1058,7 +1058,7 @@ public function test_mysqli_stmt_execute_objective(): void $offset++; $this->assertSame('mysqli_stmt::execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => "SELECT email FROM users WHERE name='John Doe'", + TraceAttributes::DB_QUERY_TEXT => "SELECT email FROM users WHERE name='John Doe'", TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -1072,7 +1072,7 @@ public function test_mysqli_stmt_execute_objective(): void $offset++; $this->assertSame('mysqli_stmt::execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => "SELECT email FROM users WHERE name='John Doe'", + TraceAttributes::DB_QUERY_TEXT => "SELECT email FROM users WHERE name='John Doe'", TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -1099,7 +1099,7 @@ public function test_mysqli_stmt_execute_procedural(): void $offset++; $this->assertSame('mysqli_stmt_execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => "SELECT email FROM users WHERE name='John Doe'", + TraceAttributes::DB_QUERY_TEXT => "SELECT email FROM users WHERE name='John Doe'", TraceAttributes::DB_OPERATION_NAME => 'SELECT', ]); @@ -1133,7 +1133,7 @@ public function test_mysqli_multiquery_with_calls(): void $offset++; $this->assertSame('mysqli::multi_query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'DROP PROCEDURE IF EXISTS get_message;', + TraceAttributes::DB_QUERY_TEXT => 'DROP PROCEDURE IF EXISTS get_message;', TraceAttributes::DB_OPERATION_NAME => 'DROP', ]); @@ -1149,14 +1149,14 @@ public function test_mysqli_multiquery_with_calls(): void TraceAttributes::DB_OPERATION_NAME => 'CREATE', ]); $span = $this->storage->offsetGet($offset); - $this->assertStringStartsWith('CREATE PROCEDURE', $span->getAttributes()->get(TraceAttributes::DB_STATEMENT)); - $this->assertStringEndsWith('END;', $span->getAttributes()->get(TraceAttributes::DB_STATEMENT)); + $this->assertStringStartsWith('CREATE PROCEDURE', $span->getAttributes()->get(TraceAttributes::DB_QUERY_TEXT)); + $this->assertStringEndsWith('END;', $span->getAttributes()->get(TraceAttributes::DB_QUERY_TEXT)); $stmt = $mysqli->prepare('CALL get_message();'); $offset++; $this->assertSame('mysqli::prepare', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'CALL get_message();', + TraceAttributes::DB_QUERY_TEXT => 'CALL get_message();', TraceAttributes::DB_OPERATION_NAME => 'CALL', ]); @@ -1165,7 +1165,7 @@ public function test_mysqli_multiquery_with_calls(): void $offset++; $this->assertSame('mysqli_stmt::execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'CALL get_message();', + TraceAttributes::DB_QUERY_TEXT => 'CALL get_message();', TraceAttributes::DB_OPERATION_NAME => 'CALL', ]); @@ -1182,14 +1182,14 @@ public function test_mysqli_multiquery_with_calls(): void $offset++; $this->assertSame('mysqli_stmt::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'CALL get_message();', + TraceAttributes::DB_QUERY_TEXT => 'CALL get_message();', TraceAttributes::DB_OPERATION_NAME => 'CALL', ]); $offset++; $this->assertSame('mysqli_stmt::next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'CALL get_message();', + TraceAttributes::DB_QUERY_TEXT => 'CALL get_message();', TraceAttributes::DB_OPERATION_NAME => 'CALL', ]); @@ -1200,7 +1200,7 @@ public function test_mysqli_multiquery_with_calls(): void $offset++; $this->assertSame('mysqli_stmt_execute', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'CALL get_message();', + TraceAttributes::DB_QUERY_TEXT => 'CALL get_message();', TraceAttributes::DB_OPERATION_NAME => 'CALL', ]); @@ -1217,14 +1217,14 @@ public function test_mysqli_multiquery_with_calls(): void $offset++; $this->assertSame('mysqli_stmt_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'CALL get_message();', + TraceAttributes::DB_QUERY_TEXT => 'CALL get_message();', TraceAttributes::DB_OPERATION_NAME => 'CALL', ]); $offset++; $this->assertSame('mysqli_stmt_next_result', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'CALL get_message();', + TraceAttributes::DB_QUERY_TEXT => 'CALL get_message();', TraceAttributes::DB_OPERATION_NAME => 'CALL', ]); @@ -1251,12 +1251,12 @@ public function test_mysqli_change_user(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => $this->user, + //TraceAttributes::DB_USER => $this->user, TraceAttributes::DB_NAMESPACE => $this->database, - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', ]); $mysqli->change_user('otel_user2', $this->passwd, 'otel_db2'); @@ -1270,12 +1270,12 @@ public function test_mysqli_change_user(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => 'otel_user2', + //TraceAttributes::DB_USER => 'otel_user2', TraceAttributes::DB_NAMESPACE => 'otel_db2', - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', ]); mysqli_change_user($mysqli, $this->user, $this->passwd, $this->database); @@ -1289,12 +1289,12 @@ public function test_mysqli_change_user(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => $this->user, + //TraceAttributes::DB_USER => $this->user, TraceAttributes::DB_NAMESPACE => $this->database, - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', ]); try { @@ -1315,12 +1315,12 @@ public function test_mysqli_change_user(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT CURRENT_USER();', + TraceAttributes::DB_QUERY_TEXT => 'SELECT CURRENT_USER();', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => $this->user, + //TraceAttributes::DB_USER => $this->user, TraceAttributes::DB_NAMESPACE => $this->database, - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); @@ -1346,12 +1346,12 @@ public function test_mysqli_select_db(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM users;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM users;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => $this->user, + //TraceAttributes::DB_USER => $this->user, TraceAttributes::DB_NAMESPACE => $this->database, - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', ]); $mysqli->select_db('otel_db2'); @@ -1364,12 +1364,12 @@ public function test_mysqli_select_db(): void $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM users;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM users;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => $this->user, + //TraceAttributes::DB_USER => $this->user, TraceAttributes::DB_NAMESPACE => 'otel_db2', - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', TraceAttributes::EXCEPTION_TYPE => mysqli_sql_exception::class, ]); } @@ -1385,12 +1385,12 @@ public function test_mysqli_select_db(): void $offset++; $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM users;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM users;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => $this->user, + //TraceAttributes::DB_USER => $this->user, TraceAttributes::DB_NAMESPACE => $this->database, - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', ]); try { @@ -1408,12 +1408,12 @@ public function test_mysqli_select_db(): void $offset++; $this->assertSame('mysqli::query', $this->storage->offsetGet($offset)->getName()); $this->assertAttributes($offset, [ - TraceAttributes::DB_STATEMENT => 'SELECT * FROM users;', + TraceAttributes::DB_QUERY_TEXT => 'SELECT * FROM users;', TraceAttributes::DB_OPERATION_NAME => 'SELECT', TraceAttributes::SERVER_ADDRESS => $this->mysqlHost, - TraceAttributes::DB_USER => $this->user, + //TraceAttributes::DB_USER => $this->user, TraceAttributes::DB_NAMESPACE => $this->database, - TraceAttributes::DB_SYSTEM => 'mysql', + TraceAttributes::DB_SYSTEM_NAME => 'mysql', ]); $offset++; diff --git a/src/Instrumentation/OpenAIPHP/.phan/config.php b/src/Instrumentation/OpenAIPHP/.phan/config.php new file mode 100644 index 000000000..6473a9aa8 --- /dev/null +++ b/src/Instrumentation/OpenAIPHP/.phan/config.php @@ -0,0 +1,371 @@ + '8.1', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/OpenAIPHP/composer.json b/src/Instrumentation/OpenAIPHP/composer.json index e850e1a3a..00c03b2f4 100644 --- a/src/Instrumentation/OpenAIPHP/composer.json +++ b/src/Instrumentation/OpenAIPHP/composer.json @@ -7,13 +7,14 @@ "readme": "./README.md", "license": "Apache-2.0", "minimum-stability": "dev", + "prefer-stable": true, "require": { "php": "^8.1", "composer-runtime-api": "^2.0", "ext-opentelemetry": "*", "openai-php/client": "*", "open-telemetry/api": "^1", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", diff --git a/src/Instrumentation/OpenAIPHP/src/OpenAIPHPInstrumentation.php b/src/Instrumentation/OpenAIPHP/src/OpenAIPHPInstrumentation.php index c08979bac..0379d92df 100644 --- a/src/Instrumentation/OpenAIPHP/src/OpenAIPHPInstrumentation.php +++ b/src/Instrumentation/OpenAIPHP/src/OpenAIPHPInstrumentation.php @@ -23,6 +23,7 @@ use OpenTelemetry\Context\ContextInterface; use function OpenTelemetry\Instrumentation\hook; use OpenTelemetry\SemConv\TraceAttributes; +use OpenTelemetry\SemConv\Version; use Throwable; final class OpenAIPHPInstrumentation @@ -39,7 +40,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.openaiphp', InstalledVersions::getVersion('open-telemetry/opentelemetry-auto-openai-php'), - 'https://opentelemetry.io/schemas/1.24.0', + Version::VERSION_1_30_0->url(), ); self::$totalTokensCounter = $instrumentation->meter()->createCounter( @@ -91,10 +92,10 @@ private static function hookApi(CachedInstrumentation $instrumentation, $class, ->spanBuilder(sprintf('openai %s', $resource . '/' . $operation)) ->setSpanKind(SpanKind::KIND_INTERNAL) // code - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) // openai ->setAttribute(OpenAIAttributes::OPENAI_RESOURCE, $resource . '/' . $operation) ; diff --git a/src/Instrumentation/PDO/.phan/config.php b/src/Instrumentation/PDO/.phan/config.php new file mode 100644 index 000000000..6bf6f35c4 --- /dev/null +++ b/src/Instrumentation/PDO/.phan/config.php @@ -0,0 +1,371 @@ + '8.2', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/PDO/composer.json b/src/Instrumentation/PDO/composer.json index 501947f2b..58ff8420f 100644 --- a/src/Instrumentation/PDO/composer.json +++ b/src/Instrumentation/PDO/composer.json @@ -13,7 +13,7 @@ "ext-pdo": "*", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "symfony/polyfill-mbstring": "^1.31" }, "suggest": { diff --git a/src/Instrumentation/PDO/src/PDOInstrumentation.php b/src/Instrumentation/PDO/src/PDOInstrumentation.php index 312c3104f..8ddc6b6f6 100644 --- a/src/Instrumentation/PDO/src/PDOInstrumentation.php +++ b/src/Instrumentation/PDO/src/PDOInstrumentation.php @@ -12,6 +12,7 @@ use OpenTelemetry\Context\Context; use function OpenTelemetry\Instrumentation\hook; use OpenTelemetry\SemConv\TraceAttributes; +use OpenTelemetry\SemConv\Version; use PDO; use PDOStatement; use Throwable; @@ -25,7 +26,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.pdo', null, - 'https://opentelemetry.io/schemas/1.24.0' + Version::VERSION_1_30_0->url(), ); $pdoTracker = new PDOTracker(); @@ -39,8 +40,8 @@ public static function register(): void if ($class === PDO::class) { //@todo split params[0] into host + port, replace deprecated trace attribute $builder - ->setAttribute(TraceAttributes::DB_CONNECTION_STRING, $params[0] ?? 'unknown') - ->setAttribute(TraceAttributes::DB_USER, $params[1] ?? 'unknown'); + ->setAttribute(TraceAttributes::SERVER_ADDRESS, $params[0] ?? 'unknown') + ->setAttribute(TraceAttributes::SERVER_PORT, $params[0] ?? null); } $parent = Context::getCurrent(); $span = $builder->startSpan(); @@ -70,7 +71,7 @@ public static function register(): void $builder = self::makeBuilder($instrumentation, 'PDO::query', $function, $class, $filename, $lineno) ->setSpanKind(SpanKind::KIND_CLIENT); if ($class === PDO::class) { - $builder->setAttribute(TraceAttributes::DB_STATEMENT, mb_convert_encoding($params[0] ?? 'undefined', 'UTF-8')); + $builder->setAttribute(TraceAttributes::DB_QUERY_TEXT, mb_convert_encoding($params[0] ?? 'undefined', 'UTF-8')); } $parent = Context::getCurrent(); $span = $builder->startSpan(); @@ -93,7 +94,7 @@ public static function register(): void $builder = self::makeBuilder($instrumentation, 'PDO::exec', $function, $class, $filename, $lineno) ->setSpanKind(SpanKind::KIND_CLIENT); if ($class === PDO::class) { - $builder->setAttribute(TraceAttributes::DB_STATEMENT, mb_convert_encoding($params[0] ?? 'undefined', 'UTF-8')); + $builder->setAttribute(TraceAttributes::DB_QUERY_TEXT, mb_convert_encoding($params[0] ?? 'undefined', 'UTF-8')); } $parent = Context::getCurrent(); $span = $builder->startSpan(); @@ -116,7 +117,7 @@ public static function register(): void $builder = self::makeBuilder($instrumentation, 'PDO::prepare', $function, $class, $filename, $lineno) ->setSpanKind(SpanKind::KIND_CLIENT); if ($class === PDO::class) { - $builder->setAttribute(TraceAttributes::DB_STATEMENT, mb_convert_encoding($params[0] ?? 'undefined', 'UTF-8')); + $builder->setAttribute(TraceAttributes::DB_QUERY_TEXT, mb_convert_encoding($params[0] ?? 'undefined', 'UTF-8')); } $parent = Context::getCurrent(); $span = $builder->startSpan(); @@ -248,10 +249,10 @@ private static function makeBuilder( /** @psalm-suppress ArgumentTypeCoercion */ return $instrumentation->tracer() ->spanBuilder($name) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); } private static function end(?Throwable $exception): void { @@ -262,7 +263,7 @@ private static function end(?Throwable $exception): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/PDO/src/PDOTracker.php b/src/Instrumentation/PDO/src/PDOTracker.php index ecf78bdef..96761f3c4 100644 --- a/src/Instrumentation/PDO/src/PDOTracker.php +++ b/src/Instrumentation/PDO/src/PDOTracker.php @@ -11,6 +11,9 @@ use WeakMap; use WeakReference; +/** + * @phan-file-suppress PhanNonClassMethodCall,PhanTypeArraySuspicious + */ final class PDOTracker { /** @@ -70,11 +73,11 @@ public function trackPdoAttributes(PDO $pdo, string $dsn): iterable /** @var string $dbSystem */ $dbSystem = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME); /** @psalm-suppress InvalidArrayAssignment */ - $attributes[TraceAttributes::DB_SYSTEM] = self::mapDriverNameToAttribute($dbSystem); + $attributes[TraceAttributes::DB_SYSTEM_NAME] = self::mapDriverNameToAttribute($dbSystem); } catch (\Error) { - // if we catched an exception, the driver is likely not supporting the operation, default to "other" + // if we caught an exception, the driver is likely not supporting the operation, default to "other" /** @psalm-suppress PossiblyInvalidArrayAssignment */ - $attributes[TraceAttributes::DB_SYSTEM] = 'other_sql'; + $attributes[TraceAttributes::DB_SYSTEM_NAME] = 'other_sql'; } $this->pdoToAttributesMap[$pdo] = $attributes; @@ -126,39 +129,39 @@ private static function extractAttributesFromDSN(string $dsn): iterable { $attributes = []; if (str_starts_with($dsn, 'sqlite::memory:')) { - $attributes[TraceAttributes::DB_SYSTEM] = 'sqlite'; - $attributes[TraceAttributes::DB_NAME] = 'memory'; + $attributes[TraceAttributes::DB_SYSTEM_NAME] = 'sqlite'; + $attributes[TraceAttributes::DB_NAMESPACE] = 'memory'; return $attributes; } elseif (str_starts_with($dsn, 'sqlite:')) { - $attributes[TraceAttributes::DB_SYSTEM] = 'sqlite'; - $attributes[TraceAttributes::DB_NAME] = substr($dsn, 7); + $attributes[TraceAttributes::DB_SYSTEM_NAME] = 'sqlite'; + $attributes[TraceAttributes::DB_NAMESPACE] = substr($dsn, 7); return $attributes; } elseif (str_starts_with($dsn, 'sqlite')) { - $attributes[TraceAttributes::DB_SYSTEM] = 'sqlite'; - $attributes[TraceAttributes::DB_NAME] = $dsn; + $attributes[TraceAttributes::DB_SYSTEM_NAME] = 'sqlite'; + $attributes[TraceAttributes::DB_NAMESPACE] = $dsn; return $attributes; } - if (preg_match('/user=([^;]*)/', $dsn, $matches)) { + //deprecated, no replacement at this time + /*if (preg_match('/user=([^;]*)/', $dsn, $matches)) { $user = $matches[1]; if ($user !== '') { $attributes[TraceAttributes::DB_USER] = $user; } - } + }*/ if (preg_match('/host=([^;]*)/', $dsn, $matches)) { $host = $matches[1]; if ($host !== '') { - $attributes[TraceAttributes::NET_PEER_NAME] = $host; $attributes[TraceAttributes::SERVER_ADDRESS] = $host; } } if (preg_match('/dbname=([^;]*)/', $dsn, $matches)) { $dbname = $matches[1]; if ($dbname !== '') { - $attributes[TraceAttributes::DB_NAME] = $dbname; + $attributes[TraceAttributes::DB_NAMESPACE] = $dbname; } } diff --git a/src/Instrumentation/PDO/tests/Integration/PDOInstrumentationTest.php b/src/Instrumentation/PDO/tests/Integration/PDOInstrumentationTest.php index 3fcd1b3c4..ba43e304a 100644 --- a/src/Instrumentation/PDO/tests/Integration/PDOInstrumentationTest.php +++ b/src/Instrumentation/PDO/tests/Integration/PDOInstrumentationTest.php @@ -69,7 +69,7 @@ public function test_pdo_construct(): void $this->assertCount(1, $this->storage); $span = $this->storage->offsetGet(0); $this->assertSame('PDO::__construct', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); } public function test_constructor_exception(): void @@ -87,32 +87,32 @@ public function test_statement_execution(): void $db->exec($statement); $span = $this->storage->offsetGet(1); $this->assertSame('PDO::exec', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertFalse($db->inTransaction()); $this->assertCount(2, $this->storage); $sth = $db->prepare('SELECT * FROM `technology`'); $span = $this->storage->offsetGet(2); $this->assertSame('PDO::prepare', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertCount(3, $this->storage); $sth->execute(); $span = $this->storage->offsetGet(3); $this->assertSame('PDOStatement::execute', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertCount(4, $this->storage); $sth->fetchAll(); $span = $this->storage->offsetGet(4); $this->assertSame('PDOStatement::fetchAll', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertCount(5, $this->storage); $db->query('SELECT * FROM `technology`'); $span = $this->storage->offsetGet(5); $this->assertSame('PDO::query', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertCount(6, $this->storage); } @@ -122,7 +122,7 @@ public function test_transaction(): void $result = $db->beginTransaction(); $span = $this->storage->offsetGet(1); $this->assertSame('PDO::beginTransaction', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertCount(2, $this->storage); $this->assertSame($result, true); @@ -131,7 +131,7 @@ public function test_transaction(): void $result = $db->commit(); $span = $this->storage->offsetGet(3); $this->assertSame('PDO::commit', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertCount(4, $this->storage); $this->assertTrue($result); @@ -143,7 +143,7 @@ public function test_transaction(): void $result = $db->rollback(); $span = $this->storage->offsetGet(6); $this->assertSame('PDO::rollBack', $span->getName()); - $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM)); + $this->assertEquals('sqlite', $span->getAttributes()->get(TraceAttributes::DB_SYSTEM_NAME)); $this->assertCount(7, $this->storage); $this->assertTrue($result); $this->assertFalse($db->inTransaction()); @@ -201,17 +201,17 @@ public function test_encode_db_statement_as_utf8(): void $db->prepare("SELECT id FROM technology WHERE id = '{$non_utf8_id}'"); $span_db_prepare = $this->storage->offsetGet(2); - $this->assertTrue(mb_check_encoding($span_db_prepare->getAttributes()->get(TraceAttributes::DB_STATEMENT), 'UTF-8')); + $this->assertTrue(mb_check_encoding($span_db_prepare->getAttributes()->get(TraceAttributes::DB_QUERY_TEXT), 'UTF-8')); $this->assertCount(3, $this->storage); $db->query("SELECT id FROM technology WHERE id = '{$non_utf8_id}'"); $span_db_query = $this->storage->offsetGet(3); - $this->assertTrue(mb_check_encoding($span_db_query->getAttributes()->get(TraceAttributes::DB_STATEMENT), 'UTF-8')); + $this->assertTrue(mb_check_encoding($span_db_query->getAttributes()->get(TraceAttributes::DB_QUERY_TEXT), 'UTF-8')); $this->assertCount(4, $this->storage); $db->exec("SELECT id FROM technology WHERE id = '{$non_utf8_id}'"); $span_db_exec = $this->storage->offsetGet(4); - $this->assertTrue(mb_check_encoding($span_db_exec->getAttributes()->get(TraceAttributes::DB_STATEMENT), 'UTF-8')); + $this->assertTrue(mb_check_encoding($span_db_exec->getAttributes()->get(TraceAttributes::DB_QUERY_TEXT), 'UTF-8')); $this->assertCount(5, $this->storage); } } diff --git a/src/Instrumentation/PDO/tests/Unit/PDOAttributeTrackerTest.php b/src/Instrumentation/PDO/tests/Unit/PDOAttributeTrackerTest.php index 7031b333a..44937122e 100644 --- a/src/Instrumentation/PDO/tests/Unit/PDOAttributeTrackerTest.php +++ b/src/Instrumentation/PDO/tests/Unit/PDOAttributeTrackerTest.php @@ -22,20 +22,20 @@ public function testPdoCanBeTracked(): void $span = Span::getInvalid(); /** @psalm-suppress InvalidArgument */ - $this->assertContains(TraceAttributes::DB_SYSTEM, array_keys($attributes)); + $this->assertContains(TraceAttributes::DB_SYSTEM_NAME, array_keys($attributes)); /** @psalm-suppress InvalidArgument */ - $this->assertContains(TraceAttributes::DB_NAME, array_keys($attributes)); + $this->assertContains(TraceAttributes::DB_NAMESPACE, array_keys($attributes)); /** @psalm-suppress InvalidArrayAccess */ - $this->assertSame('memory', $attributes[TraceAttributes::DB_NAME]); + $this->assertSame('memory', $attributes[TraceAttributes::DB_NAMESPACE]); $stmt = $pdo->prepare('SELECT NULL LIMIT 0;'); $objectMap->trackStatement($stmt, $pdo, $span->getContext()); $attributes = $objectMap->trackedAttributesForStatement($stmt); /** @psalm-suppress InvalidArgument */ - $this->assertContains(TraceAttributes::DB_SYSTEM, array_keys($attributes)); + $this->assertContains(TraceAttributes::DB_SYSTEM_NAME, array_keys($attributes)); /** @psalm-suppress InvalidArrayAccess */ - $this->assertEquals('sqlite', $attributes[TraceAttributes::DB_SYSTEM]); + $this->assertEquals('sqlite', $attributes[TraceAttributes::DB_SYSTEM_NAME]); $this->assertSame($span->getContext(), $objectMap->getSpanForPreparedStatement($stmt)); } } diff --git a/src/Instrumentation/Psr14/.phan/config.php b/src/Instrumentation/Psr14/.phan/config.php new file mode 100644 index 000000000..da2ac2d99 --- /dev/null +++ b/src/Instrumentation/Psr14/.phan/config.php @@ -0,0 +1,371 @@ + '8.0', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/Psr14/composer.json b/src/Instrumentation/Psr14/composer.json index 1b3449548..84002adbe 100644 --- a/src/Instrumentation/Psr14/composer.json +++ b/src/Instrumentation/Psr14/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "psr/event-dispatcher": "^1", "composer-runtime-api": "^2.0" }, diff --git a/src/Instrumentation/Psr14/src/Psr14Instrumentation.php b/src/Instrumentation/Psr14/src/Psr14Instrumentation.php index 1d0a239f2..e15459942 100644 --- a/src/Instrumentation/Psr14/src/Psr14Instrumentation.php +++ b/src/Instrumentation/Psr14/src/Psr14Instrumentation.php @@ -27,7 +27,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.psr14', InstalledVersions::getVersion('open-telemetry/opentelemetry-auto-psr14'), - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0', ); /** @@ -40,10 +40,10 @@ public static function register(): void $event = is_object($params[0]) ? $params[0] : null; $builder = $instrumentation->tracer() ->spanBuilder(sprintf('event %s', $event ? $event::class : 'unknown')) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); if ($event) { $builder->setAttribute('psr14.event.name', $event::class); @@ -63,7 +63,7 @@ public static function register(): void $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Psr15/.phan/config.php b/src/Instrumentation/Psr15/.phan/config.php new file mode 100644 index 000000000..da2ac2d99 --- /dev/null +++ b/src/Instrumentation/Psr15/.phan/config.php @@ -0,0 +1,371 @@ + '8.0', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/Psr15/composer.json b/src/Instrumentation/Psr15/composer.json index 0489d10ee..b9e8710f2 100644 --- a/src/Instrumentation/Psr15/composer.json +++ b/src/Instrumentation/Psr15/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "psr/http-server-middleware": "^1" }, "autoload": { diff --git a/src/Instrumentation/Psr15/src/Psr15Instrumentation.php b/src/Instrumentation/Psr15/src/Psr15Instrumentation.php index de59e64aa..025966fde 100644 --- a/src/Instrumentation/Psr15/src/Psr15Instrumentation.php +++ b/src/Instrumentation/Psr15/src/Psr15Instrumentation.php @@ -28,7 +28,11 @@ class Psr15Instrumentation public static function register(): void { - $instrumentation = new CachedInstrumentation('io.opentelemetry.contrib.php.psr15'); + $instrumentation = new CachedInstrumentation( + 'io.opentelemetry.contrib.php.psr15', + null, + 'https://opentelemetry.io/schemas/1.30.0', + ); /** * Create a span for each psr-15 middleware that is executed. @@ -38,10 +42,10 @@ public static function register(): void 'process', pre: static function (MiddlewareInterface $middleware, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($instrumentation) { $span = $instrumentation->tracer()->spanBuilder(sprintf('%s::%s', $class, $function)) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->startSpan(); Context::storage()->attach($span->storeInContext(Context::getCurrent())); @@ -54,7 +58,7 @@ public static function register(): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } $span->end(); @@ -79,10 +83,10 @@ public static function register(): void : sprintf('%s', $request?->getMethod() ?? 'unknown') ) ->setSpanKind(SpanKind::KIND_SERVER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); if (!$root && $request) { //create http root span @@ -114,7 +118,7 @@ public static function register(): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } if ($response) { diff --git a/src/Instrumentation/Psr16/composer.json b/src/Instrumentation/Psr16/composer.json index d11250ca3..5e75650ff 100644 --- a/src/Instrumentation/Psr16/composer.json +++ b/src/Instrumentation/Psr16/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "psr/simple-cache": "^1 || ^2 || ^3", "composer-runtime-api": "^2.0" }, diff --git a/src/Instrumentation/Psr16/src/Psr16Instrumentation.php b/src/Instrumentation/Psr16/src/Psr16Instrumentation.php index 4f598a9cd..f2f55f3b1 100644 --- a/src/Instrumentation/Psr16/src/Psr16Instrumentation.php +++ b/src/Instrumentation/Psr16/src/Psr16Instrumentation.php @@ -28,7 +28,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.psr16', InstalledVersions::getVersion('open-telemetry/opentelemetry-auto-psr16'), - 'https://opentelemetry.io/schemas/1.24.0', + 'https://opentelemetry.io/schemas/1.30.0', ); $pre = static function (CacheInterface $cacheItem, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($instrumentation) { @@ -68,10 +68,10 @@ private static function makeSpanBuilder( return $instrumentation->tracer() ->spanBuilder($name) ->setSpanKind(SpanKind::KIND_INTERNAL) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttribute('cache.operation', $name); } @@ -86,7 +86,7 @@ private static function end(?Throwable $exception): void $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Psr18/.phan/config.php b/src/Instrumentation/Psr18/.phan/config.php new file mode 100644 index 000000000..da2ac2d99 --- /dev/null +++ b/src/Instrumentation/Psr18/.phan/config.php @@ -0,0 +1,371 @@ + '8.0', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/Psr18/composer.json b/src/Instrumentation/Psr18/composer.json index 273e0d836..31f5940f8 100644 --- a/src/Instrumentation/Psr18/composer.json +++ b/src/Instrumentation/Psr18/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "psr/http-client": "^1" }, "autoload": { diff --git a/src/Instrumentation/Psr18/src/Psr18Instrumentation.php b/src/Instrumentation/Psr18/src/Psr18Instrumentation.php index 0be3127aa..3d085bd5f 100644 --- a/src/Instrumentation/Psr18/src/Psr18Instrumentation.php +++ b/src/Instrumentation/Psr18/src/Psr18Instrumentation.php @@ -27,7 +27,10 @@ class Psr18Instrumentation public static function register(): void { - $instrumentation = new CachedInstrumentation('io.opentelemetry.contrib.php.psr18', schemaUrl: TraceAttributes::SCHEMA_URL); + $instrumentation = new CachedInstrumentation( + 'io.opentelemetry.contrib.php.psr18', + 'https://opentelemetry.io/schemas/1.30.0', + ); hook( ClientInterface::class, @@ -56,10 +59,10 @@ public static function register(): void ->setAttribute(TraceAttributes::HTTP_REQUEST_BODY_SIZE, $request->getHeaderLine('Content-Length')) ->setAttribute(TraceAttributes::SERVER_ADDRESS, $request->getUri()->getHost()) ->setAttribute(TraceAttributes::SERVER_PORT, $request->getUri()->getPort()) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ; foreach ($propagator->fields() as $field) { @@ -110,7 +113,7 @@ public static function register(): void } } if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Psr3/composer.json b/src/Instrumentation/Psr3/composer.json index 019b1c00d..971ec8828 100644 --- a/src/Instrumentation/Psr3/composer.json +++ b/src/Instrumentation/Psr3/composer.json @@ -16,10 +16,10 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "php": "^8.0", + "php": "^8.1", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "psr/log": "^1 || ^2 || ^3" }, "autoload": { diff --git a/src/Instrumentation/Psr3/src/Psr3Instrumentation.php b/src/Instrumentation/Psr3/src/Psr3Instrumentation.php index 2cca4e8e6..e39b9e9ba 100644 --- a/src/Instrumentation/Psr3/src/Psr3Instrumentation.php +++ b/src/Instrumentation/Psr3/src/Psr3Instrumentation.php @@ -63,7 +63,7 @@ public static function register(): void $instrumentation ??= new CachedInstrumentation( 'io.opentelemetry.contrib.php.psr3', null, - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0', ); if ($function === 'log') { $level = $params[0]; @@ -76,7 +76,7 @@ public static function register(): void } $record = (new API\LogRecord($body)) - ->setSeverityNumber(API\Map\Psr3::severityNumber($level)); + ->setSeverityNumber(API\Severity::fromPsr3($level)); foreach (Formatter::format($context) as $key => $value) { $record->setAttribute((string) $key, $value); } diff --git a/src/Instrumentation/Psr3/tests/phpt/export_apix.phpt b/src/Instrumentation/Psr3/tests/phpt/export_apix.phpt index c506f205f..147c31354 100644 --- a/src/Instrumentation/Psr3/tests/phpt/export_apix.phpt +++ b/src/Instrumentation/Psr3/tests/phpt/export_apix.phpt @@ -42,7 +42,7 @@ $span->end(); "version": null, "attributes": [], "dropped_attributes_count": 0, - "schema_url": "https:\/\/opentelemetry.io\/schemas\/1.24.0", + "schema_url": "https:\/\/opentelemetry.io\/schemas\/%s", "logs": [ { "timestamp": null, diff --git a/src/Instrumentation/Psr3/tests/phpt/export_cake.phpt b/src/Instrumentation/Psr3/tests/phpt/export_cake.phpt index 1c190b1ec..73c3cdc3a 100644 --- a/src/Instrumentation/Psr3/tests/phpt/export_cake.phpt +++ b/src/Instrumentation/Psr3/tests/phpt/export_cake.phpt @@ -45,7 +45,7 @@ $span->end(); "version": null, "attributes": [], "dropped_attributes_count": 0, - "schema_url": "https:\/\/opentelemetry.io\/schemas\/1.24.0", + "schema_url": "https:\/\/opentelemetry.io\/schemas\/%s", "logs": [ { "timestamp": null, diff --git a/src/Instrumentation/Psr3/tests/phpt/export_monolog.phpt b/src/Instrumentation/Psr3/tests/phpt/export_monolog.phpt index 0ac95f040..9506318e1 100644 --- a/src/Instrumentation/Psr3/tests/phpt/export_monolog.phpt +++ b/src/Instrumentation/Psr3/tests/phpt/export_monolog.phpt @@ -39,7 +39,7 @@ $span->end(); "version": null, "attributes": [], "dropped_attributes_count": 0, - "schema_url": "https:\/\/opentelemetry.io\/schemas\/1.24.0", + "schema_url": "https:\/\/opentelemetry.io\/schemas\/%s", "logs": [ { "timestamp": null, diff --git a/src/Instrumentation/Psr3/tests/phpt/export_multi.phpt b/src/Instrumentation/Psr3/tests/phpt/export_multi.phpt index 8680d8eda..2d5dfa709 100644 --- a/src/Instrumentation/Psr3/tests/phpt/export_multi.phpt +++ b/src/Instrumentation/Psr3/tests/phpt/export_multi.phpt @@ -54,7 +54,7 @@ Message context: "version": null, "attributes": [], "dropped_attributes_count": 0, - "schema_url": "https:\/\/opentelemetry.io\/schemas\/1.24.0", + "schema_url": "https:\/\/opentelemetry.io\/schemas\/%s", "logs": [ { "timestamp": null, diff --git a/src/Instrumentation/Psr3/tests/phpt/export_symfony.phpt b/src/Instrumentation/Psr3/tests/phpt/export_symfony.phpt index d43517ffe..34205fca4 100644 --- a/src/Instrumentation/Psr3/tests/phpt/export_symfony.phpt +++ b/src/Instrumentation/Psr3/tests/phpt/export_symfony.phpt @@ -41,7 +41,7 @@ $span->end(); "version": null, "attributes": [], "dropped_attributes_count": 0, - "schema_url": "https:\/\/opentelemetry.io\/schemas\/1.24.0", + "schema_url": "https:\/\/opentelemetry.io\/schemas\/%s", "logs": [ { "timestamp": null, diff --git a/src/Instrumentation/Psr3/tests/phpt/export_yii.phpt b/src/Instrumentation/Psr3/tests/phpt/export_yii.phpt index e483d67e8..73618662a 100644 --- a/src/Instrumentation/Psr3/tests/phpt/export_yii.phpt +++ b/src/Instrumentation/Psr3/tests/phpt/export_yii.phpt @@ -59,7 +59,7 @@ Stack trace: "version": null, "attributes": [], "dropped_attributes_count": 0, - "schema_url": "https:\/\/opentelemetry.io\/schemas\/1.24.0", + "schema_url": "https:\/\/opentelemetry.io\/schemas\/%s", "logs": [ { "timestamp": null, diff --git a/src/Instrumentation/Psr6/composer.json b/src/Instrumentation/Psr6/composer.json index 64894c45b..52c5ed9d6 100644 --- a/src/Instrumentation/Psr6/composer.json +++ b/src/Instrumentation/Psr6/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "psr/cache": "^1 || ^2 || ^3", "composer-runtime-api": "^2.0" }, diff --git a/src/Instrumentation/Psr6/src/Psr6Instrumentation.php b/src/Instrumentation/Psr6/src/Psr6Instrumentation.php index 10ac01ca6..3b6727e34 100644 --- a/src/Instrumentation/Psr6/src/Psr6Instrumentation.php +++ b/src/Instrumentation/Psr6/src/Psr6Instrumentation.php @@ -29,7 +29,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.psr6', InstalledVersions::getVersion('open-telemetry/opentelemetry-auto-psr6'), - 'https://opentelemetry.io/schemas/1.24.0', + 'https://opentelemetry.io/schemas/1.30.0', ); $pre = static function (CacheItemPoolInterface $pool, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($instrumentation) { @@ -73,10 +73,10 @@ private static function makeSpanBuilder( return $instrumentation->tracer() ->spanBuilder($function) ->setSpanKind(SpanKind::KIND_INTERNAL) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttribute('cache.operation', $name); } @@ -91,7 +91,7 @@ private static function end(?Throwable $exception): void $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Slim/composer.json b/src/Instrumentation/Slim/composer.json index 4fa380ee3..f2e9cc2b6 100644 --- a/src/Instrumentation/Slim/composer.json +++ b/src/Instrumentation/Slim/composer.json @@ -13,7 +13,7 @@ "ext-opentelemetry": "*", "ext-reflection": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "slim/slim": "^4" }, "require-dev": { diff --git a/src/Instrumentation/Slim/src/SlimInstrumentation.php b/src/Instrumentation/Slim/src/SlimInstrumentation.php index ca860178e..b90a18e70 100644 --- a/src/Instrumentation/Slim/src/SlimInstrumentation.php +++ b/src/Instrumentation/Slim/src/SlimInstrumentation.php @@ -32,8 +32,9 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.slim', null, - 'https://opentelemetry.io/schemas/1.25.0' + 'https://opentelemetry.io/schemas/1.30.0', ); + /** * requires extension >= 1.0.2beta2 * @see https://github.com/open-telemetry/opentelemetry-php-instrumentation/pull/136 @@ -49,10 +50,10 @@ public static function register(): void $builder = $instrumentation->tracer() ->spanBuilder(sprintf('%s', $request?->getMethod() ?? 'unknown')) ->setSpanKind(SpanKind::KIND_SERVER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); if ($request) { $parent = Globals::propagator()->extract($request->getHeaders()); @@ -83,7 +84,7 @@ public static function register(): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } if ($response) { @@ -155,10 +156,10 @@ public static function register(): void $callable = $params[0]; $name = CallableFormatter::format($callable); $builder = $instrumentation->tracer()->spanBuilder($name) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $span = $builder->startSpan(); Context::storage()->attach($span->storeInContext(Context::getCurrent())); }, @@ -170,7 +171,7 @@ public static function register(): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } $span->end(); diff --git a/src/Instrumentation/Symfony/.phan/config.php b/src/Instrumentation/Symfony/.phan/config.php new file mode 100644 index 000000000..da2ac2d99 --- /dev/null +++ b/src/Instrumentation/Symfony/.phan/config.php @@ -0,0 +1,371 @@ + '8.0', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/Symfony/composer.json b/src/Instrumentation/Symfony/composer.json index 63acee77d..ee8e8d35a 100644 --- a/src/Instrumentation/Symfony/composer.json +++ b/src/Instrumentation/Symfony/composer.json @@ -12,7 +12,7 @@ "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "symfony/http-kernel": "*", "symfony/http-client-contracts": "*" }, diff --git a/src/Instrumentation/Symfony/src/HttpClientInstrumentation.php b/src/Instrumentation/Symfony/src/HttpClientInstrumentation.php index 666ac67a2..53b0b77f0 100644 --- a/src/Instrumentation/Symfony/src/HttpClientInstrumentation.php +++ b/src/Instrumentation/Symfony/src/HttpClientInstrumentation.php @@ -16,6 +16,9 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; +/** + * @phan-file-suppress PhanTypeInvalidCallableArraySize + */ final class HttpClientInstrumentation { /** @@ -34,7 +37,11 @@ public static function supportsProgress(string $class): bool public static function register(): void { - $instrumentation = new CachedInstrumentation('io.opentelemetry.contrib.php.symfony_http'); + $instrumentation = new CachedInstrumentation( + 'io.opentelemetry.contrib.php.symfony_http', + null, + 'https://opentelemetry.io/schemas/1.30.0', + ); hook( HttpClientInterface::class, @@ -55,10 +62,10 @@ public static function register(): void ->setAttribute(TraceAttributes::PEER_SERVICE, parse_url((string) $params[1])['host'] ?? null) ->setAttribute(TraceAttributes::URL_FULL, (string) $params[1]) ->setAttribute(TraceAttributes::HTTP_REQUEST_METHOD, $params[0]) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $propagator = Globals::propagator(); $parent = Context::getCurrent(); @@ -129,9 +136,7 @@ public static function register(): void $span = Span::fromContext($scope->context()); if (null !== $exception) { - $span->recordException($exception, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); $span->end(); diff --git a/src/Instrumentation/Symfony/src/MessengerInstrumentation.php b/src/Instrumentation/Symfony/src/MessengerInstrumentation.php index 9b0b8e606..1a3565ef3 100644 --- a/src/Instrumentation/Symfony/src/MessengerInstrumentation.php +++ b/src/Instrumentation/Symfony/src/MessengerInstrumentation.php @@ -34,7 +34,11 @@ final class MessengerInstrumentation public static function register(): void { - $instrumentation = new CachedInstrumentation('io.opentelemetry.contrib.php.symfony_messenger'); + $instrumentation = new CachedInstrumentation( + 'io.opentelemetry.contrib.php.symfony_messenger', + null, + 'https://opentelemetry.io/schemas/1.30.0', + ); /** * MessageBusInterface dispatches messages to the handlers. @@ -59,10 +63,10 @@ public static function register(): void ->tracer() ->spanBuilder(\sprintf('DISPATCH %s', $messageClass)) ->setSpanKind(SpanKind::KIND_PRODUCER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttribute(self::ATTRIBUTE_MESSENGER_BUS, $class) ->setAttribute(self::ATTRIBUTE_MESSENGER_MESSAGE, $messageClass) @@ -93,9 +97,7 @@ public static function register(): void $span = Span::fromContext($scope->context()); if (null !== $exception) { - $span->recordException($exception, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } @@ -126,10 +128,10 @@ public static function register(): void ->tracer() ->spanBuilder(\sprintf('SEND %s', $messageClass)) ->setSpanKind(SpanKind::KIND_PRODUCER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttribute(self::ATTRIBUTE_MESSENGER_TRANSPORT, $class) ->setAttribute(self::ATTRIBUTE_MESSENGER_MESSAGE, $messageClass) @@ -162,9 +164,7 @@ public static function register(): void $span = Span::fromContext($scope->context()); if (null !== $exception) { - $span->recordException($exception, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Symfony/src/SymfonyInstrumentation.php b/src/Instrumentation/Symfony/src/SymfonyInstrumentation.php index 3b2053551..934e6632f 100644 --- a/src/Instrumentation/Symfony/src/SymfonyInstrumentation.php +++ b/src/Instrumentation/Symfony/src/SymfonyInstrumentation.php @@ -24,7 +24,11 @@ final class SymfonyInstrumentation public static function register(): void { - $instrumentation = new CachedInstrumentation('io.opentelemetry.contrib.php.symfony'); + $instrumentation = new CachedInstrumentation( + 'io.opentelemetry.contrib.php.symfony', + null, + 'https://opentelemetry.io/schemas/1.30.0', + ); hook( HttpKernel::class, @@ -48,10 +52,10 @@ public static function register(): void ->tracer() ->spanBuilder($name) ->setSpanKind(($type === HttpKernelInterface::SUB_REQUEST) ? SpanKind::KIND_INTERNAL : SpanKind::KIND_SERVER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); $parent = Context::getCurrent(); if ($request) { @@ -101,9 +105,7 @@ public static function register(): void } if (null !== $exception) { - $span->recordException($exception, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + $span->recordException($exception); if (null !== $response && $response->getStatusCode() >= Response::HTTP_INTERNAL_SERVER_ERROR) { $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } @@ -159,9 +161,7 @@ public static function register(): void $throwable = $params[0]; Span::getCurrent() - ->recordException($throwable, [ - TraceAttributes::EXCEPTION_ESCAPED => true, - ]); + ->recordException($throwable); return $params; }, diff --git a/src/Instrumentation/Wordpress/composer.json b/src/Instrumentation/Wordpress/composer.json index ba499d0a8..30ef2e74d 100644 --- a/src/Instrumentation/Wordpress/composer.json +++ b/src/Instrumentation/Wordpress/composer.json @@ -7,11 +7,12 @@ "readme": "./README.md", "license": "Apache-2.0", "minimum-stability": "dev", + "prefer-stable": true, "require": { "php": "^8.0", "ext-opentelemetry": "*", "open-telemetry/api": "^1.0", - "open-telemetry/sem-conv": "^1.24", + "open-telemetry/sem-conv": "^1.30", "nyholm/psr7": "^1", "nyholm/psr7-server": "^1" }, diff --git a/src/Instrumentation/Wordpress/psalm.xml.dist b/src/Instrumentation/Wordpress/psalm.xml.dist index 155711712..c9c51229e 100644 --- a/src/Instrumentation/Wordpress/psalm.xml.dist +++ b/src/Instrumentation/Wordpress/psalm.xml.dist @@ -12,4 +12,11 @@ + + + + + + + diff --git a/src/Instrumentation/Wordpress/src/WordpressInstrumentation.php b/src/Instrumentation/Wordpress/src/WordpressInstrumentation.php index f2677223a..d23198249 100644 --- a/src/Instrumentation/Wordpress/src/WordpressInstrumentation.php +++ b/src/Instrumentation/Wordpress/src/WordpressInstrumentation.php @@ -17,6 +17,9 @@ use OpenTelemetry\SemConv\TraceAttributes; use Throwable; +/** + * @phan-file-suppress PhanUndeclaredFunction + */ class WordpressInstrumentation { public const NAME = 'wordpress'; @@ -26,7 +29,7 @@ public static function register(): void $instrumentation = new CachedInstrumentation( 'io.opentelemetry.contrib.php.wordpress', null, - 'https://opentelemetry.io/schemas/1.24.0' + 'https://opentelemetry.io/schemas/1.30.0' ); self::_hook($instrumentation, 'WP', 'main', 'WP.main'); @@ -48,9 +51,9 @@ class: 'wpdb', function: '__construct', pre: static function ($object, ?array $params, ?string $class, ?string $function, ?string $filename, ?int $lineno) use ($instrumentation) { $span = self::builder($instrumentation, 'wpdb.__connect', $function, $class, $filename, $lineno) - ->setAttribute(TraceAttributes::DB_USER, $params[0] ?? 'unknown') - ->setAttribute(TraceAttributes::DB_NAME, $params[2] ?? 'unknown') - ->setAttribute(TraceAttributes::DB_SYSTEM, 'mysql') + //->setAttribute(TraceAttributes::DB_USER, $params[0] ?? 'unknown') //deprecated, no replacement + ->setAttribute(TraceAttributes::DB_NAMESPACE, $params[2] ?? 'unknown') + ->setAttribute(TraceAttributes::DB_SYSTEM_NAME, 'mysql') ->startSpan(); Context::storage()->attach($span->storeInContext(Context::getCurrent())); }, @@ -68,7 +71,7 @@ function: 'query', pre: static function ($object, ?array $params, ?string $class, ?string $function, ?string $filename, ?int $lineno) use ($instrumentation) { $span = self::builder($instrumentation, 'wpdb.query', $function, $class, $filename, $lineno) ->setSpanKind(SpanKind::KIND_CLIENT) - ->setAttribute(TraceAttributes::DB_STATEMENT, $params[0] ?? 'undefined') + ->setAttribute(TraceAttributes::DB_QUERY_TEXT, $params[0] ?? 'undefined') ->startSpan(); Context::storage()->attach($span->storeInContext(Context::getCurrent())); }, @@ -157,10 +160,10 @@ private static function builder( /** @psalm-suppress ArgumentTypeCoercion */ return $instrumentation->tracer() ->spanBuilder($name) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno); + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno); } private static function end(?Throwable $exception): void @@ -172,7 +175,7 @@ private static function end(?Throwable $exception): void $scope->detach(); $span = Span::fromContext($scope->context()); if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Instrumentation/Yii/.phan/config.php b/src/Instrumentation/Yii/.phan/config.php new file mode 100644 index 000000000..da2ac2d99 --- /dev/null +++ b/src/Instrumentation/Yii/.phan/config.php @@ -0,0 +1,371 @@ + '8.0', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast to any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'null_casts_as_array' => true, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from `null_casts_as_any_type`. + // If `null_casts_as_any_type` is true, this has no effect. + 'array_casts_as_null' => true, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See `scalar_array_key_cast`. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. `array` can cast to `array` and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => true, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // + // E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]` + // allows casting null to a string, but not vice versa. + // (subset of `scalar_implicit_cast`) + 'scalar_implicit_partial' => [], + + // If enabled, Phan will warn if **any** type in a method invocation's object + // is definitely not an object, + // or if **any** type in an invoked expression is not a callable. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_method_checking' => false, + + // If enabled, Phan will warn if **any** type of the object expression for a property access + // does not contain that property. + 'strict_object_checking' => false, + + // If enabled, Phan will warn if **any** type in the argument's union type + // cannot be cast to a type in the parameter's expected union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_param_checking' => false, + + // If enabled, Phan will warn if **any** type in a property assignment's union type + // cannot be cast to a type in the property's declared union type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_property_checking' => false, + + // If enabled, Phan will warn if **any** type in a returned value's union type + // cannot be cast to the declared return type. + // Setting this to true will introduce numerous false positives + // (and reveal some bugs). + 'strict_return_checking' => false, + + // If true, seemingly undeclared variables in the global + // scope will be ignored. + // + // This is useful for projects with complicated cross-file + // globals that you have no hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => true, + + // Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for, + // but aren't available in the codebase, or from Reflection. + // (may lead to false positives if an extension isn't loaded) + // + // If this is true(default), then Phan will not warn. + // + // Even when this is false, Phan will still infer return values and check parameters of internal functions + // if Phan has the signatures. + 'ignore_undeclared_functions_with_known_signatures' => true, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + // + // If you are migrating from PHP 5 to PHP 7, + // you should also look into using + // [php7cc (no longer maintained)](https://github.com/sstalle/php7cc) + // and [php7mar](https://github.com/Alexia/php7mar), + // which have different backwards compatibility checks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => false, + + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // Affects analysis of the body of the method and the param types passed in by callers. + // + // (*Requires `check_docblock_signature_param_type_match` to be true*) + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires `check_docblock_signature_return_type_match` to be true*) + // + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // + // This setting affects the analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + // If enabled, check all methods that override a + // parent method to make sure its signature is + // compatible with the parent's. + // + // This check can add quite a bit of time to the analysis. + // + // This will also check if final methods are overridden, etc. + 'analyze_signature_compatibility' => true, + + // This setting maps case-insensitive strings to union types. + // + // This is useful if a project uses phpdoc that differs from the phpdoc2 standard. + // + // If the corresponding value is the empty string, + // then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`) + // + // If the corresponding value is not empty, + // then Phan will act as though it saw the corresponding UnionTypes(s) + // when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc. + // + // This matches the **entire string**, not parts of the string. + // (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting) + // + // (These are not aliases, this setting is ignored outside of doc comments). + // (Phan does not check if classes with these names exist) + // + // Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']` + 'phpdoc_type_mapping' => [], + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // Set to true in order to attempt to detect unused variables. + // `dead_code_detection` will also enable unused variable detection. + // + // This has a few known false positives, e.g. for loops or branches. + 'unused_variable_detection' => false, + + // Set to true in order to attempt to detect redundant and impossible conditions. + // + // This has some false positives involving loops, + // variables set in branches of loops, and global variables. + 'redundant_condition_detection' => false, + + // If enabled, Phan will act as though it's certain of real return types of a subset of internal functions, + // even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version). + // + // Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect. + // As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x. + 'assume_real_types_for_internal_functions' => false, + + // If true, this runs a quick version of checks that takes less + // time at the cost of not running as thorough + // of an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with `\`. + // + // (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or + // `Issue::SEVERITY_CRITICAL`. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as `'PhanUndeclaredMethod'`) + // to this deny-list to inhibit them from being reported. + 'suppress_issue_types' => [], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`) + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A list of files that will be excluded from parsing and analysis + // and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [ + 'vendor/composer/composer/src/Composer/InstalledVersions.php' + ], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as well as + // to `exclude_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + 'proto/', + 'thrift/' + ], + + // Enable this to enable checks of require/include statements referring to valid paths. + 'enable_include_path_checks' => true, + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. `['php', 'html', 'htm']`) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then Phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now) + // + // (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute. + // + // Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`) + // + // Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/master/.phan/plugins). + // + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`) + 'plugins' => [ + 'AlwaysReturnPlugin', + 'PregRegexCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in `exclude_analysis_directory_list`, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor' + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project. + 'file_list' => [], +]; diff --git a/src/Instrumentation/Yii/composer.json b/src/Instrumentation/Yii/composer.json index 28faa314a..1d0c58e75 100644 --- a/src/Instrumentation/Yii/composer.json +++ b/src/Instrumentation/Yii/composer.json @@ -11,7 +11,7 @@ "ext-opentelemetry": "*", "yiisoft/yii2": "^2.0.13", "open-telemetry/api": "^1", - "open-telemetry/sem-conv": "^1.24" + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", diff --git a/src/Instrumentation/Yii/psalm.xml.dist b/src/Instrumentation/Yii/psalm.xml.dist index e74348f05..7fce5be16 100644 --- a/src/Instrumentation/Yii/psalm.xml.dist +++ b/src/Instrumentation/Yii/psalm.xml.dist @@ -1,6 +1,8 @@ spanBuilder(sprintf('%s', $request->getMethod())) ->setParent($parent) ->setSpanKind(SpanKind::KIND_SERVER) - ->setAttribute(TraceAttributes::CODE_FUNCTION, $function) + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, $function) ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->setAttribute(TraceAttributes::CODE_FILEPATH, $filename) - ->setAttribute(TraceAttributes::CODE_LINENO, $lineno) + ->setAttribute(TraceAttributes::CODE_LINE_NUMBER, $lineno) ->setAttribute(TraceAttributes::URL_FULL, $request->getAbsoluteUrl()) ->setAttribute(TraceAttributes::HTTP_REQUEST_METHOD, $request->getMethod()) ->setAttribute(TraceAttributes::HTTP_REQUEST_BODY_SIZE, $request->getHeaders()->get('Content-Length', null, true)) @@ -113,7 +113,7 @@ public static function register(): void } if ($exception) { - $span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]); + $span->recordException($exception); $span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage()); } diff --git a/src/Logs/Monolog/composer.json b/src/Logs/Monolog/composer.json index 95f1d0302..f9d87cc5d 100644 --- a/src/Logs/Monolog/composer.json +++ b/src/Logs/Monolog/composer.json @@ -9,6 +9,7 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { + "php": "^8.1", "monolog/monolog": "^1.1|^2|^3", "open-telemetry/api": "^1.0" }, diff --git a/src/Logs/Monolog/src/Handler.php b/src/Logs/Monolog/src/Handler.php index d4fc86f35..60f7568b0 100644 --- a/src/Logs/Monolog/src/Handler.php +++ b/src/Logs/Monolog/src/Handler.php @@ -48,7 +48,7 @@ protected function write($record): void $formatted = $record['formatted']; $logRecord = (new API\LogRecord()) ->setTimestamp((int) $record['datetime']->format('Uu') * 1000) - ->setSeverityNumber(API\Map\Psr3::severityNumber($record['level_name'])) + ->setSeverityNumber(API\Severity::fromPsr3($record['level_name'])) ->setSeverityText($record['level_name']) ->setBody($formatted['message']) ; diff --git a/src/ResourceDetectors/Azure/composer.json b/src/ResourceDetectors/Azure/composer.json index 456016633..dda9a0e38 100644 --- a/src/ResourceDetectors/Azure/composer.json +++ b/src/ResourceDetectors/Azure/composer.json @@ -15,7 +15,8 @@ "require": { "php": "^7.4 || ^8.0", "open-telemetry/api": "^1.0", - "open-telemetry/sdk": "^1.0" + "open-telemetry/sdk": "^1.0", + "open-telemetry/sem-conv": "^1.30" }, "require-dev": { "assertwell/phpunit-global-state": "^0.2.2", diff --git a/src/ResourceDetectors/Azure/src/AppService/Detector.php b/src/ResourceDetectors/Azure/src/AppService/Detector.php index d98a63540..6ed306dfa 100644 --- a/src/ResourceDetectors/Azure/src/AppService/Detector.php +++ b/src/ResourceDetectors/Azure/src/AppService/Detector.php @@ -60,7 +60,7 @@ public function getResource(): ResourceInfo ResourceAttributes::CLOUD_PROVIDER => self::CLOUD_PROVIDER, ResourceAttributes::CLOUD_REGION => getenv(self::ENV_REGION_NAME_KEY), ResourceAttributes::CLOUD_RESOURCE_ID => self::generateAzureResourceUri($name, $groupName, $subscriptionId), - ResourceAttributes::DEPLOYMENT_ENVIRONMENT => getenv(self::ENV_WEBSITE_SLOT_NAME_KEY), + ResourceAttributes::DEPLOYMENT_ENVIRONMENT_NAME => getenv(self::ENV_WEBSITE_SLOT_NAME_KEY), ResourceAttributes::HOST_ID => getenv(self::ENV_WEBSITE_HOSTNAME_KEY), ResourceAttributes::SERVICE_INSTANCE_ID => getenv(self::ENV_WEBSITE_INSTANCE_ID_KEY), ResourceAttributes::SERVICE_NAME => $name, diff --git a/src/ResourceDetectors/Azure/tests/Unit/AppService/DetectorTest.php b/src/ResourceDetectors/Azure/tests/Unit/AppService/DetectorTest.php index 4c91ebf5a..e8cc97542 100644 --- a/src/ResourceDetectors/Azure/tests/Unit/AppService/DetectorTest.php +++ b/src/ResourceDetectors/Azure/tests/Unit/AppService/DetectorTest.php @@ -32,7 +32,7 @@ public function test_valid_app_service_attributes() [ResourceAttributes::CLOUD_PROVIDER, null, 'azure'], [ResourceAttributes::CLOUD_RESOURCE_ID, Detector::ENV_REGION_NAME_KEY, '/subscriptions/owner_name/resourceGroups/resouce_group/providers/Microsoft.Web/sites/demo-app'], [ResourceAttributes::CLOUD_REGION, Detector::ENV_REGION_NAME_KEY, 'westus'], - [ResourceAttributes::DEPLOYMENT_ENVIRONMENT, Detector::ENV_WEBSITE_SLOT_NAME_KEY, 'testing'], + [ResourceAttributes::DEPLOYMENT_ENVIRONMENT_NAME, Detector::ENV_WEBSITE_SLOT_NAME_KEY, 'testing'], [ResourceAttributes::HOST_ID, Detector::ENV_WEBSITE_HOSTNAME_KEY, 'example.com'], [ResourceAttributes::SERVICE_INSTANCE_ID, Detector::ENV_WEBSITE_INSTANCE_ID_KEY, uniqid()], [ResourceAttributes::SERVICE_NAME, Detector::ENV_WEBSITE_SITE_NAME_KEY, self::SERVICE_NAME], diff --git a/src/Symfony/composer.json b/src/Symfony/composer.json index 80081eeb5..20b056a75 100644 --- a/src/Symfony/composer.json +++ b/src/Symfony/composer.json @@ -13,7 +13,7 @@ "open-telemetry/context": "^1", "open-telemetry/exporter-otlp": "^1", "open-telemetry/exporter-zipkin": "^1", - "open-telemetry/sem-conv": "^1.23", + "open-telemetry/sem-conv": "^1.30", "php-http/discovery": "^1.14", "php-http/message": "^1.12" }, diff --git a/src/Symfony/src/OtelBundle/Console/ConsoleListener.php b/src/Symfony/src/OtelBundle/Console/ConsoleListener.php index 04caf6111..74aa4af64 100644 --- a/src/Symfony/src/OtelBundle/Console/ConsoleListener.php +++ b/src/Symfony/src/OtelBundle/Console/ConsoleListener.php @@ -28,7 +28,7 @@ public function __construct( $this->tracer = $tracerProvider->getTracer( OtelBundle::instrumentationName(), OtelBundle::instrumentationVersion(), - TraceAttributes::SCHEMA_URL, + 'https://opentelemetry.io/schemas/1.30.0', ); } @@ -60,7 +60,7 @@ public function startCommand(ConsoleCommandEvent $event): void $span = $this->tracer ->spanBuilder($name ?? 'command') - ->setAttribute(TraceAttributes::CODE_FUNCTION, 'run') + ->setAttribute(TraceAttributes::CODE_FUNCTION_NAME, 'run') ->setAttribute(TraceAttributes::CODE_NAMESPACE, $class) ->startSpan(); diff --git a/src/Symfony/src/OtelBundle/HttpKernel/RequestListener.php b/src/Symfony/src/OtelBundle/HttpKernel/RequestListener.php index 1b2e27d8f..b3afb00bd 100644 --- a/src/Symfony/src/OtelBundle/HttpKernel/RequestListener.php +++ b/src/Symfony/src/OtelBundle/HttpKernel/RequestListener.php @@ -57,7 +57,7 @@ public function __construct( $this->tracer = $tracerProvider->getTracer( OtelBundle::instrumentationName(), OtelBundle::instrumentationVersion(), - TraceAttributes::SCHEMA_URL, + 'https://opentelemetry.io/schemas/1.30.0', ); $this->propagator = $propagator; $this->propagationGetter = new HeadersPropagator();