@uoa/lambda-tracing 1.1.1 → 1.4.0

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.
@@ -3,18 +3,18 @@
3
3
  *
4
4
  * See {@link https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-propagator-b3/src/B3MultiPropagator.ts}
5
5
  */
6
- import {
7
- Context,
8
- isSpanContextValid,
9
- trace,
10
- TextMapGetter,
11
- TextMapPropagator,
12
- TextMapSetter,
13
- TraceFlags,
14
- createContextKey
6
+ import {
7
+ Context,
8
+ isSpanContextValid,
9
+ trace,
10
+ TextMapGetter,
11
+ TextMapPropagator,
12
+ TextMapSetter,
13
+ TraceFlags,
14
+ createContextKey
15
15
  } from '@opentelemetry/api';
16
16
  import { isTracingSuppressed } from '@opentelemetry/core';
17
- import {getRequestId} from "./tracing";
17
+ import {getTraceInfoHeader} from "./tracing";
18
18
 
19
19
 
20
20
  export const X_B3_TRACE_ID = 'x-b3-traceid';
@@ -24,133 +24,152 @@ export const X_B3_PARENT_SPAN_ID = 'x-b3-parentspanid';
24
24
  export const X_B3_FLAGS = 'x-b3-flags';
25
25
  export const X_B3_INFO = 'x-b3-info';
26
26
  export const B3_DEBUG_FLAG_KEY = createContextKey(
27
- 'B3 Debug Flag'
27
+ 'B3 Debug Flag'
28
28
  );
29
29
  export const B3_INFO_KEY = createContextKey(
30
- 'B3 Info Header'
31
- )
30
+ 'B3 Info Header'
31
+ );
32
+ export const B3_TRACE_ID_LENGTH_KEY = createContextKey(
33
+ 'B3 TraceId Header Length'
34
+ );
32
35
 
33
36
  const VALID_SAMPLED_VALUES = new Set([true, 'true', 'True', '1', 1]);
34
37
  const VALID_UNSAMPLED_VALUES = new Set([false, 'false', 'False', '0', 0]);
35
38
 
36
39
  function parseHeader(header: unknown) {
37
- return Array.isArray(header) ? header[0] : header;
40
+ return Array.isArray(header) ? header[0] : header;
38
41
  }
39
42
 
40
43
  function getHeaderValue(carrier: unknown, getter: TextMapGetter, key: string) {
41
- const header = getter.get(carrier, key);
42
- return parseHeader(header);
44
+ const header = getter.get(carrier, key);
45
+ return parseHeader(header);
46
+ }
47
+
48
+ function getTraceIdLength(carrier: unknown, getter: TextMapGetter): number {
49
+ const traceId = getHeaderValue(carrier, getter, X_B3_TRACE_ID);
50
+ if (typeof traceId === 'string') {
51
+ if (traceId.length <= 16 || traceId.length > 32) {
52
+ return 16;
53
+ } else {
54
+ return 32;
55
+ }
56
+ }
57
+ return 16;
43
58
  }
44
59
 
45
60
  function getTraceId(carrier: unknown, getter: TextMapGetter): string {
46
- const traceId = getHeaderValue(carrier, getter, X_B3_TRACE_ID);
47
- if (typeof traceId === 'string') {
48
- return traceId.padStart(32, '0');
49
- }
50
- return '';
61
+ const traceId = getHeaderValue(carrier, getter, X_B3_TRACE_ID);
62
+ if (typeof traceId === 'string') {
63
+ return traceId.padStart(32, '0');
64
+ }
65
+ return '';
51
66
  }
52
67
 
53
68
  function getSpanId(carrier: unknown, getter: TextMapGetter): string {
54
- const spanId = getHeaderValue(carrier, getter, X_B3_SPAN_ID);
55
- if (typeof spanId === 'string') {
56
- return spanId;
57
- }
58
- return 'aaaaaaaaaaaaaaaa'; //Valid dummy value as spanId will change when AwsLambdaInstrumentation is initialised
69
+ const spanId = getHeaderValue(carrier, getter, X_B3_SPAN_ID);
70
+ if (typeof spanId === 'string') {
71
+ return spanId;
72
+ }
73
+ return '';
59
74
  }
60
75
 
