@uoa/lambda-tracing 1.0.0 → 1.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/dist/uoaHttps.js CHANGED
@@ -22,6 +22,15 @@ 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
+ };
25
34
  Object.defineProperty(exports, "__esModule", { value: true });
26
35
  const https = __importStar(require("https"));
27
36
  const api_1 = require("@opentelemetry/api");
@@ -35,17 +44,175 @@ function request(...args) {
35
44
  return https.request(args[0], args[1]);
36
45
  }
37
46
  }
38
- function get(...args) {
39
- if (args[2]) {
40
- api_1.propagation.inject(api_1.context.active(), args[1].headers);
41
- return https.get(args[0], args[1], args[2]);
42
- }
43
- else {
44
- api_1.propagation.inject(api_1.context.active(), args[0].headers);
45
- return https.get(args[0], args[1]);
46
- }
47
+ function doGetRequest(hostname, path, headers) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ return new Promise(function (resolve, reject) {
50
+ const options = {
51
+ "method": "GET",
52
+ "hostname": hostname,
53
+ "path": path,
54
+ "headers": headers
55
+ };
56
+ api_1.propagation.inject(api_1.context.active(), options.headers);
57
+ const req = https.request(options, function (response) {
58
+ const chunks = [];
59
+ response.on("data", function (chunk) {
60
+ chunks.push(chunk);
61
+ });
62
+ response.on("end", function () {
63
+ let body = Buffer.concat(chunks);
64
+ body = JSON.parse(body.toString());
65
+ resolve(body);
66
+ });
67
+ response.on("error", function (e) {
68
+ reject(e);
69
+ });
70
+ });
71
+ req.end();
72
+ });
73
+ });
74
+ }
75
+ function doPostRequest(hostname, path, headers, data) {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ return new Promise(function (resolve, reject) {
78
+ const options = {
79
+ "method": "POST",
80
+ "hostname": hostname,
81
+ "path": path,
82
+ "headers": headers
83
+ };
84
+ api_1.propagation.inject(api_1.context.active(), options.headers);
85
+ const req = https.request(options, function (response) {
86
+ const chunks = [];
87
+ response.on("data", function (chunk) {
88
+ chunks.push(chunk);
89
+ });
90
+ response.on("end", function () {
91
+ if (response.statusCode == 204) {
92
+ //204 is no content, and most JSON parses blow up on an empty string
93
+ resolve(null);
94
+ }
95
+ else {
96
+ let body = Buffer.concat(chunks);
97
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
98
+ body = JSON.parse(body.toString());
99
+ }
100
+ else {
101
+ body = body.toString();
102
+ }
103
+ resolve(body);
104
+ }
105
+ });
106
+ response.on("error", function (e) {
107
+ reject(e);
108
+ });
109
+ });
110
+ if (data) {
111
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
112
+ //We serialize using JSON.stringify as a default, or if a JSON is specified
113
+ req.write(JSON.stringify(data));
114
+ }
115
+ else {
116
+ // If another content-type is specified however, we respect the serialization provided
117
+ req.write(data);
118
+ }
119
+ }
120
+ req.end();
121
+ });
122
+ });
123
+ }
124
+ function doPutRequest(hostname, path, headers, data) {
125
+ return __awaiter(this, void 0, void 0, function* () {
126
+ return new Promise(function (resolve, reject) {
127
+ const options = {
128
+ "method": "PUT",
129
+ "hostname": hostname,
130
+ "path": path,
131
+ "headers": headers
132
+ };
133
+ api_1.propagation.inject(api_1.context.active(), options.headers);
134
+ const req = https.request(options, function (response) {
135
+ const chunks = [];
136
+ response.on("data", function (chunk) {
137
+ chunks.push(chunk);
138
+ });
139
+ response.on("end", function () {
140
+ if (response.statusCode == 204) {
141
+ //204 is no content, and most JSON parses blow up on an empty string
142
+ resolve(null);
143
+ }
144
+ else {
145
+ let body = Buffer.concat(chunks);
146
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
147
+ body = JSON.parse(body.toString());
148
+ }
149
+ else {
150
+ body = body.toString();
151
+ }
152
+ resolve(body);
153
+ }
154
+ });
155
+ response.on("error", function (e) {
156
+ reject(e);
157
+ });
158
+ });
159
+ if (data) {
160
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
161
+ //We serialize using JSON.stringify as a default, or if a JSON is specified
162
+ req.write(JSON.stringify(data));
163
+ }
164
+ else {
165
+ // If another content-type is specified however, we respect the serialization provided
166
+ req.write(data);
167
+ }
168
+ }
169
+ req.end();
170
+ });
171
+ });
172
+ }
173
+ function doDeleteRequest(hostname, path, headers) {
174
+ return __awaiter(this, void 0, void 0, function* () {
175
+ return new Promise(function (resolve, reject) {
176
+ const options = {
177
+ "method": "DELETE",
178
+ "hostname": hostname,
179
+ "path": path,
180
+ "headers": headers
181
+ };
182
+ api_1.propagation.inject(api_1.context.active(), options.headers);
183
+ const req = https.request(options, function (response) {
184
+ const chunks = [];
185
+ response.on("data", function (chunk) {
186
+ chunks.push(chunk);
187
+ });
188
+ response.on("end", function () {
189
+ if (response.statusCode == 204) {
190
+ //204 is no content, and most JSON parses blow up on an empty string
191
+ resolve(null);
192
+ }
193
+ else {
194
+ let body = Buffer.concat(chunks);
195
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
196
+ body = JSON.parse(body.toString());
197
+ }
198
+ else {
199
+ body = body.toString();
200
+ }
201
+ resolve(body);
202
+ }
203
+ });
204
+ response.on("error", function (e) {
205
+ reject(e);
206
+ });
207
+ });
208
+ req.end();
209
+ });
210
+ });
47
211
  }
