Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { fakeAsync, flush } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { IconLibraryTestingModule } from '@hypertrace/assets-library';
import { NavigationService } from '@hypertrace/common';
import { runFakeRxjs } from '@hypertrace/test-utils';
import { createHostFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
import { EMPTY } from 'rxjs';
import { SpanExitCallsComponent } from './span-exit-calls.component';
import { SpanExitCallsModule } from './span-exit-calls.module';

describe('SpanExitCallsComponent', () => {
let spectator: Spectator<SpanExitCallsComponent>;

const createHost = createHostFactory({
component: SpanExitCallsComponent,
imports: [SpanExitCallsModule, HttpClientTestingModule, IconLibraryTestingModule],
declareComponent: false,
providers: [
mockProvider(ActivatedRoute, {
queryParamMap: EMPTY
}),
mockProvider(NavigationService, {
navigation$: EMPTY
})
]
});

test('should render data correctly', fakeAsync(() => {
spectator = createHost(`<ht-span-exit-calls [exitCalls]="exitCalls"></ht-span-exit-calls>`, {
hostProps: { exitCalls: { 'name 1': '10', 'name 2': '11' } }
});

runFakeRxjs(({ expectObservable }) => {
expect(spectator.component.dataSource).toBeDefined();
expectObservable(spectator.component.dataSource!.getData(undefined!)).toBe('(x|)', {
x: {
data: [
{ name: 'name 1', calls: '10' },
{ name: 'name 2', calls: '11' }
],
totalCount: 2
}
});

flush();
});
}));
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { Dictionary } from '@hypertrace/common';
import { TableColumnConfig, TableDataResponse, TableDataSource, TableRow } from '@hypertrace/components';
import { Observable, of } from 'rxjs';

@Component({
selector: 'ht-span-exit-calls',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<div class="span-exit-calls">
<ht-table [columnConfigs]="this.columnConfigs" [data]="this.dataSource" [pageable]="false"></ht-table>
</div> `
})
export class SpanExitCallsComponent implements OnInit {
@Input()
public exitCalls?: Dictionary<string>;

public dataSource?: TableDataSource<TableRow>;
public columnConfigs: TableColumnConfig[] = [
{
id: 'name',
name: 'name',
title: 'Service',
visible: true,
width: '80%',
sortable: false,
filterable: false
},
{
id: 'calls',
name: 'calls',
title: 'Calls',
visible: true,
sortable: false,
filterable: false
}
];

public ngOnInit(): void {
this.buildDataSource();
}

private buildDataSource(): void {
this.dataSource = {
getData: (): Observable<TableDataResponse<TableRow>> =>
of({
data: Object.entries(this.exitCalls ?? {}).map(item => ({ name: item[0], calls: item[1] })),
totalCount: Object.keys(this.exitCalls ?? {}).length
}),
getScope: () => undefined
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { TableModule } from '@hypertrace/components';
import { SpanExitCallsComponent } from './span-exit-calls.component';

@NgModule({
declarations: [SpanExitCallsComponent],
exports: [SpanExitCallsComponent],
imports: [CommonModule, TableModule]
})
export class SpanExitCallsModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export interface SpanData {
responseBody: string;
tags: Dictionary<unknown>;
requestUrl: string;
exitCallsBreakup?: Dictionary<string>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ import { SpanDetailLayoutStyle } from './span-detail-layout-style';
<ht-tab label="Attributes" class="attributes">
<ht-span-tags-detail [tags]="this.spanData.tags"></ht-span-tags-detail>
</ht-tab>
<ht-tab label="Exit Calls" *ngIf="this.showExitCallsTab">
<ht-span-exit-calls [exitCalls]="this.spanData.exitCallsBreakup"></ht-span-exit-calls>
</ht-tab>
</ht-tab-group>
</div>
`
Expand All @@ -62,11 +65,13 @@ export class SpanDetailComponent implements OnChanges {

public showRequestTab?: boolean;
public showResponseTab?: boolean;
public showExitCallsTab?: boolean;

public ngOnChanges(changes: TypedSimpleChanges<this>): void {
if (changes.spanData) {
this.showRequestTab = !isEmpty(this.spanData?.requestHeaders) || !isEmpty(this.spanData?.requestBody);
this.showResponseTab = !isEmpty(this.spanData?.responseHeaders) || !isEmpty(this.spanData?.responseBody);
this.showExitCallsTab = !isEmpty(this.spanData?.exitCallsBreakup);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ToggleButtonModule,
TooltipModule
} from '@hypertrace/components';
import { SpanExitCallsModule } from './exit-calls/span-exit-calls.module';
import { SpanDetailTitleHeaderModule } from './headers/title/span-detail-title-header.module';
import { SpanRequestDetailModule } from './request/span-request-detail.module';
import { SpanResponseDetailModule } from './response/span-response-detail.module';
Expand All @@ -32,7 +33,8 @@ import { SpanTagsDetailModule } from './tags/span-tags-detail.module';
JsonViewerModule,
LoadAsyncModule,
ListViewModule,
SpanDetailTitleHeaderModule
SpanDetailTitleHeaderModule,
SpanExitCallsModule
],
declarations: [SpanDetailComponent],
exports: [SpanDetailComponent]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ describe('Trace detail data source model', () => {
traceProperties: expect.arrayContaining([
expect.objectContaining({ name: 'tags' }),
expect.objectContaining({ name: 'traceId' }),
expect.objectContaining({ name: 'statusCode' })
expect.objectContaining({ name: 'statusCode' }),
expect.objectContaining({ name: 'apiCalleeNameCount' })
])
})
);
Expand All @@ -99,7 +100,8 @@ describe('Trace detail data source model', () => {
traceProperties: expect.arrayContaining([
expect.objectContaining({ name: 'tags' }),
expect.objectContaining({ name: 'traceId' }),
expect.objectContaining({ name: 'statusCode' })
expect.objectContaining({ name: 'statusCode' }),
expect.objectContaining({ name: 'apiCalleeNameCount' })
])
})
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import { Model } from '@hypertrace/hyperdash';
import { Trace, traceIdKey } from '../../../../graphql/model/schema/trace';

import { Dictionary } from '@hypertrace/common';
import { TraceDetailData, TraceDetailDataSourceModel } from './trace-detail-data-source.model';

@Model({
type: 'api-trace-detail-data-source'
})
export class ApiTraceDetailDataSourceModel extends TraceDetailDataSourceModel {
protected getTraceAttributes(): string[] {
return [...super.getTraceAttributes(), 'traceId'];
return [...super.getTraceAttributes(), 'traceId', 'apiCalleeNameCount'];
}

protected constructTraceDetailData(trace: Trace): ApiTraceDetailData {
return {
...super.constructTraceDetailData(trace),
traceId: trace.traceId as string, // For API Trace traceId is real Trace ID. NOT Symbol('traceId').
entrySpanId: trace[traceIdKey] // API Trace Symbol('traceId') same as apiTraceId which is actually Entry Span ID
entrySpanId: trace[traceIdKey], // API Trace Symbol('traceId') same as apiTraceId which is actually Entry Span ID,
exitCallsBreakup: trace.apiCalleeNameCount as Dictionary<string>
};
}
}

export interface ApiTraceDetailData extends TraceDetailData {
entrySpanId: string;
exitCallsBreakup: Dictionary<string>;
}