Skip to content

Commit 2d53b57

Browse files
authored
Supports optional properties for SummaryStatistics (#155)
* Make summary statistics optional * add test * bump version to 2.2.0
1 parent 668a671 commit 2d53b57

File tree

5 files changed

+303
-7
lines changed

5 files changed

+303
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## 2.2.0
6+
7+
- Make properties of `SummaryStatistics` optional
8+
59
## 2.1.2
610

711
- Security: Upgrade Go in build process to 1.19.3

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "grafana-x-ray-datasource",
3-
"version": "2.1.2",
3+
"version": "2.2.0",
44
"description": "AWS X-Ray data source",
55
"scripts": {
66
"build": "grafana-toolkit plugin:build",

src/DataSource.test.ts

Lines changed: 275 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ import {
99
ScopedVars,
1010
VariableModel,
1111
} from '@grafana/data';
12-
import { XrayJsonData, XrayQuery, XrayQueryType, XrayTraceDataRaw, XrayTraceDataSegmentDocument } from './types';
12+
import {
13+
XrayJsonData,
14+
XrayQuery,
15+
XrayQueryType,
16+
XrayService,
17+
XrayTraceDataRaw,
18+
XrayTraceDataSegmentDocument,
19+
} from './types';
1320
import { of } from 'rxjs';
1421
import { TemplateSrv } from '@grafana/runtime';
1522

@@ -77,6 +84,22 @@ describe('XrayDataSource', () => {
7784
});
7885
});
7986