48
212
  module.exports = {
49
213
  request,
50
- get
214
+ doGetRequest,
215
+ doPostRequest,
216
+ doPutRequest,
217
+ doDeleteRequest
51
218
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uoa/lambda-tracing",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Library for logging & distributed tracing in UoA Lambda projects",
5
5
  "repository": {
6
6
  "type": "git",
package/readme.md CHANGED
@@ -3,6 +3,11 @@
3
3
  This library contains functions to enable distributed tracing & logging in University of Auckland AWS Lambda projects.
4
4
 
5
5
  ## Usage
6
+ ### Prerequisites
7
+ If deploying to Kong gateway, your lambda plugin should have the `awsgateway_compatible` flag set to `true`.
8
+
9
+ This ensures the trace headers will be passed through to your lambda project correctly, but you will now have to base64 decode the request body before using it.
10
+
6
11
  ### Installation
7
12
  Install the library using the command
8
13
  ```
@@ -40,7 +45,8 @@ Once the logger has been imported, you can log any info using
40
45
  logger.info('Hello Logger!');
41
46
  ```
42
47
 
43
- ####Logging Levels
48
+ **Logging Levels**
49
+
44
50
  At UoA, we have four logging levels available to use. Ordered by decreasing priority, these are:
45
51
 
46
52
  |Level| Logger usage |
@@ -66,7 +72,8 @@ logger.warn('Will be logged');
66
72
  logger.error('Will be logged');
67
73
  ```
68
74
 
69
- ####Logging format
75
+ **Logging format**
76
+
70
77
  By default, logs will be produced in the following format:
71
78
  ```
72
79
  date [thread] level class - [[[traceId,spanId,info]]] message
@@ -105,12 +112,22 @@ If this header is not passed, it will be randomly generated.
105
112
  `X-B3-Info` can be any string value to provide extra information in your logs.\
106
113
  If this header is not passed, it will be set as `lambdaRequestId:requestId` where `requestId` is the id of the current lambda invocation.
107
114
 
108
- ####Header Propagation
115
+ **Header Propagation**
116
+
109
117
  To propagate the ```X-B3-TraceId``` and ```X-B3-Info``` headers to other APIs, you can import and use the uoaHttps module:
110
118
  ```
111
119
  const uoaHttps = require('@uoa/lambda-tracing/uoaHttps');
112
120
  ```
113
121
 
114
- There are two functions exposed in this module: `get()` and `request()` which will inject the additional tracing headers into the request before it is made.\
115
- The usage of these is the same as the functions provided by the Node https library (see `get()` specs [here](https://nodejs.org/api/https.html#httpsgetoptions-callback) and `request()` specs [here](https://nodejs.org/api/https.html#httpsrequestoptions-callback)).
122
+ The `uoaHttps` module exposes some functions to perform the primary HTTP operations. These will inject the tracing headers into requests before they are made:
123
+
124
+ ```
125
+ doGetRequest(hostname, path, headers): Promise
126
+ doPostRequest(hostname, path, headers, data): Promise
127
+ doPutRequest(hostname, path, headers, data): Promise
128
+ doDeleteRequest(hostname, path, headers): Promise
129
+ ```
130
+
131
+ There is also another function `request()` exposed in this module in case header propagation with operations other than the basic GET, POST, PUT, and DELETE are required.\
132
+ The usage of this is the same as the one provided by the Node https library (see specs [here](https://nodejs.org/api/https.html#httpsrequestoptions-callback)).
116
133
 
package/uoaHttps.ts CHANGED
@@ -16,19 +16,183 @@ function request(...args: any[]): http.ClientRequest {
16
16
  }
17
17
  }
18
18
 
19
- function get(options: RequestOptions | string | URL, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;
20
- function get(url: string | URL, options: RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;
21
- function get(...args: any[]): http.ClientRequest {
22
- if (args[2]) {
23
- propagation.inject(context.active(), args[1].headers);
24
- return https.get(args[0], args[1], args[2]);
25
- } else {
26
- propagation.inject(context.active(), args[0].headers);
27
- return https.get(args[0], args[1]);
28
- }
19
+ async function doGetRequest(hostname: string, path: string, headers: any) {
20
+ return new Promise(function (resolve, reject) {
21
+ const options = {
22
+ "method": "GET",
23
+ "hostname": hostname,
24
+ "path": path,
25
+ "headers": headers
26
+ }
27
+ propagation.inject(context.active(), options.headers);
28
+
29
+ const req = https.request(options, function (response) {
30
+ const chunks: any[] = [];
31
+
32
+ response.on("data", function (chunk) {
33
+ chunks.push(chunk);
34
+ });
35
+
36
+ response.on("end", function () {
37
+ let body = Buffer.concat(chunks);
38
+ body = JSON.parse(body.toString());
39
+ resolve(body);
40
+ });
41
+
42
+ response.on("error", function (e) {
43
+ reject(e);
44
+ })
45
+ });
46
+
47
+ req.end();
48
+ });
49
+ }
50
+
51
+ async function doPostRequest(hostname: string, path: string, headers: any, data: any) {
52
+ return new Promise(function (resolve, reject) {
53
+ const options = {
54
+ "method": "POST",
55
+ "hostname": hostname,
56
+ "path": path,
57
+ "headers": headers
58
+ }
59
+ propagation.inject(context.active(), options.headers);
60
+
61
+ const req = https.request(options, function (response) {
62
+ const chunks: any[] = [];
63
+
64
+ response.on("data", function (chunk) {
65
+ chunks.push(chunk);
66
+ });
67
+
68
+ response.on("end", function () {
69
+ if (response.statusCode == 204) {
70
+ //204 is no content, and most JSON parses blow up on an empty string
71
+ resolve(null);
72
+ } else {
73
+ let body: any = Buffer.concat(chunks);
74
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
75
+ body = JSON.parse(body.toString());
76
+ } else {
77
+ body = body.toString();
78
+ }
79
+ resolve(body);
80
+ }
81
+ });
82
+
83
+ response.on("error", function (e) {
84
+ reject(e);
85
+ })
86
+ });
87
+
88
+ if (data) {
89
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
90
+ //We serialize using JSON.stringify as a default, or if a JSON is specified
91
+ req.write(JSON.stringify(data));
92
+ } else {
93
+ // If another content-type is specified however, we respect the serialization provided
94
+ req.write(data);
95
+ }
96
+ }
97
+ req.end();
98
+ });
99
+ }
100
+
101
+ async function doPutRequest(hostname: string, path: string, headers: any, data: any) {
102
+ return new Promise(function (resolve, reject) {
103
+ const options = {
104
+ "method": "PUT",
105
+ "hostname": hostname,
106
+ "path": path,
107
+ "headers": headers
108
+ }
109
+ propagation.inject(context.active(), options.headers);
110
+
111
+ const req = https.request(options, function (response) {
112
+ const chunks: any[] = [];
113
+
114
+ response.on("data", function (chunk) {
115
+ chunks.push(chunk);
116
+ });
117
+
118
+ response.on("end", function () {
119
+ if (response.statusCode == 204) {
120
+ //204 is no content, and most JSON parses blow up on an empty string
121
+ resolve(null);
122
+ } else {
123
+ let body: any = Buffer.concat(chunks);
124
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
125
+ body = JSON.parse(body.toString());
126
+ } else {
127
+ body = body.toString();
128
+ }
129
+ resolve(body);
130
+ }
131
+ });
132
+
133
+ response.on("error", function (e) {
134
+ reject(e);
135
+ })
136
+ });
137
+
138
+ if (data) {
139
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
140
+ //We serialize using JSON.stringify as a default, or if a JSON is specified
141
+ req.write(JSON.stringify(data));
142
+ } else {
143
+ // If another content-type is specified however, we respect the serialization provided
144
+ req.write(data);
145
+ }
146
+ }
147
+ req.end();
148
+ });
149
+ }
150
+
151
+ async function doDeleteRequest(hostname: string, path: string, headers: any) {
152
+ return new Promise(function (resolve, reject) {
153
+ const options = {
154
+ "method": "DELETE",
155
+ "hostname": hostname,
156
+ "path": path,
157
+ "headers": headers
158
+ }
159
+ propagation.inject(context.active(), options.headers);
160
+
161
+ const req = https.request(options, function (response) {
162
+ const chunks: any[] = [];
163
+
164
+ response.on("data", function (chunk) {
165
+ chunks.push(chunk);
166
+ });
167
+
168
+ response.on("end", function () {
169
+ if (response.statusCode == 204) {
170
+ //204 is no content, and most JSON parses blow up on an empty string
171
+ resolve(null);
172
+ } else {
173
+ let body: any = Buffer.concat(chunks);
174
+ if (!('Content-Type' in options.headers) || options.headers['Content-Type'] === 'application/json') {
175
+ body = JSON.parse(body.toString());
176
+ } else {
177
+ body = body.toString();
178
+ }
179
+ resolve(body);
180
+ }
181
+ });
182
+
183
+ response.on("error", function (e) {
184
+ reject(e);
185
+ })
186
+ });
187
+
188
+ req.end();
189
+ });
29
190
  }
30
191
 
31
192
  module.exports = {
32
193
  request,
33
- get
194
+ doGetRequest,
195
+ doPostRequest,
196
+ doPutRequest,
197
+ doDeleteRequest
34
198
  }