-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[APM] Critical path for a single trace #143735
Conversation
( | ||
normalizedChildStart >= scanTime || | ||
normalizedChildEnd < start || | ||
childEnd > scanTime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlexanderWert do you remember what the reasoning was here? I understand that a span cannot be on the critical path if it ends after its parent, because it implies that the parent doesn't care about it finishing, but this also eliminates spans that end after its sibling that was previously on the critical path. Which might be a valid reason, but wanted to clarify that with you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's take this one as an example:
The algorithm starts from the end with GET /api/order
and we know that GET /api/order
is on the CP. The spans Parse the document
and Longtask
are partially parallel to GET /api/order
because they are not a parent of GET /api/order
, started before GET /api/order
, but DID NOT END before GET /api/order
. This implies that the start of GET /api/oder
is blocked by its parent rather one of the other two mentioned spans. As a consequence, the CP before GET /api/order
lies on the parent orders
and we can eliminate Parce the document
and Longtask
from the critical path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, that makes sense!
Pinging @elastic/apm-ui (Team:APM) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Core Changes LGTM
I think a Switch would look better in this case, since you are turning it on and off. You could even change the text to show/hide based on the status. I also think using the tech preview icon instead of the text would look nicer. Especially because when I first look at this my first impression is that the entire waterfall is in tech preview, cc: @boriskirov |
@dgieselaar is there any documentation we should point the users to? Is it clear what a critical path is for everyone? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a few nits let me know what you think.
}); | ||
} | ||
|
||
span({ spanName, spanType, spanSubtype, ...apmFields }: SpanParams) { | ||
span(...options: [string, string] | [string, string, string] | [SpanParams]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very weird, why is it needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's basically method overloading, but in one signature. I think span(spanName) is often good enough and more concise than span({ spanName: ... }). I previously discussed this with @sqren when he changed it, and IIRC(?) we decided I would add back the original method when I would have time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it makes the signature simpler but I'd rather be without the extra complexity in synthtrace. But I don't feel strongly for it either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I'll take that back. I don't think the signature improved except for transaction()
with a single arg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the signature is more complicated but not less easy to use, which is my goal. Like you know, I disagree about span({...}) and transaction({...}) being the better interface. I do we think should add more defaults for span() though, IMHO span(spanName) is good enough too, we can default to custom/custom for span type and subtype.
export function service(name: string, environment: string, agentName: string): Service; | ||
|
||
export function service(options: { name: string; environment: string; agentName: string }): Service; | ||
|
||
export function service( | ||
...args: [{ name: string; environment: string; agentName: string }] | [string, string, string] | ||
) { | ||
const [serviceName, environment, agentName] = | ||
args.length === 1 ? [args[0].name, args[0].environment, args[0].agentName] : args; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this overcomplicate this a bit? Is it really necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above.
description: i18n.translate('xpack.observability.enableCriticalPathDescription', { | ||
defaultMessage: '{technicalPreviewLabel} Optionally display the critical path of a trace.', | ||
values: { | ||
technicalPreviewLabel: `<em>[${technicalPreviewLabel}]</em>`, | ||
}, | ||
}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@boriskirov we're showing a link where users can give feedback for tech preview features, isn't there a link for this as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlexanderWert how do you feel about this?
* 2.0. | ||
*/ | ||
|
||
import type { IWaterfallSpanOrTransaction } from '../../public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_helpers/waterfall_helpers'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this look odd a common file importing stuff from a public component? Can you move the typing definitions of the waterfall to a common folder and use it here and adjust the imports? That's already a starting point to refactor the waterfall, we discussed about moving some of the logic to the server a couple of weeks ago.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a type-only import which I think is usually fine. I get your point, but I think there's also a lot of value of co-locating types with the code that uses them (the most).
// the critical path, but we only want one to contribute. | ||
// - The span/tx ends before the start of the initial scan period. | ||
// - The span ends _after_ the current scan time. | ||
( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you remove this extra (
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I'm actually surprised ESLint doesn't remove this. Maybe it adds it automatically because of the comment, I'll look into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ESLint adds it automatically :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if you move the comments up it'll look nicer. but it's up to you.
import { enableCriticalPath } from '@kbn/observability-plugin/common'; | ||
import { useApmPluginContext } from '../context/apm_plugin/use_apm_plugin_context'; | ||
|
||
export function useCriticalPathEnabledSetting() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export function useCriticalPathEnabledSetting() { | |
export function useCriticalPathSetting() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to distinguish between whether the feature is enabled and whether it is toggled on in the current view. Not sure if this is the best name but it's better than useCriticalPathSetting
IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you change it to align the settings name as discussed below I think it'll be fine: useCriticalPathFeatureEnabledSetting
defaults: { | ||
query: { | ||
showCriticalPath: '', | ||
}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it necessary if you'll use the value defined in the settings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some cases we cannot type-check links (e.g. when linking from outside the app), this is to handle those cases.
const criticalPath = showCriticalPath | ||
? getCriticalPath(waterfall) | ||
: undefined; | ||
|
||
const criticalPathSegmentsById = groupBy( | ||
criticalPath?.segments, | ||
(segment) => segment.item.id | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it's important to wrap it inside a useMemo
so it won't recalculate on every render?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will be fast enough. There will only be a handful of segments in most cases.
onShowCriticalPathChange={(nextShowCriticalPath) => { | ||
push(history, { | ||
query: { | ||
showCriticalPath: nextShowCriticalPath ? 'true' : 'false', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use toString
instead?
showCriticalPath: nextShowCriticalPath ? 'true' : 'false', | |
showCriticalPath: nextShowCriticalPath.toString(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point, but I think I have a slight preference for being explicit here.
<Waterfall waterfallItemId={waterfallItemId} waterfall={waterfall} /> | ||
</div> | ||
<EuiFlexGroup direction="column"> | ||
{isCriticalPathEnabled ? ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the name of the setting and the props are a bit confusing. I think the other way around would make more sense.
Change the settings to showCriticalPath
and change the props to enableCriticalPath
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about swapping them, I think I'll change it to isCriticalPathFeatureEnabled
or maybe isCriticalPathFeatureAvailable
. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think isCriticalPathFeatureEnabled
is better.
…into critical-path-preview
@cauemarcondes I think I got most of it, mind having another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
// the critical path, but we only want one to contribute. | ||
// - The span/tx ends before the start of the initial scan period. | ||
// - The span ends _after_ the current scan time. | ||
( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if you move the comments up it'll look nicer. but it's up to you.
💚 Build Succeeded
Metrics [docs]Module Count
Public APIs missing comments
Async chunks
Page load bundle
Unknown metric groupsAPI count
History
To update your PR or re-run it, just comment with: |
💔 All backports failed
Manual backportTo create the backport manually run:
Questions ?Please refer to the Backport tool documentation |
* main: (24 commits) [Files] Add file upload to file picker (elastic#143969) [Security solution] Guided onboarding, alerts & cases (elastic#143598) [APM] Critical path for a single trace (elastic#143735) skip failing test suite (elastic#143933) [Fleet] Update GH Projects automation (elastic#144123) [APM] Performance fix for 'cardinality' telemetry task (elastic#144061) [Enterprise Search] Attach ML Inference Pipeline - Pipeline re-use (elastic#143979) [8.5][DOCS] Add support for differential logs (elastic#143242) Bump nwsapi from v2.2.0 to v2.2.2 (elastic#144001) [APM] Add waterfall to dependency operations (elastic#143257) [Shared UX] Add deprecation message to kibana react Markdown (elastic#143766) [Security Solution][Endpoint] Adds RBAC API checks for Blocklist (elastic#144047) Improve `needs-team` auto labeling regex (elastic#143787) [Reporting/CSV Export] _id field can not be formatted (elastic#143807) Adds SavedObjectsWarning to analytics results pages. (elastic#144109) Bump chromedriver to 107 (elastic#144073) Update cypress (elastic#143755) [Maps] nest security layers in layer group (elastic#144055) [Lens][Agg based Heatmap] Navigate to Lens Agg based Heatmap. (elastic#143820) Added support of saved search (elastic#144095) ...
Friendly reminder: Looks like this PR hasn’t been backported yet. |
1 similar comment
Friendly reminder: Looks like this PR hasn’t been backported yet. |
.timestamp(1) | ||
.duration(100) | ||
.children( | ||
service.span('foo', 'external', 'db').duration(100).timestamp(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually think this reads worse than before. I'm not sure what either of those arguments are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree, it's clear to me. I realise I'm biased as the author but I think you're also exaggerating a little bit here :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree, it's clear to me
How many on the team do you think will know that "foo" is span.name, "external" is span.type and "db" is span.subtype?
If it's more than half I'll shut up. We should do a pop quiz and settle this ;)
Part of #142370.