@uoa/lambda-tracing 2.0.2 → 2.1.0-beta.2

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/changelog.md ADDED
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+
3
+ ## 2.1.0
4
+ - Unexpected errors are now caught within the library. When this occurs, the request promise will reject with the error.
5
+ - http response promises will now be rejected if the response code is not in the 2xx range
6
+ - The response content-type header is now correctly checked to convert the response body. Previously the response transformation was checking the content-type header of the request. If the content-type header is not present, it will attempt to transform the response to JSON.
7
+ - Added support for XML responses - these will be parsed to an object
8
+ - Added support for Image responses - these will be parsed to a base64 string
9
+
10
+ ## [Deprecated] 2.0.0, 2.0.1, 2.0.2
11
+ - Changes for Zipkin which have since been removed
12
+ - Do not use these versions
13
+
14
+ ## 1.6.0
15
+ - Fix error when logged message was undefined
16
+
17
+ ## 1.5.0
18
+ - Generate a new span ID instead of using that of the incoming request.
19
+ - Use the incoming request's span ID as the current span's parent span ID.
20
+
21
+ ## 1.4.0
22
+ - Add support for 16 and 32 character trace IDs
23
+ - Add function to allow getting and setting the X-B3-Info header
24
+
25
+ ## 1.3.0
26
+ - Add optional port parameter to all functions in uoaHttps module. Defaults to 443 if not specified
27
+
28
+ ## 1.2.0
29
+ - Fix newlines not logging correctly in logging module
30
+
31
+ ## 1.1.1
32
+ - Update readme with information on Kong plugin requirements
33
+
34
+ ## 1.1.0
35
+ - Add uoaHttps module to propagate tracing headers through http requests
36
+
37
+ ## 1.0.1
38
+ - Fix formatting in readme
39
+
40
+ ## 1.0.0
41
+ - Initial release with Lambda tracing & logging functionality
package/dist/tracing.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { Tracer } from "@opentelemetry/api";
2
- export declare function initializeTracing(serviceName: string): void;
3
- export declare function getTracer(): Tracer;
1
+ export declare function initializeTracing(): void;
4
2
  export declare function getTraceInfoHeader(): string;
5
3
  export declare function setTraceInfoHeader(info: string): void;
package/dist/tracing.js CHANGED
@@ -1,23 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setTraceInfoHeader = exports.getTraceInfoHeader = exports.getTracer = exports.initializeTracing = void 0;
3
+ exports.setTraceInfoHeader = exports.getTraceInfoHeader = exports.initializeTracing = void 0;
4
4
  const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
5
5
  const instrumentation_aws_lambda_1 = require("@opentelemetry/instrumentation-aws-lambda");
6
6
  const instrumentation_1 = require("@opentelemetry/instrumentation");
7
7
  const UoaB3Propagator_1 = require("./UoaB3Propagator");
8
8
  const api_1 = require("@opentelemetry/api");
9
9
  const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
10
- const zipkin_1 = require("./zipkin/zipkin");
11
10
  const provider = new sdk_trace_node_1.NodeTracerProvider({ sampler: new sdk_trace_base_1.AlwaysOnSampler() });
12
11
  let infoHeader;
13
- let tracer;
14
- let name;
15
- function initializeTracing(serviceName) {
16
- const options = {
17
- url: process.env.zipkinUrl ? process.env.zipkinUrl : 'http://internal-zipkin-uoa-its-nonprod-internal-1407434909.ap-southeast-2.elb.amazonaws.com:443/api/v2/spans',
18
- serviceName: serviceName
19
- };
20
- provider.addSpanProcessor(new sdk_trace_node_1.BatchSpanProcessor(new zipkin_1.ZipkinExporter(options)));
12
+ function initializeTracing() {
21
13
  provider.register({
22
14
  propagator: new UoaB3Propagator_1.UoaB3Propagator()
23
15
  });
@@ -38,19 +30,8 @@ function initializeTracing(serviceName) {
38
30
  })
39
31
  ]
40
32
  });
41
- name = serviceName;
42
- tracer = api_1.trace.getTracer(serviceName);
43
33
  }
44
34
  exports.initializeTracing = initializeTracing;
