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

Correct trace name resolution #541

Merged

Conversation

swapster
Copy link
Contributor

@swapster swapster commented Mar 9, 2020

Related to #461.

There is a problem with resolution of a trace name for traces without spans with empty refs (when a "root span" is a span with remote parent).

This PR fixes this problem as suggested in a discussion. To detect a "root span" we:

  1. Find all spans that either have no parent reference, or a parent reference that is not found among all trace's spans.
  2. Sort found spans by start time.
  3. Take a first ("the earliest") span and make a trace name from this span's data.

Additionally, there are some unit tests for a different cases.

@codecov
Copy link

codecov bot commented Mar 9, 2020

Codecov Report

Merging #541 into master will decrease coverage by 0.02%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #541      +/-   ##
==========================================
- Coverage   92.97%   92.94%   -0.03%     
==========================================
  Files         197      197              
  Lines        4840     4848       +8     
  Branches     1174     1177       +3     
==========================================
+ Hits         4500     4506       +6     
- Misses        300      302       +2     
  Partials       40       40              
Impacted Files Coverage Δ
packages/jaeger-ui/src/model/trace-viewer.tsx 100.00% <100.00%> (ø)
...eViewer/TimelineHeaderRow/TimelineViewingLayer.tsx 88.13% <0.00%> (-3.39%) ⬇️

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 68e282d...cd8d04c. Read the comment docs.

1. Find all spans without parent reference or with a parent reference that is not found in the trace
2. Sort all found spans by start time (in case when there are more than one span found)
3. Take first of the found spans and get a trace name

Signed-off-by: Valerii Varankin <[email protected]>
* Test for trace without root span
* Test for trace with exactly one root span (with remote ref)
* Test for trace with exactly one root span (with no refs)
* Test for trace with more than one root span

Signed-off-by: Valerii Varankin <[email protected]>
* File extension changed to .tsx
* Path to changed file removed from tsconfig.lint.json
* Added type for spans argument in getTraceName()

Signed-off-by: Valerii Varankin <[email protected]>
@swapster swapster force-pushed the correct-trace-name-resolution branch from 79a7e39 to e968cdb Compare March 9, 2020 18:03
Copy link
Member

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

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

thanks for the PR

@@ -0,0 +1,172 @@
// Copyright (c) 2018 Uber Technologies, Inc.
Copy link
Member

Choose a reason for hiding this comment

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

2020

Copy link
Contributor Author

Choose a reason for hiding this comment

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

const parentIDs = sp.references.filter(r => r.refType === 'CHILD_OF').map(r => r.spanID);

// no parent from trace
return !parentIDs.some(pID => allSpanIDs.includes(pID));
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't allSpanIDs.includes do a linear search? Why not construct allSpanIDs as a dictionary {spanID->span}?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just didn't think about it. But yeap, dictionary makes sense here.
Changed an array to a dict.

// no parent from trace
return !parentIDs.some(pID => allSpanIDs.includes(pID));
})
.sort((sp1, sp2) => sp1.startTime - sp2.startTime)[0];
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is correct, as it does not give preference to the true root span (that one that has NO parent). It's only correct in the absence of clock skews.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I missed it.

Added a parents check to a sort() method (also, left untouched comparing by a startTime since, I think, it's better than not to sort multiple "root" spans at all if there are several of them).

Also, changed a couple of tests.

@@ -30,7 +30,6 @@
"src/api/jaeger.js",
"src/components/SearchTracePage/SearchResults/ResultItem.markers.js",
"src/model/order-by.js",
"src/model/trace-viewer.js",
Copy link
Member

Choose a reason for hiding this comment

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

should the tsx file be added to some other linter config, or will it be automatically linted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will be linted since this config file inherits another config with include option.
Please correct me if I'm wrong.

const spansWithNoRoots = [
{
spanID: firstSpanId,
startTime: 1583758690000,
Copy link
Member

Choose a reason for hiding this comment

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

I recommend defining a constant t and using deltas like t+10 to vary the timestamps.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, fixed.

},
references: [
{
spanID: remoteSpanId,
Copy link
Member

Choose a reason for hiding this comment

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

nit: this looks more like missingSpanId rather than remote.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, its' better, fixed.

Fixed a year in a copyright text

Signed-off-by: Valerii Varankin <[email protected]>
Renamed variable from "remoteSpanId" to "missingSpanId"

Signed-off-by: Valerii Varankin <[email protected]>
Made a constant with base span's timestamp in a tests

Signed-off-by: Valerii Varankin <[email protected]>
Usage of dictionary of all spans instead of id's array to check an inclusion

Signed-off-by: Valerii Varankin <[email protected]>
Correction of a spans sorting to such order:
1. First, sort spans by a presence of a parent
2. Second, sort spans by a start time

Signed-off-by: Valerii Varankin <[email protected]>
* Test for a trace with multiple root spans different by parents
* Test for a trace with multiple root spans different by start time

Signed-off-by: Valerii Varankin <[email protected]>
Added a process key with an empty object to all test spans to avoid reading property of undefined

Signed-off-by: Valerii Varankin <[email protected]>
packages/jaeger-ui/src/model/trace-viewer.tsx Outdated Show resolved Hide resolved
packages/jaeger-ui/src/model/find-trace-name.test.js Outdated Show resolved Hide resolved
packages/jaeger-ui/src/model/find-trace-name.test.js Outdated Show resolved Hide resolved
if (!sp.references || !sp.references.length) {
return true;
}
const parentIDs = sp.references.filter(r => r.refType === 'CHILD_OF').map(r => r.spanID);
Copy link
Member

Choose a reason for hiding this comment

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

What if you dropped filters for CHILD_OF? It's possible to have an async trace using FOLLOWS_FROM. I don't think the algorithm is actually sensitive to the type of reference. If anything, I would filter on r.spanContext.traceID being the same as the current span, because a reference to an external trace is definitely not a parent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm. Did I understand correctly, span.references can't contain refs to a children? I mean, if some span listed as a reference, it can be either a parent or a some missing ref, but not a child?
If so, I suggest to change this logic by this way. There is no need to calculate a dict of all trace spans anymore, since some() can check traceID by itself. If there are no situations when spans (which is an argument to this function) contains more data then all .references, this approach looks more correct.

P. S. "I didn't find spanContext in a types, think it should be r.traceID or r.span.traceID :)"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, I was wrong.

There may be situations when there are references with same traceID but with incorrect (missing) spanID. It this case such span won't define as a root but it can be a root.

Updated a logic and a tests. Now it should work correct.

swapster and others added 4 commits March 11, 2020 11:19
….test.js

Co-Authored-By: Yuri Shkuro <[email protected]>
Signed-off-by: Valerii Varankin <[email protected]>
Co-Authored-By: Yuri Shkuro <[email protected]>
Signed-off-by: Valerii Varankin <[email protected]>
Co-Authored-By: Yuri Shkuro <[email protected]>
Signed-off-by: Valerii Varankin <[email protected]>
@swapster swapster force-pushed the correct-trace-name-resolution branch from 207ec09 to bfbce5b Compare March 11, 2020 08:20
Method of parents definition changed to comparing traceIDs of spans

Signed-off-by: Valerii Varankin <[email protected]>
Tests traces data was changed to fit parents definition method by a traceIDs

Signed-off-by: Valerii Varankin <[email protected]>
Added a checking of parent span presence among all trace's spans

Signed-off-by: Valerii Varankin <[email protected]>
Tests traces data was changed according to changed logic

Signed-off-by: Valerii Varankin <[email protected]>
Copy link
Member

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

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

LGTM !

@yurishkuro yurishkuro merged commit a9dce8b into jaegertracing:master Mar 12, 2020
vvvprabhakar pushed a commit to vvvprabhakar/jaeger-ui that referenced this pull request Jul 5, 2021
* Trace name resolution by root span with remote ref

1. Find all spans without parent reference or with a parent reference that is not found in the trace
2. Sort all found spans by start time (in case when there are more than one span found)
3. Take first of the found spans and get a trace name

Signed-off-by: Valerii Varankin <[email protected]>

* Unit tests for getTraceName() method

* Test for trace without root span
* Test for trace with exactly one root span (with remote ref)
* Test for trace with exactly one root span (with no refs)
* Test for trace with more than one root span

Signed-off-by: Valerii Varankin <[email protected]>

* trace-viewer to .tsx

* File extension changed to .tsx
* Path to changed file removed from tsconfig.lint.json
* Added type for spans argument in getTraceName()

Signed-off-by: Valerii Varankin <[email protected]>

* Year fix

Fixed a year in a copyright text

Signed-off-by: Valerii Varankin <[email protected]>

* Variable rename

Renamed variable from "remoteSpanId" to "missingSpanId"

Signed-off-by: Valerii Varankin <[email protected]>

* Timestamp constant

Made a constant with base span's timestamp in a tests

Signed-off-by: Valerii Varankin <[email protected]>

* Spans id array to spans dictionary

Usage of dictionary of all spans instead of id's array to check an inclusion

Signed-off-by: Valerii Varankin <[email protected]>

* Correct sort logic

Correction of a spans sorting to such order:
1. First, sort spans by a presence of a parent
2. Second, sort spans by a start time

Signed-off-by: Valerii Varankin <[email protected]>

* Tests for a new sorting logic

* Test for a trace with multiple root spans different by parents
* Test for a trace with multiple root spans different by start time

Signed-off-by: Valerii Varankin <[email protected]>

* Empty process object to all test spans

Added a process key with an empty object to all test spans to avoid reading property of undefined

Signed-off-by: Valerii Varankin <[email protected]>

* Update Copyright text in packages/jaeger-ui/src/model/trace-viewer.tsx

Co-Authored-By: Yuri Shkuro <[email protected]>
Signed-off-by: Valerii Varankin <[email protected]>

* Update Copyright text in packages/jaeger-ui/src/model/find-trace-name.test.js

Co-Authored-By: Yuri Shkuro <[email protected]>
Signed-off-by: Valerii Varankin <[email protected]>

* More detailed comment for root span

Co-Authored-By: Yuri Shkuro <[email protected]>
Signed-off-by: Valerii Varankin <[email protected]>

* Note about a loop

Co-Authored-By: Yuri Shkuro <[email protected]>
Signed-off-by: Valerii Varankin <[email protected]>

* Change of parents definition logic

Method of parents definition changed to comparing traceIDs of spans

Signed-off-by: Valerii Varankin <[email protected]>

* Tests correction according to changed logic

Tests traces data was changed to fit parents definition method by a traceIDs

Signed-off-by: Valerii Varankin <[email protected]>

* Checking of parent span presence

Added a checking of parent span presence among all trace's spans

Signed-off-by: Valerii Varankin <[email protected]>

* Tests correction according to changed logic

Tests traces data was changed according to changed logic

Signed-off-by: Valerii Varankin <[email protected]>

Co-authored-by: Yuri Shkuro <[email protected]>
Signed-off-by: vvvprabhakar <[email protected]>
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.

2 participants