Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slim and psr-15 auto-instrumentation #81

Merged
merged 26 commits into from
Nov 10, 2022
Merged

Slim and psr-15 auto-instrumentation #81

merged 26 commits into from
Nov 10, 2022

Conversation

brettmc
Copy link
Collaborator

@brettmc brettmc commented Oct 19, 2022

No description provided.

<?php
require_once 'vendor/autoload.php';

$tracerProvider = <create tracer provider>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we plan to simplify that in production ready release?. Important aspect of auto-instrumentation is easy of use. Using this approach user needs to know some details of opentelemetry, at least how to create trace provider and export spans, then he has to add opentelemetry dependencies to application. This might be good for experienced user that want to know what's going on under the hood, but 99% users IMHO will be not interested in such details.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If all inputs are provided via environment variables, we could automatically create and register everything. Combining https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/traces/features/configuration_from_environment.php with the composer autoload-files technique is one way I think we could provide zero-code instrumentation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I was thinking about

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With open-telemetry/opentelemetry-php#849 we could define lazy initializers in the SDK that are invoked iff the user does not configure the instances manually.

Globals::registerInitializer(static function(Configurator $configurator): Configurator {
    $tracerProvider = (new TracerProviderFactory('should be fetched from resource instead'))->create();
    ShutdownHandler::register($tracerProvider->shutdown(...));

    return $configurator->withTracerProvider($tracerProvider);
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, how will we check if user configured these instances, should it be part of Globals::registerInitializer implementation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Globals already takes care of that - eg if you try to get a tracer provider, it will first check in context:

    public static function tracerProvider(): TracerProviderInterface
    {
        return Context::getCurrent()->get(ContextKeys::tracerProvider()) ?? self::globals()->tracerProvider;
    }

@codecov
Copy link

codecov bot commented Oct 24, 2022

Codecov Report

Merging #81 (df02999) into main (23464b2) will decrease coverage by 8.98%.
The diff coverage is 19.37%.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##               main      #81      +/-   ##
============================================
- Coverage     89.58%   80.60%   -8.99%     
- Complexity      283      330      +47     
============================================
  Files            31       34       +3     
  Lines           816     1000     +184     
============================================
+ Hits            731      806      +75     
- Misses           85      194     +109     
Flag Coverage Δ
7.4 89.66% <ø> (+0.08%) ⬆️
8.0 80.30% <18.60%> (-9.04%) ⬇️
8.1 80.40% <19.37%> (-8.94%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...Instrumentation/Psr15/src/Psr15Instrumentation.php 0.00% <0.00%> (ø)
...c/Instrumentation/Slim/src/SlimInstrumentation.php 0.00% <0.00%> (ø)
src/Instrumentation/Slim/src/CallableFormatter.php 86.20% <86.20%> (ø)
src/Aws/src/Ecs/Detector.php 92.00% <0.00%> (-2.74%) ⬇️
src/Symfony/src/OtelSdkBundle/Util/ExporterDsn.php 100.00% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 23464b2...df02999. Read the comment docs.

@brettmc brettmc marked this pull request as ready for review October 24, 2022 05:46
@brettmc brettmc requested a review from a team October 24, 2022 05:46
Copy link
Contributor

@tcarrio tcarrio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly a vested citizen in the CNCF channel excited for the OTel PHP SDK. A couple things I noticed here that I thought I would comment on slightly_smiling_face

src/Instrumentation/Psr15/src/Psr15Instrumentation.php Outdated Show resolved Hide resolved
src/Instrumentation/Psr15/src/Psr15Instrumentation.php Outdated Show resolved Hide resolved
src/Instrumentation/Psr15/README.md Outdated Show resolved Hide resolved
src/Instrumentation/Psr15/README.md Show resolved Hide resolved
@brettmc brettmc marked this pull request as draft November 1, 2022 00:38
add class to span name
src/Instrumentation/Psr15/src/Psr15Instrumentation.php Outdated Show resolved Hide resolved
$span->recordException($exception, [TraceAttributes::EXCEPTION_ESCAPED => true]);
$span->setStatus(StatusCode::STATUS_ERROR, $exception->getMessage());
}
if ($response?->getStatusCode() >= 500) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should capture some additional http attributes such as http.status_code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, added a few more attributes.

brettmc and others added 2 commits November 3, 2022 10:43
suggested change from Nevay

Co-authored-by: Tobias Bachert <[email protected]>
adding more http trace attributes
hook(
RequestHandlerInterface::class,
'handle',
pre: static function (RequestHandlerInterface $handler, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($instrumentation) {
Copy link
Member

@pdelewski pdelewski Nov 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about current implementation for some time and I don't think that relying on external library parameters (I'm taking about request and its usage to store span) is good thing. I believe that instrumentation should be independent and rely only on itself implementation, therefore why not use Context (I got the same effect with it). Below pre hook that uses additional $rootspan variable

pre: static function (RequestHandlerInterface $handler, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($instrumentation, $rootspan) {
                $request = ($params[0] instanceof ServerRequestInterface) ? $params[0] : null;
                $root = Context::getCurrent()->get($rootspan);
                $builder = $instrumentation->tracer()->spanBuilder(
                    $root
                    ? sprintf('%s::%s', $class, $function)
                    : sprintf('PSR HTTP %s %s', $request?->getMethod(), $request->getUri() ?? 'unknown')
                )
                    ->setSpanKind(SpanKind::KIND_SERVER)
                    ->setAttribute('code.function', $function)
                    ->setAttribute('code.namespace', $class)
                    ->setAttribute('code.filepath', $filename)
                    ->setAttribute('code.lineno', $lineno);
                $parent = Context::getCurrent();
                if (!$root && $request) {
                    //create http root span
                    $parent = Globals::propagator()->extract($request->getHeaders());
                    $parent = $parent->with($rootspan, true);
                    $span = $builder
                        ->setParent($parent)
                        ->setAttribute(TraceAttributes::HTTP_URL, $request->getUri()->__toString())
                        ->setAttribute(TraceAttributes::HTTP_METHOD, $request->getMethod())
                        ->setAttribute(TraceAttributes::HTTP_REQUEST_CONTENT_LENGTH, $request->getHeaderLine('Content-Length'))
                        ->setAttribute(TraceAttributes::HTTP_SCHEME, $request->getUri()->getScheme())
                        ->startSpan();
                } else {
                    $span = $builder->startSpan();
                }
             
                Context::storage()->attach($span->storeInContext($parent));
                return [$request];
            },

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your example, is $rootSpan something like a ContextKey(SpanInterface::class)? It seems like a good idea to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, in my example I stored just bool, but I think it does not matter what will be there, main point is to get rid of using request attribute

RoutingMiddleware::class,
'performRouting',
pre: null,
post: static function (RoutingMiddleware $middleware, array $params, ServerRequestInterface $request, ?Throwable $exception) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook is used only to update span name created by other hook. I think that hooks should be self contained and orthogonal. I would remove this hook and use request->getUri() in handle hook(s)

Copy link
Collaborator Author

@brettmc brettmc Nov 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I've done it as "set" then later "update" is:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, we can extract part of uri, it would simplify code.

* Create a span representing the http transaction for Slim\App::handle
* @psalm-suppress ArgumentTypeCoercion
*/
hook(
Copy link
Member

@pdelewski pdelewski Nov 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I don't understand need for this hook as we already hooking into RequestHandlerInterface::handle, is it only due to ending root span?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it's redundant now. I left it there because I wasn't sure which way I'd end up going, but if having Psr15 instrumentation work out when to create a root span in RequestHandlerInterface::handle, then this hook can be removed.

pdelewski pushed a commit to pdelewski/opentelemetry-php-contrib that referenced this pull request Nov 4, 2022
pdelewski pushed a commit to pdelewski/opentelemetry-php-contrib that referenced this pull request Nov 4, 2022
get rid of using request attributes to store parent information
and use context instead
@pdelewski
Copy link
Member

@brettmc I'm thinking about merging this PR as it is now. We can make improvements later with additional PRs

@brettmc
Copy link
Collaborator Author

brettmc commented Nov 10, 2022

@pdelewski great idea - I haven't even looked at this PR in a week. I'll give it a quick tidy up and submit, then others can collaborate

remove App::handle auto-instrumentation, psr15 does this
@brettmc brettmc marked this pull request as ready for review November 10, 2022 05:39
@brettmc brettmc merged commit f0e6db3 into open-telemetry:main Nov 10, 2022
@brettmc brettmc deleted the slim-auto-instrumentation branch November 28, 2022 23:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants