@henrique-olivier/network-listener 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,7 +73,20 @@ Exemplo de retorno:
73
73
  medianDurationMs: 700,
74
74
  p95DurationMs: 2300,
75
75
  affectedEndpointRatio: 0.2
76
- }
76
+ },
77
+ affectedEndpoints: [
78
+ {
79
+ normalizedRoute: '/api/reports',
80
+ requestCount: 7,
81
+ errorRate: 0,
82
+ timeoutRate: 0,
83
+ slowRequestRate: 1,
84
+ medianDurationMs: 1800,
85
+ p95DurationMs: 2300,
86
+ statusCodes: [],
87
+ issueTypes: ['slow']
88
+ }
89
+ ]
77
90
  }
78
91
  ```
79
92
 
@@ -44,6 +44,118 @@ function countRoutes(events) {
44
44
  }
45
45
  return count;
46
46
  }
47
+ function percentile(sortedValues, percentileValue) {
48
+ var index;
49
+ if (sortedValues.length === 0) {
50
+ return 0;
51
+ }
52
+ index = Math.ceil((percentileValue / 100) * sortedValues.length) - 1;
53
+ if (index < 0) {
54
+ index = 0;
55
+ }
56
+ return sortedValues[index];
57
+ }
58
+ function pushUniqueString(values, value) {
59
+ if (values.indexOf(value) < 0) {
60
+ values.push(value);
61
+ }
62
+ }
63
+ function pushUniqueNumber(values, value) {
64
+ if (values.indexOf(value) < 0) {
65
+ values.push(value);
66
+ }
67
+ }
68
+ function getEndpointIssueType(event, slowRequestThresholdMs) {
69
+ if (event.timedOut) {
70
+ return 'timeout';
71
+ }
72
+ if (event.durationMs >= slowRequestThresholdMs) {
73
+ return 'slow';
74
+ }
75
+ if (event.errorType) {
76
+ return event.errorType;
77
+ }
78
+ if (typeof event.status === 'number' && event.status >= 500) {
79
+ return 'http-server';
80
+ }
81
+ if (typeof event.status === 'number' && event.status >= 400) {
82
+ return 'http-client';
83
+ }
84
+ return undefined;
85
+ }
86
+ function buildAffectedEndpoints(events, slowRequestThresholdMs) {
87
+ var grouped = {};
88
+ var result = [];
89
+ var i;
90
+ var event;
91
+ var route;
92
+ var item;
93
+ var issueType;
94
+ for (i = 0; i < events.length; i += 1) {
95
+ event = events[i];
96
+ route = event.normalizedRoute;
97
+ if (!grouped[route]) {
98
+ grouped[route] = {
99
+ normalizedRoute: route,
100
+ requestCount: 0,
101
+ errors: 0,
102
+ timeouts: 0,
103
+ slowRequests: 0,
104
+ durations: [],
105
+ statusCodes: [],
106
+ issueTypes: [],
107
+ };
108
+ }
109
+ item = grouped[route];
110
+ item.requestCount += 1;
111
+ item.durations.push(event.durationMs);
112
+ if (!event.success) {
113
+ item.errors += 1;
114
+ }
115
+ if (event.timedOut) {
116
+ item.timeouts += 1;
117
+ }
118
+ if (event.durationMs >= slowRequestThresholdMs) {
119
+ item.slowRequests += 1;
120
+ }
121
+ if (typeof event.status === 'number' && event.status >= 400) {
122
+ pushUniqueNumber(item.statusCodes, event.status);
123
+ }
124
+ issueType = getEndpointIssueType(event, slowRequestThresholdMs);
125
+ if (issueType) {
126
+ pushUniqueString(item.issueTypes, issueType);
127
+ }
128
+ }
129
+ for (route in grouped) {
130
+ if (Object.prototype.hasOwnProperty.call(grouped, route)) {
131
+ item = grouped[route];
132
+ if (item.issueTypes.length > 0) {
133
+ item.durations.sort(function (a, b) {
134
+ return a - b;
135
+ });
136
+ result.push({
137
+ normalizedRoute: item.normalizedRoute,
138
+ requestCount: item.requestCount,
139
+ errorRate: item.errors / item.requestCount,
140
+ timeoutRate: item.timeouts / item.requestCount,
141
+ slowRequestRate: item.slowRequests / item.requestCount,
142
+ medianDurationMs: percentile(item.durations, 50),
143
+ p95DurationMs: percentile(item.durations, 95),
144
+ statusCodes: item.statusCodes.sort(function (a, b) {
145
+ return a - b;
146
+ }),
147
+ issueTypes: item.issueTypes,
148
+ });
149
+ }
150
+ }
151
+ }
152
+ result.sort(function (a, b) {
153
+ var aScore = a.errorRate + a.timeoutRate + a.slowRequestRate;
154
+ var bScore = b.errorRate + b.timeoutRate + b.slowRequestRate;
155
+ return bScore - aScore;
156
+ });
157
+ return result;
158
+ }
47
159
  function buildDiagnosis(status, probableCause, confidenceLevel, reasons, events, slowRequestThresholdMs) {
48
160
  return {
49
161
  status: status,
@@ -51,6 +163,7 @@ function buildDiagnosis(status, probableCause, confidenceLevel, reasons, events,
51
163
  confidenceLevel: confidenceLevel,
52
164
  reasons: reasons,
53
165
  summary: (0, metricsStore_1.calculateSummary)(events, slowRequestThresholdMs),
166
+ affectedEndpoints: buildAffectedEndpoints(events, slowRequestThresholdMs),
54
167
  };
55
168
  }
56
169
  function diagnoseNetwork(events, options) {
@@ -28,12 +28,25 @@ export type NetworkSummary = {
28
28
  p95DurationMs: number;
29
29
  affectedEndpointRatio: number;
30
30
  };
31
+ export type EndpointIssueType = 'slow' | 'timeout' | 'http-client' | 'http-server' | 'network' | 'aborted' | 'unknown';
32
+ export type EndpointDiagnosis = {
33
+ normalizedRoute: string;
34
+ requestCount: number;
35
+ errorRate: number;
36
+ timeoutRate: number;
37
+ slowRequestRate: number;
38
+ medianDurationMs: number;
39
+ p95DurationMs: number;
40
+ statusCodes: number[];
41
+ issueTypes: EndpointIssueType[];
42
+ };
31
43
  export type NetworkDiagnosis = {
32
44
  status: NetworkStatus;
33
45
  probableCause: ProbableCause;
34
46
  confidenceLevel: ConfidenceLevel;
35
47
  reasons: string[];
36
48
  summary: NetworkSummary;
49
+ affectedEndpoints: EndpointDiagnosis[];
37
50
  };
38
51
  export type RouteNormalizer = (url: string) => string;
39
52
  export type NetworkListenerOptions = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henrique-olivier/network-listener",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "POC de uma biblioteca leve para observar requisicoes HTTP e gerar diagnosticos provaveis.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",