chore: decouple client/server tracing from PSR implementation and consolidate nextSpanResolver.#166
chore: decouple client/server tracing from PSR implementation and consolidate nextSpanResolver.#166jcchavezs wants to merge 8 commits intohttp_serverfrom
Conversation
| # Somehow this started failing | ||
| message: '#Constant .* already defined#' | ||
| path: src/Zipkin No newline at end of file | ||
| - |
There was a problem hiding this comment.
Ignore this changes.
| public function getParser(): Parser | ||
| { | ||
| return $this->parser; | ||
| private static function buildNextSpanResolver( |
There was a problem hiding this comment.
This is important change.
| */ | ||
| private const TRACE_ID_NAME = 'X-B3-TraceId'; | ||
|
|
There was a problem hiding this comment.
Ignore all changes in this class. It is just lint.
| use Zipkin\Propagation\TraceContext; | ||
|
|
||
| /** | ||
| * NoopParser is a noop implementation of a parser that parses nothing as it does not know anything about the request. |
There was a problem hiding this comment.
not sure I should provide this but at least it is convenient for tests.
There was a problem hiding this comment.
if not sure keep it in tests directory :P
…tation and consolidates nextSpanResolver.
450c0be to
bd75590
Compare
| use Zipkin\Propagation\TraceContext; | ||
|
|
||
| /** | ||
| * NoopParser is a noop implementation of a parser that parses nothing as it does not know anything about the request. |
There was a problem hiding this comment.
if not sure keep it in tests directory :P
| { | ||
| public function spanName($request): string | ||
| { | ||
| return ''; |
There was a problem hiding this comment.
is this because null isn't a thing?
| * @return callable(TraceContext, $request): Span the next span handler which creates an appropriate span based | ||
| * on the extracted context. | ||
| */ | ||
| public function getNextSpanResolver(): callable |
There was a problem hiding this comment.
gut feel is there are too many variants of functions like this. I still don't fully understand why they have to be exposed separately as a function provider, as opposed to just using a handler.
I don't remember what these do, and it is odd that we have something typically called extractor which this is similar to, but maybe not the same as?
It smells like there are too many types of abstractions, like 1 per framework :P
before reviewing anything else, especially as the common answer is so often that X is for something not in this repo.. please make a model of things not in this repo that require the different types, as for example in java we don't require so many types of helper functions that have similar but different names. It is very confusing and not the best change model to drift here for something not here, and with no model tests to show why.
ex you can litersally make a test called PSR and even have that in the test dependency making s small version which shows why all these things are needed.
currently, the cognitive burden is very high due to so many things that are in many cases arbitrarily different than brave for me to review. When all things including nameing, class organization, lack of example code, etc are different it is very hard for me to help as each change is like a new baby and quest to figure out what its parents are.
There was a problem hiding this comment.
here's an example.. in brave we dno't have OT in the same repo. To explain why some features exist (ex to give visibility so we can refactor them later etc, and if OT drifts we know what we initially designed to), we have a partial copy of the actual OT code https://github.com/openzipkin/brave/tree/master/brave/src/test/java/brave/features/opentracing
I've used this as how that's implemented has been revised and we'd easily break the hooks otherwise. For someone looking at change right now I have to look at different repos or ask you questions to try to understand why seems like 3 web frameworks need 3 variants of nextSpan :D I'd like to see these things here, the parts that require all these bits somehow and know this isn't a mono-repo. Another way is to locally put some of the parts that drive the design here literally marked as PSR etc.
That way it is easier to understand the design impact. Concretely, there are functions that are being slightly modified for this or that. sometimes composition is a better choice as it is less new words to invent and explain. Like "extract and call tracer" requires naming a word while just doing the 2 or 3 lines locally to a framework does not. It is easy to over-abstract in other words, and that sets up not just new vocab to learn that isn't anything like other vocab, but in certain perspectives it is completely unnecessary.
Ex even if the same 2 or 3 lines are combined in 3 projects (which is the minimal to do such a thing :P) it doesn't mean the composition of that 2 functions is worth naming as a higher order function. even if it might be.. the models of PSR etc here could prove the case that they actually add value enough to have to explain why X is not the same as Y, and neither is it like U T and Z.
So concretely, I'm thinking localize small integrations of all things you've done so far. whatever the several frameworks are since this is not a mono-repo.. into the test tree. Use these "dummy projects" to have a test case for the actual abstraction working.. this could make it easier to see where several new functions are worthwhile or not worthwhile.
Meanwhile, bear in mind if statement nesting inside a higher order function is a smell that it isn't quite clean as a separate function. Keep these to a minimal. Ex Tracer.joinSpan in brave, it exists in the tracer as disabling it lives there. only use twice and only on server side (HTTP and RPC), so just inlined them locally to the places that call it. I'd prefer to explain more the choices of what is done there if something is unfamiliar than have to explain a few more nextSpan variant functions. Ex it may not be obvious, but we also have to explicitly pass trace context in a request sometimes.. we can have this conversation and design impact easily if where these things are needed exist in the same codebase as the design is being developed and implemented.
hope this helps!
There was a problem hiding this comment.
Thanks for the feedback @adriancole, actually PSR implementation is in this PR: https://github.com/openzipkin/zipkin-php/pull/166/files#diff-480132932af55e40a0941e973a46d2afR48-R85
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$extractedContext = ($this->extractor)($request);
$span = ($this->nextSpanResolver)($extractedContext, $request);
$scopeCloser = $this->tracer->openScope($span);
...Indeed nextSpanResolver was inspired by the nextSpanHandler as described in #162 (comment). The idea was to abstract the complexity for getting a new span in a server request/response situation. The way it is structured works for PSR (the standard for PHP) and any other server framework, that was the whole idea on separating the server instrumentation and PSR and keep PSR as one implementation because this logic of joining span or creating a new one from the current scope or use the requestSampler is being repeated in all the servers.
I still don't fully understand why they have to be exposed separately as a function provider, as opposed to just using a handler.
I don't fully understand this, probably because I don't have a clear idea on how a handler look like, is it that we would prefer a pluggable object that resolves or an object that resolves this without the need of being part of the server tracing?
There was a problem hiding this comment.
when I say handler I usually mean https://github.com/openzipkin/brave/blob/master/instrumentation/http/src/main/java/brave/http/HttpServerHandler.java filtered on non-deprecated methods
There was a problem hiding this comment.
for example, I've not found a case yet where you want to create a span and not parse data from its request or response. that's why the "nextSpan" type logic is a part of the handler.
|
I am closing this as there are many concerns from @adriancole and I don't feel too comfortable making some decisions now that I would not be able to revert in the future when tackling the use cases. |
This PR decouples the PSR implementation of HTTP tracing so the http abstraction can be used also with non PSR libraries.
It also consolidates the nextSpanResolver as a way to remove the responsability in the client or middleware to deal with the complexity of the next span:
Once the design is finished I will add more test coverage.
Ping @adriancole