61
76
  function getDebug(carrier: unknown, getter: TextMapGetter): string | undefined {
62
- const debug = getHeaderValue(carrier, getter, X_B3_FLAGS);
63
- return debug === '1' ? '1' : undefined;
77
+ const debug = getHeaderValue(carrier, getter, X_B3_FLAGS);
78
+ return debug === '1' ? '1' : undefined;
64
79
  }
65
80
 
66
81
  function getTraceFlags(
67
- carrier: unknown,
68
- getter: TextMapGetter
82
+ carrier: unknown,
83
+ getter: TextMapGetter
69
84
  ): TraceFlags | undefined {
70
- const traceFlags = getHeaderValue(carrier, getter, X_B3_SAMPLED);
71
- const debug = getDebug(carrier, getter);
72
- if (debug === '1' || VALID_SAMPLED_VALUES.has(traceFlags)) {
73
- return TraceFlags.SAMPLED;
74
- }
75
- if (traceFlags === undefined || VALID_UNSAMPLED_VALUES.has(traceFlags)) {
76
- return TraceFlags.NONE;
77
- }
78
- // This indicates to isValidSampledValue that this is not valid
79
- return;
85
+ const traceFlags = getHeaderValue(carrier, getter, X_B3_SAMPLED);
86
+ const debug = getDebug(carrier, getter);
87
+ if (debug === '1' || VALID_SAMPLED_VALUES.has(traceFlags)) {
88
+ return TraceFlags.SAMPLED;
89
+ }
90
+ if (traceFlags === undefined || VALID_UNSAMPLED_VALUES.has(traceFlags)) {
91
+ return TraceFlags.NONE;
92
+ }
93
+ // This indicates to isValidSampledValue that this is not valid
94
+ return;
80
95
  }
81
96
 
82
97
  function getInfo(carrier: unknown, getter: TextMapGetter): string | undefined {
83
- const info = getHeaderValue(carrier, getter, X_B3_INFO);
84
- if (typeof info === 'string') {
85
- return info;
86
- }
87
- return undefined;
98
+ const info = getHeaderValue(carrier, getter, X_B3_INFO);
99
+ if (typeof info === 'string') {
100
+ return info;
101
+ }
102
+ return undefined;
88
103
  }
89
104
 