87+
it('returns parsed data when querying service map', async () => {
88+
const ds = makeDatasourceWithResponse(makeServiceMapResponse());
89+
const response = await ds.query(makeQuery({ queryType: XrayQueryType.getServiceMap, query: '' })).toPromise();
90+
expect(response.data.length).toBe(2);
91+
const nodes: DataFrame = response.data[0];
92+
expect(nodes.fields.length).toBe(9);
93+
const edges: DataFrame = response.data[1];
94+
expect(edges.fields.length).toBe(7);
95+
expect(edges.fields.find((f) => f.name === 'mainStat')?.values.toArray()).toEqual(
96+
expect.arrayContaining(['N/A'])
97+
);
98+
expect(edges.fields.find((f) => f.name === 'secondaryStat')?.values.toArray()).toEqual(
99+
expect.arrayContaining([undefined])
100+
);
101+
});
102+
80103
it('should parse insight response correctly', async () => {
81104
const ds = makeDatasourceWithResponse(makeInsightResponse());
82105
const response = await ds.query(makeQuery({ queryType: XrayQueryType.getInsights, query: '' })).toPromise();
@@ -214,6 +237,244 @@ function makeTrace(): XrayTraceDataRaw {
214237
};
215238
}
216239

240+
function makeServiceMapWithLinkedEdge() {
241+
const serviceMap: XrayService[] = [
242+
{
243+
AccountId: null,
244+
DurationHistogram: [
245+
{ Count: 1, Value: 0.375 },
246+
{ Count: 1, Value: 0.012 },
247+
],
248+
Edges: [
249+
{
250+
Aliases: [],
251+
EndTime: 9,
252+
ReferenceId: 1,
253+
ResponseTimeHistogram: [
254+
{ Count: 1, Value: 0.375 },
255+
{ Count: 1, Value: 0.012 },
256+
],
257+
StartTime: 1,
258+
SummaryStatistics: {
259+
ErrorStatistics: { OtherCount: 0, ThrottleCount: 0, TotalCount: 0 },
260+
FaultStatistics: { OtherCount: 0, TotalCount: 0 },
261+
OkCount: 2,
262+
TotalCount: 2,
263+
TotalResponseTime: 0.387,
264+
},
265+
},
266+
],
267+
EndTime: 9,
268+
Name: 'ProcessSQSRecord',
269+
Names: ['ProcessSQSRecord'],
270+
ReferenceId: 0,
271+
ResponseTimeHistogram: [
272+
{ Count: 1, Value: 0.375 },
273+
{ Count: 1, Value: 0.012 },
274+
],
275+
Root: null,
276+
StartTime: 1,
277+
State: 'active',
278+
SummaryStatistics: {
279+
ErrorStatistics: { OtherCount: 0, ThrottleCount: 0, TotalCount: 0 },
280+
FaultStatistics: { OtherCount: 0, TotalCount: 0 },
281+
OkCount: 2,
282+
TotalCount: 2,
283+
TotalResponseTime: 0.387,
284+
},
285+
Type: 'AWS::Lambda',
286+
},
287+
{
288+
AccountId: '1',
289+
DurationHistogram: [
290+
{ Count: 1, Value: 0.002 },
291+
{ Count: 1, Value: 0.242 },
292+
],
293+
Edges: [],
294+
EndTime: 9,
295+
Name: 'ProcessSQSRecord',
296+
Names: ['ProcessSQSRecord'],
297+
ReferenceId: 1,
298+
ResponseTimeHistogram: [
299+
{ Count: 1, Value: 0.002 },
300+
{ Count: 1, Value: 0.013 },
301+
],
302+
Root: null,
303+
StartTime: 1,
304+
State: 'active',
305+
SummaryStatistics: {
306+
ErrorStatistics: { OtherCount: 0, ThrottleCount: 0, TotalCount: 0 },
307+
FaultStatistics: { OtherCount: 0, TotalCount: 0 },
308+
OkCount: 2,
309+
TotalCount: 2,
310+
TotalResponseTime: 0.014,
311+
},
312+
Type: 'AWS::Lambda::Function',
313+
},
314+
{
315+
AccountId: null,
316+
DurationHistogram: [
317+
{ Count: 1, Value: 0.506 },
318+
{ Count: 33, Value: 0.002 },
319+
{ Count: 147, Value: -0 },
320+
{ Count: 2, Value: 0.522 },
321+
{ Count: 1, Value: 0.51 },
322+
{ Count: 2, Value: 0.507 },
323+
{ Count: 1, Value: 0.508 },
324+
{ Count: 333, Value: 0.501 },
325+
{ Count: 160, Value: 0.503 },
326+
{ Count: 497, Value: 0.001 },
327+
{ Count: 1, Value: 0.514 },
328+
{ Count: 2, Value: 0.509 },
329+
{ Count: 2, Value: 0.505 },
330+
{ Count: 9, Value: 0.504 },
331+
{ Count: 2326, Value: 0.502 },
332+
{ Count: 36, Value: 0.044 },
333+
],
334+
Edges: [
335+
{
336+
Aliases: [],
337+
EndTime: 9,
338+
ReferenceId: 4,
339+
ResponseTimeHistogram: [
340+
{ Count: 1, Value: 0.073 },
341+
{ Count: 1, Value: 0.117 },
342+
],
343+
StartTime: 1,
344+
SummaryStatistics: {
345+
ErrorStatistics: { OtherCount: 0, ThrottleCount: 0, TotalCount: 0 },
346+
FaultStatistics: { OtherCount: 0, TotalCount: 0 },
347+
OkCount: 2,
348+
TotalCount: 2,
349+
TotalResponseTime: 0.19,
350+
},
351+
},
352+
],
353+
EndTime: 9,
354+
Name: 'SampleSite',
355+
Names: ['SampleSite'],
356+
ReferenceId: 2,
357+
ResponseTimeHistogram: [
358+
{ Count: 1, Value: 0.506 },
359+
{ Count: 33, Value: 0.002 },
360+
{ Count: 147, Value: -0 },
361+
{ Count: 2, Value: 0.522 },
362+
{ Count: 1, Value: 0.51 },
363+
{ Count: 2, Value: 0.507 },
364+
{ Count: 1, Value: 0.508 },
365+
{ Count: 333, Value: 0.501 },
366+
{ Count: 160, Value: 0.503 },
367+
{ Count: 497, Value: 0.001 },
368+
{ Count: 1, Value: 0.514 },
369+
{ Count: 2, Value: 0.509 },
370+
{ Count: 2, Value: 0.505 },
371+
{ Count: 9, Value: 0.504 },
372+
{ Count: 2326, Value: 0.502 },
373+
{ Count: 36, Value: 0.044 },
374+
],
375+
Root: true,
376+
StartTime: 1,
377+
State: 'active',
378+
SummaryStatistics: {
379+
ErrorStatistics: { OtherCount: 711, ThrottleCount: 0, TotalCount: 711 },
380+
FaultStatistics: { OtherCount: 0, TotalCount: 0 },
381+
OkCount: 2842,
382+
TotalCount: 3553,
383+
TotalResponseTime: 1427.793,
384+
},
385+
Type: 'AWS::ElasticBeanstalk::Environment',
386+
},
387+
{
388+
AccountId: null,
389+
DurationHistogram: [],
390+
Edges: [
391+
{
392+
Aliases: [],
393+
EndTime: 9,
394+
ReferenceId: 2,
395+
ResponseTimeHistogram: [
396+
{ Count: 1, Value: 0.506 },
397+
{ Count: 33, Value: 0.002 },
398+
{ Count: 147, Value: -0 },
399+
{ Count: 2, Value: 0.522 },
400+
{ Count: 1, Value: 0.51 },
401+
{ Count: 2, Value: 0.507 },
402+
{ Count: 1, Value: 0.508 },
403+
{ Count: 333, Value: 0.501 },
404+
{ Count: 160, Value: 0.503 },
405+
{ Count: 497, Value: 0.001 },
406+
{ Count: 1, Value: 0.514 },
407+
{ Count: 2, Value: 0.509 },
408+
{ Count: 2, Value: 0.505 },
409+
{ Count: 9, Value: 0.504 },
410+
{ Count: 2326, Value: 0.502 },
411+
{ Count: 36, Value: 0.044 },
412+
],
413+
StartTime: 1,
414+
SummaryStatistics: {
415+
ErrorStatistics: {
416+
OtherCount: 711,
417+
ThrottleCount: 0,
418+
TotalCount: 711,
419+
},
420+
FaultStatistics: { OtherCount: 0, TotalCount: 0 },
421+
OkCount: 2842,
422+
TotalCount: 3553,
423+
TotalResponseTime: 1427.793,
424+
},
425+
},
426+
],
427+
EndTime: 9,
428+
Name: 'SampleSite',
429+
Names: ['SampleSite'],
430+
ReferenceId: 3,
431+
ResponseTimeHistogram: [],
432+
Root: null,
433+
StartTime: 1,
434+
State: 'unknown',
435+
SummaryStatistics: {},
436+
Type: 'client',
437+
},
438+
{
439+
AccountId: null,
440+
DurationHistogram: [
441+
{ Count: 1, Value: 0.073 },
442+
{ Count: 1, Value: 0.117 },
443+
],
444+
Edges: [
445+
{
446+
Aliases: [],
447+
EndTime: 9,
448+
ReferenceId: 0,
449+
ResponseTimeHistogram: [],
450+
StartTime: 1,
451+
SummaryStatistics: {},
452+
},
453+
],
454+
EndTime: 9,
455+
Name: 'https://sqs.us-east-1.amazonaws.com/123456789012/SampleQueue',
456+
Names: ['https://sqs.us-east-1.amazonaws.com/123456789012/SampleQueue'],
457+
ReferenceId: 4,
458+
ResponseTimeHistogram: [
459+
{ Count: 1, Value: 0.073 },
460+
{ Count: 1, Value: 0.117 },
461+
],
462+
Root: null,
463+
StartTime: 1,
464+
State: 'unknown',
465+
SummaryStatistics: {
466+
ErrorStatistics: { OtherCount: 0, ThrottleCount: 0, TotalCount: 0 },
467+
FaultStatistics: { OtherCount: 0, TotalCount: 0 },
468+
OkCount: 2,
469+
TotalCount: 2,
470+
TotalResponseTime: 0.19,
471+
},
472+
Type: 'AWS::SQS::Queue',
473+
},
474+
];
475+
return serviceMap.map((json) => JSON.stringify(json));
476+
}
477+
217478
function makeTraceSummariesResponse(): DataFrame {
218479
return new MutableDataFrame({
219480
name: 'TraceSummaries',
@@ -250,6 +511,19 @@ function makeInsightResponse(): DataFrame {
250511
});
251512
}
252513

514+
function makeServiceMapResponse(): DataFrame {
515+
return new MutableDataFrame({
516+
name: 'ServiceMap',
517+
fields: [
518+
{
519+
name: 'Service',
520+
type: FieldType.string,
521+
values: new ArrayVector(makeServiceMapWithLinkedEdge()),
522+
},
523+
],
524+
});
525+
}
526+
253527
function makeTraceResponse(trace: XrayTraceDataRaw): DataFrame {
254528
return new MutableDataFrame({
255529
name: 'Traces',

src/types.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,11 @@ interface HistogramValue {
194194
}
195195

196196
export interface SummaryStatistics {
197-
ErrorStatistics: { OtherCount: number; ThrottleCount: number; TotalCount: number };
198-
FaultStatistics: { OtherCount: number; TotalCount: number };
199-
OkCount: number;
200-
TotalCount: number;
201-
TotalResponseTime: number;
197+
ErrorStatistics?: { OtherCount: number; ThrottleCount: number; TotalCount: number };
198+
FaultStatistics?: { OtherCount: number; TotalCount: number };
199+
OkCount?: number;
200+
TotalCount?: number;
201+
TotalResponseTime?: number;
202202
}
203203

204204
export interface XrayEdge {

src/utils/transform.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,26 +475,44 @@ export function parseGraphResponse(response: DataFrame, query?: XrayQuery, optio
475475
}
476476

477477
export function avgResponseTime(statistics: SummaryStatistics) {
478+
if (!statistics.TotalResponseTime || !statistics.TotalCount) {
479+
return 0;
480+
}
478481
return (statistics.TotalResponseTime / statistics.TotalCount) * 1000;
479482
}
480483

481484
export function tracesPerMinute(statistics: SummaryStatistics, startTime: number | string, endTime: number | string) {
485+
if (!statistics.TotalCount) {
486+
return undefined;
487+
}
482488
return endTime && startTime ? statistics.TotalCount / ((toMs(endTime) - toMs(startTime)) / (60 * 1000)) : undefined;
483489
}
484490

485491
export function successPercentage(statistics: SummaryStatistics) {
492+
if (!statistics.OkCount || !statistics.TotalCount) {
493+
return 0;
494+
}
486495
return statistics.OkCount / statistics.TotalCount;
487496
}
488497

489498
export function throttledPercentage(statistics: SummaryStatistics) {
499+
if (!statistics.ErrorStatistics || !statistics.TotalCount) {
500+
return 0;
501+
}
490502
return statistics.ErrorStatistics.ThrottleCount / statistics.TotalCount;
491503
}
492504

493505
export function errorsPercentage(statistics: SummaryStatistics) {
506+
if (!statistics.ErrorStatistics || !statistics.TotalCount) {
507+
return 0;
508+
}
494509
return (statistics.ErrorStatistics.TotalCount - statistics.ErrorStatistics.ThrottleCount) / statistics.TotalCount;
495510
}
496511

497512
export function faultsPercentage(statistics: SummaryStatistics) {
513+
if (!statistics.FaultStatistics || !statistics.TotalCount) {
514+
return 0;
515+
}
498516
return statistics.FaultStatistics.TotalCount / statistics.TotalCount;
499517
}
500518

0 commit comments

Comments
 (0)