123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- import type {Theme} from '@emotion/react';
- import type {EventTransaction} from 'sentry/types/event';
- import type {TraceTree} from './traceTree';
- function isTraceTransaction(value: TraceTree.NodeValue): value is TraceTree.Transaction {
- return !!(value && 'transaction' in value);
- }
- function isTraceError(value: TraceTree.NodeValue): value is TraceTree.TraceError {
- return !!(value && 'level' in value);
- }
- function isTraceSpan(value: TraceTree.NodeValue): value is TraceTree.Span {
- return !!(
- value &&
- 'span_id' in value &&
- !isTraceAutogroup(value) &&
- !isTraceTransaction(value)
- );
- }
- function isTraceAutogroup(
- value: TraceTree.NodeValue
- ): value is TraceTree.ChildrenAutogroup | TraceTree.SiblingAutogroup {
- return !!(value && 'autogrouped_by' in value);
- }
- function shouldCollapseNodeByDefault(node: TraceTreeNode<TraceTree.NodeValue>) {
- if (isTraceSpan(node.value)) {
- // Android creates TCP connection spans which are noisy and not useful in most cases.
- // Unless the span has a child txn which would indicate a continuaton of the trace, we collapse it.
- if (node.value.op === 'http.client' && node.value.origin === 'auto.http.okhttp') {
- return true;
- }
- }
- return false;
- }
- export class TraceTreeNode<T extends TraceTree.NodeValue = TraceTree.NodeValue> {
- parent: TraceTreeNode | null = null;
- reparent_reason: 'pageload server handler' | null = null;
- fetchStatus: 'resolved' | 'error' | 'idle' | 'loading' = 'idle';
- value: T;
- canFetch: boolean = false;
- expanded: boolean = true;
- zoomedIn: boolean = false;
- metadata: TraceTree.Metadata = {
- project_slug: undefined,
- event_id: undefined,
- spans: undefined,
- };
- event: EventTransaction | null = null;
- // Events associated with the node, these are inferred from the node value.
- errors = new Set<TraceTree.TraceError>();
- performance_issues = new Set<TraceTree.TracePerformanceIssue>();
- profiles: TraceTree.Profile[] = [];
- space: [number, number] = [0, 0];
- children: TraceTreeNode[] = [];
- depth: number | undefined;
- connectors: number[] | undefined;
- constructor(parent: TraceTreeNode | null, value: T, metadata: TraceTree.Metadata) {
- this.parent = parent ?? null;
- this.value = value;
- this.metadata = metadata;
- // The node can fetch its children if it has more than one span, or if we failed to fetch the span count.
- this.canFetch =
- typeof metadata.spans === 'number'
- ? metadata.spans > 1
- : isTraceTransaction(this.value);
- // If a node has both a start and end timestamp, then we can infer a duration,
- // otherwise we can only infer a timestamp.
- if (
- value &&
- 'timestamp' in value &&
- 'start_timestamp' in value &&
- typeof value.timestamp === 'number' &&
- typeof value.start_timestamp === 'number'
- ) {
- this.space = [
- value.start_timestamp * 1e3,
- (value.timestamp - value.start_timestamp) * 1e3,
- ];
- } else if (value && 'timestamp' in value && typeof value.timestamp === 'number') {
- this.space = [value.timestamp * 1e3, 0];
- }
- if (value) {
- if ('errors' in value && Array.isArray(value.errors)) {
- value.errors.forEach(error => this.errors.add(error));
- }
- if ('performance_issues' in value && Array.isArray(value.performance_issues)) {
- value.performance_issues.forEach(issue => this.performance_issues.add(issue));
- }
- if ('profile_id' in value && typeof value.profile_id === 'string') {
- this.profiles.push({profile_id: value.profile_id});
- }
- if ('profiler_id' in value && typeof value.profiler_id === 'string') {
- this.profiles.push({profiler_id: value.profiler_id});
- }
- }
- // For error nodes, its value is the only associated issue.
- if (isTraceError(this.value)) {
- this.errors.add(this.value);
- }
- // Android http spans generate sub spans for things like dns resolution in http requests,
- // which creates a lot of noise and is not useful to display.
- if (shouldCollapseNodeByDefault(this)) {
- this.expanded = false;
- }
- }
- get hasErrors(): boolean {
- return this.errors.size > 0 || this.performance_issues.size > 0;
- }
- private _max_severity: keyof Theme['level'] | undefined;
- get maxIssueSeverity(): keyof Theme['level'] {
- if (this._max_severity) {
- return this._max_severity;
- }
- for (const error of this.errors) {
- if (error.level === 'error' || error.level === 'fatal') {
- this._max_severity = error.level;
- return this.maxIssueSeverity;
- }
- }
- return 'default';
- }
- invalidate() {
- this.connectors = undefined;
- this.depth = undefined;
- }
- static Root() {
- return new TraceTreeNode(null, null, {
- event_id: undefined,
- project_slug: undefined,
- });
- }
- }
|