90
105
  export class UoaB3Propagator implements TextMapPropagator {
91
- inject(context: Context, carrier: any, setter: TextMapSetter<any>): void {
92
- const spanContext = trace.getSpanContext(context);
93
- if (
94
- !spanContext ||
95
- !isSpanContextValid(spanContext) ||
96
- isTracingSuppressed(context)
97
- )
98
- return;
99
-
100
- const debug = context.getValue(B3_DEBUG_FLAG_KEY);
101
- setter.set(carrier, X_B3_TRACE_ID, spanContext.traceId);
102
- setter.set(carrier, X_B3_SPAN_ID, spanContext.spanId);
103
- const info = context.getValue(B3_INFO_KEY);
104
- if (info && typeof info === 'string') {
105
- setter.set(carrier, X_B3_INFO, info.toString());
106
- } else if (getRequestId()) {
107
- setter.set(carrier, X_B3_INFO, `lambdaRequestId:${getRequestId()}`);
108
- }
109
- // According to the B3 spec, if the debug flag is set,
110
- // the sampled flag shouldn't be propagated as well.
111
- if (debug === '1') {
112
- setter.set(carrier, X_B3_FLAGS, debug);
113
- } else if (spanContext.traceFlags !== undefined) {
114
- // We set the header only if there is an existing sampling decision.
115
- // Otherwise we will omit it => Absent.
116
- setter.set(
117
- carrier,
118
- X_B3_SAMPLED,
119
- (TraceFlags.SAMPLED & spanContext.traceFlags) === TraceFlags.SAMPLED
120
- ? '1'
121
- : '0'
122
- );
123
- }
124
- }
125
-
126
- extract(context: Context, carrier: any, getter: TextMapGetter<any>): Context {
127
- const traceId = getTraceId(carrier, getter);
128
- const spanId = getSpanId(carrier, getter);
129
- const traceFlags = getTraceFlags(carrier, getter) as TraceFlags;
130
- const debug = getDebug(carrier, getter);
131
- const info = getInfo(carrier, getter);
132
-
133
- context = context.setValue(B3_DEBUG_FLAG_KEY, debug);
134
- if (info) {
135
- context = context.setValue(B3_INFO_KEY, info);
136
- }
137
- return trace.setSpanContext(context, {
138
- traceId,
139
- spanId,
140
- isRemote: true,
141
- traceFlags,
142
- });
143
- }
144
-
145
- fields(): string[] {
146
- return [
147
- X_B3_TRACE_ID,
148
- X_B3_SPAN_ID,
149
- X_B3_FLAGS,
150
- X_B3_SAMPLED,
151
- X_B3_PARENT_SPAN_ID,
152
- X_B3_INFO
153
- ];
154
- }
106
+ inject(context: Context, carrier: any, setter: TextMapSetter<any>): void {
107
+ const spanContext = trace.getSpanContext(context);
108
+ if (
109
+ !spanContext ||
110
+ !isSpanContextValid(spanContext) ||
111
+ isTracingSuppressed(context)
112
+ )
113
+ return;
114
+
115
+ const debug = context.getValue(B3_DEBUG_FLAG_KEY);
116
+ const traceIdLength: number = <number>context.getValue(B3_TRACE_ID_LENGTH_KEY);
117
+ setter.set(carrier, X_B3_TRACE_ID, spanContext.traceId.slice(spanContext.traceId.length - traceIdLength));
118
+ setter.set(carrier, X_B3_SPAN_ID, spanContext.spanId);
119
+ const info = context.getValue(B3_INFO_KEY);
120
+ if (getTraceInfoHeader()) {
121
+ setter.set(carrier, X_B3_INFO, getTraceInfoHeader());
122
+ } else if (info && typeof info === 'string') {
123
+ setter.set(carrier, X_B3_INFO, info.toString());
124
+ }
125
+ // According to the B3 spec, if the debug flag is set,
126
+ // the sampled flag shouldn't be propagated as well.
127
+ if (debug === '1') {
128
+ setter.set(carrier, X_B3_FLAGS, debug);
129
+ } else if (spanContext.traceFlags !== undefined) {
130
+ // We set the header only if there is an existing sampling decision.
131
+ // Otherwise we will omit it => Absent.
132
+ setter.set(
133
+ carrier,
134
+ X_B3_SAMPLED,
135
+ (TraceFlags.SAMPLED & spanContext.traceFlags) === TraceFlags.SAMPLED
136
+ ? '1'
137
+ : '0'
138
+ );
139
+ }
140
+ }
141
+
142
+ extract(context: Context, carrier: any, getter: TextMapGetter<any>): Context {
143
+ const traceIdLength = getTraceIdLength(carrier, getter);
144
+ context = context.setValue(B3_TRACE_ID_LENGTH_KEY, traceIdLength);
145
+
146
+ const traceId = getTraceId(carrier, getter);
147
+ const spanId = getSpanId(carrier, getter);
148
+ const traceFlags = getTraceFlags(carrier, getter) as TraceFlags;
149
+ const debug = getDebug(carrier, getter);
150
+ const info = getInfo(carrier, getter);
151
+
152
+ context = context.setValue(B3_DEBUG_FLAG_KEY, debug);
153
+ if (info) {
154
+ context = context.setValue(B3_INFO_KEY, info);
155
+ }
156
+ return trace.setSpanContext(context, {
157
+ traceId,
158
+ spanId,
159
+ isRemote: true,
160
+ traceFlags,
161
+ });
162
+ }
163
+
164
+ fields(): string[] {
165
+ return [
166
+ X_B3_TRACE_ID,
167
+ X_B3_SPAN_ID,
168
+ X_B3_FLAGS,
169
+ X_B3_SAMPLED,
170
+ X_B3_PARENT_SPAN_ID,
171
+ X_B3_INFO
172
+ ];
173
+ }
155
174
 
156
175
  }
@@ -12,6 +12,7 @@ export declare const X_B3_FLAGS = "x-b3-flags";
12
12
  export declare const X_B3_INFO = "x-b3-info";
13
13
  export declare const B3_DEBUG_FLAG_KEY: symbol;
14
14
  export declare const B3_INFO_KEY: symbol;
15
+ export declare const B3_TRACE_ID_LENGTH_KEY: symbol;
15
16
  export declare class UoaB3Propagator implements TextMapPropagator {
16
17
  inject(context: Context, carrier: any, setter: TextMapSetter<any>): void;
17
18
  extract(context: Context, carrier: any, getter: TextMapGetter<any>): Context;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UoaB3Propagator = exports.B3_INFO_KEY = exports.B3_DEBUG_FLAG_KEY = exports.X_B3_INFO = exports.X_B3_FLAGS = exports.X_B3_PARENT_SPAN_ID = exports.X_B3_SAMPLED = exports.X_B3_SPAN_ID = exports.X_B3_TRACE_ID = void 0;
3
+ exports.UoaB3Propagator = exports.B3_TRACE_ID_LENGTH_KEY = exports.B3_INFO_KEY = exports.B3_DEBUG_FLAG_KEY = exports.X_B3_INFO = exports.X_B3_FLAGS = exports.X_B3_PARENT_SPAN_ID = exports.X_B3_SAMPLED = exports.X_B3_SPAN_ID = exports.X_B3_TRACE_ID = void 0;
4
4
  /**
5
5
  * Class extended from OpenTelemetry B3MultiPropagator so that we can propagate & log the X-B3-Info header
6
6
  *
@@ -17,6 +17,7 @@ exports.X_B3_FLAGS = 'x-b3-flags';
17
17
  exports.X_B3_INFO = 'x-b3-info';
18
18
  exports.B3_DEBUG_FLAG_KEY = (0, api_1.createContextKey)('B3 Debug Flag');
19
19
  exports.B3_INFO_KEY = (0, api_1.createContextKey)('B3 Info Header');
20
+ exports.B3_TRACE_ID_LENGTH_KEY = (0, api_1.createContextKey)('B3 TraceId Header Length');
20
21
  const VALID_SAMPLED_VALUES = new Set([true, 'true', 'True', '1', 1]);
21
22
  const VALID_UNSAMPLED_VALUES = new Set([false, 'false', 'False', '0', 0]);
22
23
  function parseHeader(header) {
@@ -26,6 +27,18 @@ function getHeaderValue(carrier, getter, key) {
26
27
  const header = getter.get(carrier, key);
27
28
  return parseHeader(header);
28
29
  }
30
+ function getTraceIdLength(carrier, getter) {
31
+ const traceId = getHeaderValue(carrier, getter, exports.X_B3_TRACE_ID);
32
+ if (typeof traceId === 'string') {
33
+ if (traceId.length <= 16 || traceId.length > 32) {
34
+ return 16;
35
+ }
36
+ else {
37
+ return 32;
38
+ }
39
+ }
40
+ return 16;
41
+ }
29
42
  function getTraceId(carrier, getter) {
30
43
  const traceId = getHeaderValue(carrier, getter, exports.X_B3_TRACE_ID);
31
44
  if (typeof traceId === 'string') {
@@ -38,7 +51,7 @@ function getSpanId(carrier, getter) {
38
51
  if (typeof spanId === 'string') {
39
52
  return spanId;
40
53
  }
41
- return 'aaaaaaaaaaaaaaaa'; //Valid dummy value as spanId will change when AwsLambdaInstrumentation is initialised
54
+ return '';
42
55
  }
43
56
  function getDebug(carrier, getter) {
44
57
  const debug = getHeaderValue(carrier, getter, exports.X_B3_FLAGS);
@@ -71,14 +84,15 @@ class UoaB3Propagator {
71
84
  (0, core_1.isTracingSuppressed)(context))
72
85
  return;
73
86
  const debug = context.getValue(exports.B3_DEBUG_FLAG_KEY);
74
- setter.set(carrier, exports.X_B3_TRACE_ID, spanContext.traceId);
87
+ const traceIdLength = context.getValue(exports.B3_TRACE_ID_LENGTH_KEY);
88
+ setter.set(carrier, exports.X_B3_TRACE_ID, spanContext.traceId.slice(spanContext.traceId.length - traceIdLength));
75
89
  setter.set(carrier, exports.X_B3_SPAN_ID, spanContext.spanId);
76
90
  const info = context.getValue(exports.B3_INFO_KEY);
77
- if (info && typeof info === 'string') {
78
- setter.set(carrier, exports.X_B3_INFO, info.toString());
91
+ if ((0, tracing_1.getTraceInfoHeader)()) {
92
+ setter.set(carrier, exports.X_B3_INFO, (0, tracing_1.getTraceInfoHeader)());
79
93
  }
80
- else if ((0, tracing_1.getRequestId)()) {
81
- setter.set(carrier, exports.X_B3_INFO, `lambdaRequestId:${(0, tracing_1.getRequestId)()}`);
94
+ else if (info && typeof info === 'string') {
95
+ setter.set(carrier, exports.X_B3_INFO, info.toString());
82
96
  }
83
97
  // According to the B3 spec, if the debug flag is set,
84
98
  // the sampled flag shouldn't be propagated as well.
@@ -94,6 +108,8 @@ class UoaB3Propagator {
94
108
  }
95
109
  }
96
110
  extract(context, carrier, getter) {
111
+ const traceIdLength = getTraceIdLength(carrier, getter);
112
+ context = context.setValue(exports.B3_TRACE_ID_LENGTH_KEY, traceIdLength);
97
113
  const traceId = getTraceId(carrier, getter);
98
114
  const spanId = getSpanId(carrier, getter);
99
115
  const traceFlags = getTraceFlags(carrier, getter);
package/dist/logging.js CHANGED
@@ -35,21 +35,22 @@ function getLogReplacementValues(callingModule, logInfo) {
35
35
  }
36
36
  let info = '-';
37
37
  const infoHeader = context.active().getValue(UoaB3Propagator_1.B3_INFO_KEY);
38
- if (infoHeader) {
39
- info = infoHeader.toString();
38
+ if ((0, tracing_1.getTraceInfoHeader)()) {
39
+ info = (0, tracing_1.getTraceInfoHeader)();
40
40
  }
41
- else if ((0, tracing_1.getRequestId)()) {
42
- info = `lambdaRequestId:${(0, tracing_1.getRequestId)()}`;
41
+ else if (infoHeader) {
42
+ info = infoHeader.toString();
43
43
  }
44
+ const traceIdLength = context.active().getValue(UoaB3Propagator_1.B3_TRACE_ID_LENGTH_KEY);
44
45
  let logReplacements = new Map();
45
46
  logReplacements.set('%date', moment().toISOString());
46
47
  logReplacements.set('%thread', '-');
47
48
  logReplacements.set('%level', logInfo.level.toUpperCase());
48
49
  logReplacements.set('%class', moduleParts.join('.'));
49
- logReplacements.set('%traceId', traceId);
50
+ logReplacements.set('%traceId', traceId.slice(traceId.length - traceIdLength));
50
51
  logReplacements.set('%spanId', spanId);
51
52
  logReplacements.set('%info', info);
52
- logReplacements.set('%message', logInfo.message);
53
+ logReplacements.set('%message', logInfo.message.replace(/\n/g, ''));
53
54
  return logReplacements;
54
55
  }
55
56
  module.exports = function (callingModule) {
package/dist/tracing.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export declare function initializeTracing(): void;
2
- export declare function getRequestId(): string;
2
+ export declare function getTraceInfoHeader(): string;
3
+ export declare function setTraceInfoHeader(info: string): void;
package/dist/tracing.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getRequestId = 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
+ const api_1 = require("@opentelemetry/api");
8
9
  const provider = new sdk_trace_node_1.NodeTracerProvider();
9
- let requestId;
10
+ let infoHeader;
10
11
  function initializeTracing() {
11
12
  provider.register({
12
13
  propagator: new UoaB3Propagator_1.UoaB3Propagator()
@@ -16,7 +17,7 @@ function initializeTracing() {
16
17
  new instrumentation_aws_lambda_1.AwsLambdaInstrumentation({
17
18
  requestHook: (span, { event, context }) => {
18
19
  span.setAttribute('faas.name', context.functionName);
19
- requestId = context.awsRequestId;
20
+ infoHeader = undefined; //reset header value in case lambda execution environment maintained since last invocation
20
21
  },
21
22
  responseHook: (span, { err, res }) => {
22
23
  if (err instanceof Error)
@@ -30,7 +31,16 @@ function initializeTracing() {
30
31
  });
31
32
  }
32
33
  exports.initializeTracing = initializeTracing;
33
- function getRequestId() {
34
- return requestId;
34
+ function getTraceInfoHeader() {
35
+ if (infoHeader) {
36
+ return infoHeader;
37
+ }
38
+ else {
39
+ return api_1.context.active().getValue(UoaB3Propagator_1.B3_INFO_KEY);
40
+ }
35
41
  }
36
- exports.getRequestId = getRequestId;
42
+ exports.getTraceInfoHeader = getTraceInfoHeader;
43
+ function setTraceInfoHeader(info) {
44
+ infoHeader = info;
45
+ }
46
+ exports.setTraceInfoHeader = setTraceInfoHeader;
package/dist/uoaHttps.js CHANGED
@@ -44,14 +44,15 @@ function request(...args) {
44
44
  return https.request(args[0], args[1]);
45
45
  }
46
46
  }
47
- function doGetRequest(hostname, path, headers) {
47
+ function doGetRequest(hostname, path, headers, port = 443) {
48
48
  return __awaiter(this, void 0, void 0, function* () {
49
49
  return new Promise(function (resolve, reject) {
50
50
  const options = {
51
51
  "method": "GET",
52
52
  "hostname": hostname,
53
53
  "path": path,
54
- "headers": headers
54
+ "headers": headers,
55
+ "port": port
55
56
  };
56
57
  api_1.propagation.inject(api_1.context.active(), options.headers);
57
58
  const req = https.request(options, function (response) {
@@ -72,14 +73,15 @@ function doGetRequest(hostname, path, headers) {
72
73
  });
73
74
  });
74
75
  }
75
- function doPostRequest(hostname, path, headers, data) {
76
+ function doPostRequest(hostname, path, headers, data, port = 443) {
76
77
  return __awaiter(this, void 0, void 0, function* () {
77
78
  return new Promise(function (resolve, reject) {
78
79
  const options = {
79
80
  "method": "POST",
80
81
  "hostname": hostname,
81
82
  "path": path,
82
- "headers": headers
83
+ "headers": headers,
84
+ "port": port
83
85
  };
84
86
  api_1.propagation.inject(api_1.context.active(), options.headers);
85
87
  const req = https.request(options, function (response) {
@@ -121,14 +123,15 @@ function doPostRequest(hostname, path, headers, data) {
121
123
  });
122
124
  });
123
125
  }
124
- function doPutRequest(hostname, path, headers, data) {
126
+ function doPutRequest(hostname, path, headers, data, port = 443) {
125
127
  return __awaiter(this, void 0, void 0, function* () {
126
128
  return new Promise(function (resolve, reject) {
127
129
  const options = {
128
130
  "method": "PUT",
129
131
  "hostname": hostname,
130
132
  "path": path,
131
- "headers": headers
133
+ "headers": headers,
134
+ "port": port
132
135
  };
133
136
  api_1.propagation.inject(api_1.context.active(), options.headers);
134
137
  const req = https.request(options, function (response) {
@@ -170,14 +173,15 @@ function doPutRequest(hostname, path, headers, data) {
170
173
  });
171
174
  });
172
175
  }
173
- function doDeleteRequest(hostname, path, headers) {
176
+ function doDeleteRequest(hostname, path, headers, port = 443) {
174
177
  return __awaiter(this, void 0, void 0, function* () {
175
178
  return new Promise(function (resolve, reject) {
176
179
  const options = {
177
180
  "method": "DELETE",
178
181
  "hostname": hostname,
179
182
  "path": path,
180
- "headers": headers
183
+ "headers": headers,
184
+ "port": port
181
185
  };
182
186
  api_1.propagation.inject(api_1.context.active(), options.headers);
183
187
  const req = https.request(options, function (response) {
package/logging.ts CHANGED
@@ -1,5 +1,5 @@
1
- import {B3_INFO_KEY} from "./UoaB3Propagator";
2
- import {getRequestId} from "./tracing";
1
+ import {B3_INFO_KEY, B3_TRACE_ID_LENGTH_KEY} from "./UoaB3Propagator";
2
+ import {getTraceInfoHeader} from "./tracing";
3
3
 
4
4
  const winston = require('winston');
5
5
  const moment = require('moment');
@@ -41,21 +41,23 @@ function getLogReplacementValues(callingModule: NodeModule, logInfo: any): Map<s
41
41
 
42
42
  let info = '-';
43
43
  const infoHeader = context.active().getValue(B3_INFO_KEY);
44
- if (infoHeader) {
44
+ if (getTraceInfoHeader()) {
45
+ info = getTraceInfoHeader();
46
+ } else if (infoHeader) {
45
47
  info = infoHeader.toString();
46
- } else if (getRequestId()) {
47
- info = `lambdaRequestId:${getRequestId()}`;
48
48
  }
49
49
 
50
+ const traceIdLength: number = <number>context.active().getValue(B3_TRACE_ID_LENGTH_KEY);
51
+
50
52
  let logReplacements: Map<string, string> = new Map<string, string>();
51
53
  logReplacements.set('%date', moment().toISOString());
52
54
  logReplacements.set('%thread', '-');
53
55
  logReplacements.set('%level', logInfo.level.toUpperCase());
54
56
  logReplacements.set('%class', moduleParts.join('.'));
55
- logReplacements.set('%traceId', traceId);
57
+ logReplacements.set('%traceId', traceId.slice(traceId.length - traceIdLength));
56
58
  logReplacements.set('%spanId', spanId);
57
59
  logReplacements.set('%info', info);
58
- logReplacements.set('%message', logInfo.message);
60
+ logReplacements.set('%message', logInfo.message.replace(/\n/g, ''));
59
61
 
60
62
  return logReplacements;
61
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uoa/lambda-tracing",
3
- "version": "1.1.1",
3
+ "version": "1.4.0",
4
4
  "description": "Library for logging & distributed tracing in UoA Lambda projects",
5
5
  "repository": {
6
6
  "type": "git",
package/readme.md CHANGED
@@ -97,20 +97,26 @@ Valid logging pattern placeholders are as follows:
97
97
  |%class|The module which logged the message|src.handle-service|
98
98
  |%traceId|Unique Id for the request|5c0c783c965a684842608f10422fdf2c|
99
99
  |%spanId|Unique Id for the current lambda invocation|6a8b025511ac1191|
100
- |%info|Extra information to help with filtering the logs|lambdaRequestId:dc2f1b60-96af-4869-9b75-036f9ddcdb33|
100
+ |%info|Extra information to help with filtering the logs|usefulCode=12345|
101
101
  |%message|The logged message|Hello Logger!|
102
102
 
103
103
  ### Distributed Tracing
104
104
  There are two headers that can be passed in API calls to your lambda project using this library: ```X-B3-TraceId``` and ```X-B3-Info```.
105
105
  If passed to a lambda project using this library, the values of %traceId and %info in the logging pattern will be the corresponding header values.
106
106
 
107
- `X-B3-TraceId` should be a 32 character lowercase hex encoded string.\
108
- If the passed traceId is less than 32
109
- characters, it will be left padded with 0's to get to a length of 32.\
110
- If this header is not passed, it will be randomly generated.
107
+ `X-B3-TraceId` should be either a 16 or 32 character lowercase hex encoded string.\
108
+ If the passed traceId is less than 16 characters, it will be left padded with 0's to get to a length of 16.\
109
+ Likewise, if it is longer than 16 but less than 32 characters, it will be left padded with 0's to get to a length of 32.\
110
+ If it is longer than 32 characters, a new traceId will be generated.\
111
+ If the `X-B3-TraceId` **_and_** `X-B3-SpanId` headers are not passed, they will be randomly generated.
111
112
 
112
113
  `X-B3-Info` can be any string value to provide extra information in your logs.\
113
- If this header is not passed, it will be set as `lambdaRequestId:requestId` where `requestId` is the id of the current lambda invocation.
114
+ The value of this header can be accessed by using the `getTraceInfoHeader(): string` function.
115
+ Similarly, it can be set using the `setTraceInfoHeader(string)` function.\
116
+ These two functions can be imported using:
117
+ ```
118
+ const {setTraceInfoHeader, getTraceInfoHeader} = require('./logging/tracing');
119
+ ```
114
120
 
115
121
  **Header Propagation**
116
122
 
package/tracing.ts CHANGED
@@ -1,10 +1,11 @@
1
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
- import {UoaB3Propagator} from "./UoaB3Propagator";
4
+ import {B3_INFO_KEY, UoaB3Propagator} from "./UoaB3Propagator";
5
+ import {context} from "@opentelemetry/api";
5
6
 
6
7
  const provider = new NodeTracerProvider();
7
- let requestId: string;
8
+ let infoHeader: string | undefined;
8
9
 
9
10
  export function initializeTracing() {
10
11
  provider.register({
@@ -16,7 +17,7 @@ export function initializeTracing() {
16
17
  new AwsLambdaInstrumentation({
17
18
  requestHook: (span, { event, context }) => {
18
19
  span.setAttribute('faas.name', context.functionName);
19
- requestId = context.awsRequestId;
20
+ infoHeader = undefined; //reset header value in case lambda execution environment maintained since last invocation
20
21
  },
21
22
  responseHook: (span, { err, res }) => {
22
23
  if (err instanceof Error) span.setAttribute('faas.error', err.message);
@@ -29,6 +30,14 @@ export function initializeTracing() {
29
30
 
30
31
  }
31
32
 
32
- export function getRequestId() {
33
- return requestId;
33
+ export function getTraceInfoHeader(): string {
34
+ if (infoHeader) {
35
+ return infoHeader;
36
+ } else {
37
+ return <string>context.active().getValue(B3_INFO_KEY);
38
+ }
39
+ }
40
+
41
+ export function setTraceInfoHeader(info: string) {
42
+ infoHeader = info;
34
43
  }
package/uoaHttps.ts CHANGED
@@ -16,13 +16,14 @@ function request(...args: any[]): http.ClientRequest {
16
16
  }
17
17
  }
18
18
 
19
- async function doGetRequest(hostname: string, path: string, headers: any) {
19
+ async function doGetRequest(hostname: string, path: string, headers: any, port: number | string = 443) {
20
20
  return new Promise(function (resolve, reject) {
21
21
  const options = {
22
22
  "method": "GET",
23
23
  "hostname": hostname,
24
24
  "path": path,
25
- "headers": headers
25
+ "headers": headers,
26
+ "port": port
26
27
  }
27
28
  propagation.inject(context.active(), options.headers);
28
29
 
@@ -48,13 +49,14 @@ async function doGetRequest(hostname: string, path: string, headers: any) {
48
49
  });
49
50
  }
50
51
 
51
- async function doPostRequest(hostname: string, path: string, headers: any, data: any) {
52
+ async function doPostRequest(hostname: string, path: string, headers: any, data: any, port: number | string = 443) {
52
53
  return new Promise(function (resolve, reject) {
53
54
  const options = {
54
55
  "method": "POST",
55
56
  "hostname": hostname,
56
57
  "path": path,
57
- "headers": headers
58
+ "headers": headers,
59
+ "port": port
58
60
  }
59
61
  propagation.inject(context.active(), options.headers);
60
62
 
@@ -98,13 +100,14 @@ async function doPostRequest(hostname: string, path: string, headers: any, data:
98
100
  });
99
101
  }
100
102
 
101
- async function doPutRequest(hostname: string, path: string, headers: any, data: any) {
103
+ async function doPutRequest(hostname: string, path: string, headers: any, data: any, port: number | string = 443) {
102
104
  return new Promise(function (resolve, reject) {
103
105
  const options = {
104
106
  "method": "PUT",
105
107
  "hostname": hostname,
106
108
  "path": path,
107
- "headers": headers
109
+ "headers": headers,
110
+ "port": port
108
111
  }
109
112
  propagation.inject(context.active(), options.headers);
110
113
 
@@ -148,13 +151,14 @@ async function doPutRequest(hostname: string, path: string, headers: any, data:
148
151
  });
149
152
  }
150
153
 
151
- async function doDeleteRequest(hostname: string, path: string, headers: any) {
154
+ async function doDeleteRequest(hostname: string, path: string, headers: any, port: number | string = 443) {
152
155
  return new Promise(function (resolve, reject) {
153
156
  const options = {
154
157
  "method": "DELETE",
155
158
  "hostname": hostname,
156
159
  "path": path,
157
- "headers": headers
160
+ "headers": headers,
161
+ "port": port
158
162
  }
159
163
  propagation.inject(context.active(), options.headers);
160
164