45
- function getTracer() {
46
- if (tracer) {
47
- return tracer;
48
- }
49
- else {
50
- return api_1.trace.getTracer(name);
51
- }
52
- }
53
- exports.getTracer = getTracer;
54
35
  function getTraceInfoHeader() {
55
36
  if (infoHeader) {
56
37
  return infoHeader;
package/dist/uoaHttps.js CHANGED
@@ -22,19 +22,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
25
  Object.defineProperty(exports, "__esModule", { value: true });
35
26
  const https = __importStar(require("https"));
36
27
  const api_1 = require("@opentelemetry/api");
37
- const tracing_1 = require("./tracing");
28
+ const fast_xml_parser_1 = require("fast-xml-parser");
38
29
  function request(...args) {
39
30
  if (args[2]) {
40
31
  api_1.propagation.inject(api_1.context.active(), args[1].headers);
@@ -45,224 +36,128 @@ function request(...args) {
45
36
  return https.request(args[0], args[1]);
46
37
  }
47
38
  }
48
- function doGetRequest(hostname, path, headers, port = 443) {
49
- return __awaiter(this, void 0, void 0, function* () {
50
- return new Promise(function (resolve, reject) {
51
- const options = {
52
- "method": "GET",
53
- "hostname": hostname,
54
- "path": path,
55
- "headers": headers,
56
- "port": port
57
- };
58
- api_1.propagation.inject(api_1.context.active(), options.headers);
59
- const req = https.request(options, function (response) {
60
- const chunks = [];
61
- response.on("data", function (chunk) {
62
- chunks.push(chunk);
63
- });
64
- response.on("end", function () {
65
- let body = Buffer.concat(chunks);
66
- if (options.headers['Content-Type'] === 'application/json') {
67
- body = JSON.parse(body.toString());
68
- }
69
- else {
70
- body = body.toString();
71
- }
72
- resolve(body);
73
- });
74
- response.on("error", function (e) {
75
- reject(e);
76
- });
77
- });
78
- req.end();
79
- });
39
+ async function doGetRequest(hostname, path, headers, port = 443) {
40
+ return new Promise(function (resolve, reject) {
41
+ const options = {
42
+ "method": "GET",
43
+ "hostname": hostname,
44
+ "path": path,
45
+ "headers": headers,
46
+ "port": port
47
+ };
48
+ api_1.propagation.inject(api_1.context.active(), options.headers);
49
+ const req = doHttpsRequest(options, resolve, reject);
50
+ req.end();
80
51
  });
81
52
  }
82
- function doGetRequestExternal(hostname, path, headers, port = 443) {
83
- return __awaiter(this, void 0, void 0, function* () {
84
- return (0, tracing_1.getTracer)().startActiveSpan(hostname + path, (span) => __awaiter(this, void 0, void 0, function* () {
85
- const result = yield doGetRequest(hostname, path, headers, port);
86
- span.end();
87
- return result;
88
- }));
53
+ async function doPostRequest(hostname, path, headers, data, port = 443) {
54
+ return new Promise(function (resolve, reject) {
55
+ const options = {
56
+ "method": "POST",
57
+ "hostname": hostname,
58
+ "path": path,
59
+ "headers": headers,
60
+ "port": port
61
+ };
62
+ api_1.propagation.inject(api_1.context.active(), options.headers);
63
+ const req = doHttpsRequest(options, resolve, reject);
64
+ setRequestBody(req, data);
65
+ req.end();
89
66
  });
90
67
  }
91
- function doPostRequest(hostname, path, headers, data, port = 443) {
92
- return __awaiter(this, void 0, void 0, function* () {
93
- return new Promise(function (resolve, reject) {
94
- const options = {
95
- "method": "POST",
96
- "hostname": hostname,
97
- "path": path,
98
- "headers": headers,
99
- "port": port
100
- };
101
- api_1.propagation.inject(api_1.context.active(), options.headers);
102
- const req = https.request(options, function (response) {
103
- const chunks = [];
104
- response.on("data", function (chunk) {
105
- chunks.push(chunk);
106
- });
107
- response.on("end", function () {
108
- if (response.statusCode == 204) {
109
- //204 is no content, and most JSON parses blow up on an empty string
110
- resolve(null);
111
- }
112
- else {
113
- let body = Buffer.concat(chunks);
114
- if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
115
- body = JSON.parse(body.toString());
116
- }
117
- else {
118
- body = body.toString();
119
- }
120
- resolve(body);
121
- }
122
- });
123
- response.on("error", function (e) {
124
- reject(e);
125
- });
126
- });
127
- if (data) {
128
- if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
129
- //We serialize using JSON.stringify as a default, or if a JSON is specified
130
- req.write(JSON.stringify(data));
131
- }
132
- else {
133
- // If another content-type is specified however, we respect the serialization provided
134
- req.write(data);
135
- }
136
- }
137
- req.end();
138
- });
68
+ async function doPutRequest(hostname, path, headers, data, port = 443) {
69
+ return new Promise(function (resolve, reject) {
70
+ const options = {
71
+ "method": "PUT",
72
+ "hostname": hostname,
73
+ "path": path,
74
+ "headers": headers,
75
+ "port": port
76
+ };
77
+ api_1.propagation.inject(api_1.context.active(), options.headers);
78
+ const req = doHttpsRequest(options, resolve, reject);
79
+ setRequestBody(req, data);
80
+ req.end();
139
81
  });
140
82
  }
141
- function doPostRequestExternal(hostname, path, headers, data, port = 443) {
142
- return __awaiter(this, void 0, void 0, function* () {
143
- return (0, tracing_1.getTracer)().startActiveSpan(hostname + path, (span) => __awaiter(this, void 0, void 0, function* () {
144
- const result = yield doPostRequest(hostname, path, headers, port);
145
- span.end();
146
- return result;
147
- }));
83
+ async function doDeleteRequest(hostname, path, headers, port = 443) {
84
+ return new Promise(function (resolve, reject) {
85
+ const options = {
86
+ "method": "DELETE",
87
+ "hostname": hostname,
88
+ "path": path,
89
+ "headers": headers,
90
+ "port": port
91
+ };
92
+ api_1.propagation.inject(api_1.context.active(), options.headers);
93
+ const req = doHttpsRequest(options, resolve, reject);
94
+ req.end();
148
95
  });
149
96
  }
150
- function doPutRequest(hostname, path, headers, data, port = 443) {
151
- return __awaiter(this, void 0, void 0, function* () {
152
- return new Promise(function (resolve, reject) {
153
- const options = {
154
- "method": "PUT",
155
- "hostname": hostname,
156
- "path": path,
157
- "headers": headers,
158
- "port": port
159
- };
160
- api_1.propagation.inject(api_1.context.active(), options.headers);
161
- const req = https.request(options, function (response) {
162
- const chunks = [];
163
- response.on("data", function (chunk) {
164
- chunks.push(chunk);
165
- });
166
- response.on("end", function () {
167
- if (response.statusCode == 204) {
168
- //204 is no content, and most JSON parses blow up on an empty string
169
- resolve(null);
97
+ function doHttpsRequest(options, resolve, reject) {
98
+ return https.request(options, function (response) {
99
+ const chunks = [];
100
+ response.on("data", function (chunk) {
101
+ chunks.push(chunk);
102
+ });
103
+ response.on("end", function () {
104
+ if (response.statusCode === 204) {
105
+ //204 is no content, and most JSON parses blow up on an empty string
106
+ resolve(null);
107
+ }
108
+ else {
109
+ try {
110
+ let body = Buffer.concat(chunks);
111
+ let parsedBody = body.toString();
112
+ //Get the response content-type header value so we can apply different parsing methods
113
+ const responseContentType = response.headers["content-type"]?.toLowerCase() ?? '';
114
+ if (responseContentType === '' || responseContentType.includes('application/json')) {
115
+ parsedBody = JSON.parse(body.toString());
116
+ }
117
+ else if (responseContentType.includes('application/xml') || responseContentType.includes('text/xml')) {
118
+ const parser = new fast_xml_parser_1.XMLParser({
119
+ ignoreDeclaration: true,
120
+ ignorePiTags: true
121
+ });
122
+ parsedBody = parser.parse(body.toString());
123
+ }
124
+ else if (responseContentType.includes('image/')) {
125
+ parsedBody = body.toString('base64');
126
+ }
127
+ if (response.statusCode !== undefined && response.statusCode >= 200 && response.statusCode < 300) {
128
+ resolve(parsedBody);
170
129
  }
171
130
  else {
172
- let body = Buffer.concat(chunks);
173
- if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
174
- body = JSON.parse(body.toString());
175
- }
176
- else {
177
- body = body.toString();
178
- }
179
- resolve(body);
131
+ reject(parsedBody);
180
132
  }
181
- });
182
- response.on("error", function (e) {
183
- reject(e);
184
- });
185
- });
186
- if (data) {
187
- if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
188
- //We serialize using JSON.stringify as a default, or if a JSON is specified
189
- req.write(JSON.stringify(data));
190
133
  }
191
- else {
192
- // If another content-type is specified however, we respect the serialization provided
193
- req.write(data);
134
+ catch (e) {
135
+ reject(e);
194
136
  }
195
137
  }
196
- req.end();
197
138
  });
198
- });
199
- }
200
- function doPutRequestExternal(hostname, path, headers, data, port = 443) {
201
- return __awaiter(this, void 0, void 0, function* () {
202
- return (0, tracing_1.getTracer)().startActiveSpan(hostname + path, (span) => __awaiter(this, void 0, void 0, function* () {
203
- const result = yield doPutRequest(hostname, path, headers, port);
204
- span.end();
205
- return result;
206
- }));
207
- });
208
- }
209
- function doDeleteRequest(hostname, path, headers, port = 443) {
210
- return __awaiter(this, void 0, void 0, function* () {
211
- return new Promise(function (resolve, reject) {
212
- const options = {
213
- "method": "DELETE",
214
- "hostname": hostname,
215
- "path": path,
216
- "headers": headers,
217
- "port": port
218
- };
219
- api_1.propagation.inject(api_1.context.active(), options.headers);
220
- const req = https.request(options, function (response) {
221
- const chunks = [];
222
- response.on("data", function (chunk) {
223
- chunks.push(chunk);
224
- });
225
- response.on("end", function () {
226
- if (response.statusCode == 204) {
227
- //204 is no content, and most JSON parses blow up on an empty string
228
- resolve(null);
229
- }
230
- else {
231
- let body = Buffer.concat(chunks);
232
- if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
233
- body = JSON.parse(body.toString());
234
- }
235
- else {
236
- body = body.toString();
237
- }
238
- resolve(body);
239
- }
240
- });
241
- response.on("error", function (e) {
242
- reject(e);
243
- });
244
- });
245
- req.end();
139
+ response.on("error", function (e) {
140
+ reject(e);
246
141
  });
247
142
  });
248
143
  }
249
- function doDeleteRequestExternal(hostname, path, headers, data, port = 443) {
250
- return __awaiter(this, void 0, void 0, function* () {
251
- return (0, tracing_1.getTracer)().startActiveSpan(hostname + path, (span) => __awaiter(this, void 0, void 0, function* () {
252
- const result = yield doDeleteRequest(hostname, path, headers, port);
253
- span.end();
254
- return result;
255
- }));
256
- });
144
+ function setRequestBody(request, data) {
145
+ if (data) {
146
+ const requestContentType = request.getHeader('content-type')?.toString() ?? '';
147
+ if (requestContentType === '' || requestContentType.includes('application/json')) {
148
+ //We serialize using JSON.stringify as a default, or if JSON is specified
149
+ request.write(JSON.stringify(data));
150
+ }
151
+ else {
152
+ // If another content-type is specified however, we respect the serialization provided
153
+ request.write(data);
154
+ }
155
+ }
257
156
  }
258
157
  module.exports = {
259
158
  request,
260
159
  doGetRequest,
261
160
  doPostRequest,
262
161
  doPutRequest,
263
- doDeleteRequest,
264
- doGetRequestExternal,
265
- doPostRequestExternal,
266
- doPutRequestExternal,
267
- doDeleteRequestExternal
162
+ doDeleteRequest
268
163
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uoa/lambda-tracing",
3
- "version": "2.0.2",
3
+ "version": "2.1.0-beta.2",
4
4
  "description": "Library for logging & distributed tracing in UoA Lambda projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,8 @@
19
19
  "types": "dist/tracing.d.ts",
20
20
  "scripts": {
21
21
  "test": "echo \"Error: no test specified\" && exit 1",
22
- "prepare": "tsc"
22
+ "prepare": "tsc",
23
+ "prepack": "tsc"
23
24
  },
24
25
  "exports": {
25
26
  ".": "./dist/tracing.js",
@@ -33,6 +34,7 @@
33
34
  "@opentelemetry/instrumentation": "^0.28.0",
34
35
  "@opentelemetry/instrumentation-aws-lambda": "^0.31.0",
35
36
  "@opentelemetry/sdk-trace-node": "^1.8.0",
37
+ "fast-xml-parser": "^4.3.4",
36
38
  "moment": "^2.29.3",
37
39
  "winston": "^3.7.2"
38
40
  },
package/tracing.ts CHANGED
@@ -1,23 +1,14 @@
1
- import {NodeTracerProvider, BatchSpanProcessor} from '@opentelemetry/sdk-trace-node';
1
+ import {NodeTracerProvider} from '@opentelemetry/sdk-trace-node';
2
2
  import {AwsLambdaInstrumentation} from '@opentelemetry/instrumentation-aws-lambda';
3
3
  import {registerInstrumentations} from '@opentelemetry/instrumentation';
4
4
  import {B3_INFO_KEY, UoaB3Propagator} from "./UoaB3Propagator";
5
- import {context, trace, Tracer} from "@opentelemetry/api";
5
+ import {context} from "@opentelemetry/api";
6
6
  import {AlwaysOnSampler} from "@opentelemetry/sdk-trace-base";
7
- import {ZipkinExporter} from "./zipkin/zipkin";
8
7
 
9
8
  const provider = new NodeTracerProvider({sampler: new AlwaysOnSampler()});
10
9
  let infoHeader: string | undefined;
11
- let tracer: Tracer | undefined;
12
- let name : string;
13
-
14
- export function initializeTracing(serviceName: string) {
15
- const options = {
16
- url: process.env.zipkinUrl ? process.env.zipkinUrl : 'http://internal-zipkin-uoa-its-nonprod-internal-1407434909.ap-southeast-2.elb.amazonaws.com:443/api/v2/spans',
17
- serviceName: serviceName
18
- }
19
- provider.addSpanProcessor(new BatchSpanProcessor(new ZipkinExporter(options)));
20
10
 
11
+ export function initializeTracing() {
21
12
  provider.register({
22
13
  propagator: new UoaB3Propagator()
23
14
  });
@@ -36,17 +27,7 @@ export function initializeTracing(serviceName: string) {
36
27
  disableAwsContextPropagation: true
37
28
  })
38
29
  ]
39
- })
40
- name = serviceName;
41
- tracer = trace.getTracer(serviceName);
42
- }
43
-
44
- export function getTracer(): Tracer {
45
- if (tracer) {
46
- return tracer;
47
- } else {
48
- return trace.getTracer(name);
49
- }
30
+ });
50
31
  }
51
32
 
52
33
  export function getTraceInfoHeader(): string {
@@ -60,4 +41,3 @@ export function getTraceInfoHeader(): string {
60
41
  export function setTraceInfoHeader(info: string) {
61
42
  infoHeader = info;
62
43
  }
63
-
package/tsconfig.json CHANGED
@@ -11,7 +11,7 @@
11
11
  // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12
12
 
13
13
  /* Language and Environment */
14
- "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
14
+ "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15
15
  // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16
16
  // "jsx": "preserve", /* Specify what JSX code is generated. */
17
17
  // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
@@ -25,7 +25,7 @@
25
25
  // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26
26
 
27
27
  /* Modules */
28
- "module": "commonjs", /* Specify what module code is generated. */
28
+ "module": "CommonJS", /* Specify what module code is generated. */
29
29
  // "rootDir": "./", /* Specify the root folder within your source files. */
30
30
  // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
31
31
  // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */