@salesforce/mrt-utilities 0.0.1 → 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 +49 -45
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +10 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/metrics/index.d.ts +1 -0
- package/dist/cjs/metrics/index.js +7 -0
- package/dist/cjs/metrics/index.js.map +1 -0
- package/dist/cjs/metrics/metrics-sender.d.ts +136 -0
- package/dist/cjs/metrics/metrics-sender.js +240 -0
- package/dist/cjs/metrics/metrics-sender.js.map +1 -0
- package/dist/cjs/middleware/data-store.d.ts +56 -0
- package/dist/cjs/middleware/data-store.js +124 -0
- package/dist/cjs/middleware/data-store.js.map +1 -0
- package/dist/cjs/middleware/index.d.ts +3 -0
- package/dist/cjs/middleware/index.js +8 -0
- package/dist/cjs/middleware/index.js.map +1 -0
- package/dist/cjs/middleware/middleware.d.ts +126 -0
- package/dist/cjs/middleware/middleware.js +416 -0
- package/dist/cjs/middleware/middleware.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/streaming/create-lambda-adapter.d.ts +68 -0
- package/dist/cjs/streaming/create-lambda-adapter.js +797 -0
- package/dist/cjs/streaming/create-lambda-adapter.js.map +1 -0
- package/dist/cjs/streaming/index.d.ts +1 -0
- package/dist/cjs/streaming/index.js +7 -0
- package/dist/cjs/streaming/index.js.map +1 -0
- package/dist/cjs/utils/configure-proxying.d.ts +160 -0
- package/dist/cjs/utils/configure-proxying.js +204 -0
- package/dist/cjs/utils/configure-proxying.js.map +1 -0
- package/dist/cjs/utils/ssr-proxying.d.ts +300 -0
- package/dist/cjs/utils/ssr-proxying.js +713 -0
- package/dist/cjs/utils/ssr-proxying.js.map +1 -0
- package/dist/cjs/utils/utils.d.ts +27 -0
- package/dist/cjs/utils/utils.js +44 -0
- package/dist/cjs/utils/utils.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/metrics/index.d.ts +1 -0
- package/dist/esm/metrics/index.js +7 -0
- package/dist/esm/metrics/index.js.map +1 -0
- package/dist/esm/metrics/metrics-sender.d.ts +136 -0
- package/dist/esm/metrics/metrics-sender.js +240 -0
- package/dist/esm/metrics/metrics-sender.js.map +1 -0
- package/dist/esm/middleware/data-store.d.ts +56 -0
- package/dist/esm/middleware/data-store.js +124 -0
- package/dist/esm/middleware/data-store.js.map +1 -0
- package/dist/esm/middleware/index.d.ts +3 -0
- package/dist/esm/middleware/index.js +9 -0
- package/dist/esm/middleware/index.js.map +1 -0
- package/dist/esm/middleware/middleware.d.ts +126 -0
- package/dist/esm/middleware/middleware.js +416 -0
- package/dist/esm/middleware/middleware.js.map +1 -0
- package/dist/esm/streaming/create-lambda-adapter.d.ts +68 -0
- package/dist/esm/streaming/create-lambda-adapter.js +797 -0
- package/dist/esm/streaming/create-lambda-adapter.js.map +1 -0
- package/dist/esm/streaming/index.d.ts +1 -0
- package/dist/esm/streaming/index.js +7 -0
- package/dist/esm/streaming/index.js.map +1 -0
- package/dist/esm/utils/configure-proxying.d.ts +160 -0
- package/dist/esm/utils/configure-proxying.js +204 -0
- package/dist/esm/utils/configure-proxying.js.map +1 -0
- package/dist/esm/utils/ssr-proxying.d.ts +300 -0
- package/dist/esm/utils/ssr-proxying.js +713 -0
- package/dist/esm/utils/ssr-proxying.js.map +1 -0
- package/dist/esm/utils/utils.d.ts +27 -0
- package/dist/esm/utils/utils.js +44 -0
- package/dist/esm/utils/utils.js.map +1 -0
- package/package.json +130 -7
package/README.md
CHANGED
|
@@ -1,45 +1,49 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
# mrt-utilities
|
|
2
|
+
|
|
3
|
+
Middleware and utilities to simulate a deployed MRT environment.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
import {
|
|
9
|
+
createMRTProxyMiddlewares,
|
|
10
|
+
createMRTRequestProcessorMiddleware,
|
|
11
|
+
createMRTStaticAssetServingMiddleware,
|
|
12
|
+
createMRTCommonMiddleware,
|
|
13
|
+
createMRTCleanUpMiddleware,
|
|
14
|
+
isLocal,
|
|
15
|
+
} from '@salesforce/mrt-utilities';
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export const createApp = (): Express => {
|
|
19
|
+
const app = express();
|
|
20
|
+
app.disable('x-powered-by');
|
|
21
|
+
|
|
22
|
+
// Top most middleware to set up headers
|
|
23
|
+
app.use(createMRTCommonMiddleware());
|
|
24
|
+
|
|
25
|
+
if (isLocal()) {
|
|
26
|
+
const requestProcessorPath = 'path/to/request-processor.js';
|
|
27
|
+
const proxyConfigs = [
|
|
28
|
+
{
|
|
29
|
+
host: 'https://example.com',
|
|
30
|
+
path: 'api',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
app.use(createMRTRequestProcessorMiddleware(requestProcessorPath, proxyConfigs));
|
|
34
|
+
|
|
35
|
+
const mrtProxies = createMRTProxyMiddlewares(proxyConfigs);
|
|
36
|
+
mrtProxies.forEach(({ path, fn }) => {
|
|
37
|
+
app.use(path, fn);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const staticAssetDir = 'path/to/static';
|
|
41
|
+
app.use(
|
|
42
|
+
`/mobify/bundle/${process.env.BUNDLE_ID || '1'}/static/`,
|
|
43
|
+
createMRTStaticAssetServingMiddleware(staticAssetDir)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Cleans up any remaining headers and sets any remaining values
|
|
48
|
+
app.use(createMRTCleanUpMiddleware());
|
|
49
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
export * from './middleware/index.js';
|
|
7
|
+
export * from './metrics/index.js';
|
|
8
|
+
export * from './streaming/index.js';
|
|
9
|
+
export { isLocal } from './utils/utils.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './metrics-sender.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
export * from './metrics-sender.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/metrics/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { CloudWatchClient } from '@aws-sdk/client-cloudwatch';
|
|
2
|
+
export declare const DEFAULT_NAMESPACE = "ssr";
|
|
3
|
+
export declare const getDimensions: () => Record<string, string>;
|
|
4
|
+
/**
|
|
5
|
+
* Input metric for sending to CloudWatch.
|
|
6
|
+
*
|
|
7
|
+
* @property name - The name of the metric (required)
|
|
8
|
+
* @property value - The numeric value of the metric (optional, defaults to 0)
|
|
9
|
+
* @property timestamp - The timestamp for the metric (optional, defaults to current time)
|
|
10
|
+
* @property unit - The unit for the metric (optional, defaults to 'Count')
|
|
11
|
+
* @property dimensions - Key-value pairs for metric dimensions (optional)
|
|
12
|
+
*/
|
|
13
|
+
interface InputMetric {
|
|
14
|
+
name: string;
|
|
15
|
+
value?: number;
|
|
16
|
+
timestamp?: Date;
|
|
17
|
+
unit?: string;
|
|
18
|
+
dimensions?: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A class that handles asynchronous sending of CloudWatch metrics.
|
|
22
|
+
*
|
|
23
|
+
* This class uses a singleton pattern. Use MetricsSender.getSender()
|
|
24
|
+
* to get the singleton instance. Metrics can be queued and sent in
|
|
25
|
+
* batches, or sent immediately. The class automatically batches metrics
|
|
26
|
+
* into groups of 20 (CloudWatch's limit per request).
|
|
27
|
+
*
|
|
28
|
+
* In local development environments, metrics are queued but not sent
|
|
29
|
+
* unless the SEND_CW_METRICS environment variable is set.
|
|
30
|
+
*/
|
|
31
|
+
export declare class MetricsSender {
|
|
32
|
+
private _CW;
|
|
33
|
+
private _queue;
|
|
34
|
+
static _override: boolean;
|
|
35
|
+
private static _instance;
|
|
36
|
+
/** @internal Test hook: inject a CloudWatch client for unit tests */
|
|
37
|
+
static _testClient: CloudWatchClient | null;
|
|
38
|
+
private constructor();
|
|
39
|
+
/**
|
|
40
|
+
* Return the number of metrics waiting to be sent
|
|
41
|
+
* @returns {number}
|
|
42
|
+
*/
|
|
43
|
+
get queueLength(): number;
|
|
44
|
+
/**
|
|
45
|
+
* Create a CloudWatch AWS SDK client, or return a falsy value
|
|
46
|
+
* if this MetricsSender is not actually sending metrics.
|
|
47
|
+
*
|
|
48
|
+
* The client is only created when running in a remote environment
|
|
49
|
+
* (AWS Lambda) or when SEND_CW_METRICS environment variable is set.
|
|
50
|
+
* The client is configured with maxAttempts: 1 to prevent retries
|
|
51
|
+
* and reduce latency under high load.
|
|
52
|
+
*
|
|
53
|
+
* @private
|
|
54
|
+
* @returns {CloudWatchClient|null} The CloudWatch client, or null if not sending metrics
|
|
55
|
+
*/
|
|
56
|
+
private _setup;
|
|
57
|
+
/**
|
|
58
|
+
* Convert InputMetric to MetricDatum format
|
|
59
|
+
*
|
|
60
|
+
* @private
|
|
61
|
+
* @param metric - Input metric to convert
|
|
62
|
+
* @param defaultTimestamp - Default timestamp to use if not provided
|
|
63
|
+
* @returns Converted metric datum
|
|
64
|
+
*/
|
|
65
|
+
private _convertToMetricDatum;
|
|
66
|
+
/**
|
|
67
|
+
* Send metrics to CloudWatch using putMetricData.
|
|
68
|
+
*
|
|
69
|
+
* Errors are caught and logged but not re-thrown. If the client
|
|
70
|
+
* is null (local environment without SEND_CW_METRICS), this method
|
|
71
|
+
* returns immediately without sending.
|
|
72
|
+
*
|
|
73
|
+
* @private
|
|
74
|
+
* @param cw - CloudWatch client (may be null)
|
|
75
|
+
* @param metrics - Array of MetricDatum to send
|
|
76
|
+
* @returns Promise that resolves when the send operation completes (or immediately if client is null)
|
|
77
|
+
*/
|
|
78
|
+
private _putMetricData;
|
|
79
|
+
/**
|
|
80
|
+
* Batch and send metrics. Handles batching into groups of 20 (CloudWatch limit)
|
|
81
|
+
* and sends them asynchronously (fire and forget). Errors are logged but not raised.
|
|
82
|
+
*
|
|
83
|
+
* @private
|
|
84
|
+
* @param metrics - Array of metrics to send
|
|
85
|
+
*/
|
|
86
|
+
private _sendBatchedMetrics;
|
|
87
|
+
/**
|
|
88
|
+
* Send any queued metrics. Returns a Promise that resolves immediately
|
|
89
|
+
* after starting the send operations (fire and forget). Errors are logged
|
|
90
|
+
* but not raised. The queue is cleared before sending begins.
|
|
91
|
+
*
|
|
92
|
+
* @returns Promise that resolves immediately after starting send operations
|
|
93
|
+
*/
|
|
94
|
+
flush(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Add one or more custom metric values to the queue of those waiting
|
|
97
|
+
* to be sent, or send them immediately. This function supports simple
|
|
98
|
+
* name-and-value metrics. It doesn't support more complex CloudWatch types.
|
|
99
|
+
*
|
|
100
|
+
* A metric is an object with at least 'name' (string) and optionally 'value'
|
|
101
|
+
* (number, defaults to 0). It may also optionally include 'timestamp'
|
|
102
|
+
* (defaults to the time of the call to send()), and 'unit', which
|
|
103
|
+
* must be one of Seconds, Microseconds, Milliseconds, Bytes, Kilobytes,
|
|
104
|
+
* Megabytes, Gigabytes, Terabytes, Bits, Kilobits, Megabits, Gigabits,
|
|
105
|
+
* Terabits, Percent, Count, Bytes/Second, Kilobytes/Second,
|
|
106
|
+
* Megabytes/Second, Gigabytes/Second, Terabytes/Second,
|
|
107
|
+
* Bits/Second, Kilobits/Second, Megabits/Second, Gigabits/Second,
|
|
108
|
+
* Terabits/Second, Count/Second or None (defaults to 'Count').
|
|
109
|
+
* There may also be a 'dimensions'
|
|
110
|
+
* object, which has dimension names as keys and dimension
|
|
111
|
+
* values as values. Empty or falsy dimension values are filtered out.
|
|
112
|
+
*
|
|
113
|
+
* In a local development environment, metrics are queued but not sent
|
|
114
|
+
* unless the SEND_CW_METRICS environment variable is set. This allows
|
|
115
|
+
* for testing metric sending behavior locally.
|
|
116
|
+
*
|
|
117
|
+
* The metrics are added to an internal queue so that they can be
|
|
118
|
+
* batched up to send more efficiently. They are only sent when
|
|
119
|
+
* flush() is called, unless immediate is true.
|
|
120
|
+
*
|
|
121
|
+
* @private
|
|
122
|
+
* @param metrics - Array of InputMetric objects to send
|
|
123
|
+
* @param immediate - If true, send metrics immediately instead of queuing (default: false)
|
|
124
|
+
*/
|
|
125
|
+
send(metrics: InputMetric[], immediate?: boolean): void;
|
|
126
|
+
/**
|
|
127
|
+
* Get the singleton MetricsSender instance.
|
|
128
|
+
*
|
|
129
|
+
* Creates a new instance if one doesn't exist, otherwise returns
|
|
130
|
+
* the existing instance.
|
|
131
|
+
*
|
|
132
|
+
* @returns The singleton MetricsSender instance
|
|
133
|
+
*/
|
|
134
|
+
static getSender(): MetricsSender;
|
|
135
|
+
}
|
|
136
|
+
export {};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { CloudWatchClient, PutMetricDataCommand } from '@aws-sdk/client-cloudwatch';
|
|
7
|
+
import { isLocal } from '../utils/utils.js';
|
|
8
|
+
const isRemote = () => !isLocal();
|
|
9
|
+
export const DEFAULT_NAMESPACE = 'ssr';
|
|
10
|
+
export const getDimensions = () => {
|
|
11
|
+
return {
|
|
12
|
+
Project: process.env.MOBIFY_PROPERTY_ID || 'UNKNOWN',
|
|
13
|
+
Target: process.env.DEPLOY_TARGET || 'UNKNOWN',
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A class that handles asynchronous sending of CloudWatch metrics.
|
|
18
|
+
*
|
|
19
|
+
* This class uses a singleton pattern. Use MetricsSender.getSender()
|
|
20
|
+
* to get the singleton instance. Metrics can be queued and sent in
|
|
21
|
+
* batches, or sent immediately. The class automatically batches metrics
|
|
22
|
+
* into groups of 20 (CloudWatch's limit per request).
|
|
23
|
+
*
|
|
24
|
+
* In local development environments, metrics are queued but not sent
|
|
25
|
+
* unless the SEND_CW_METRICS environment variable is set.
|
|
26
|
+
*/
|
|
27
|
+
export class MetricsSender {
|
|
28
|
+
_CW = null;
|
|
29
|
+
_queue = [];
|
|
30
|
+
static _override = false;
|
|
31
|
+
static _instance = null;
|
|
32
|
+
/** @internal Test hook: inject a CloudWatch client for unit tests */
|
|
33
|
+
static _testClient = null;
|
|
34
|
+
constructor() {
|
|
35
|
+
// CloudWatch client used to send metrics. For a local dev server,
|
|
36
|
+
// this will remain falsy, since a local dev server doesn't actually
|
|
37
|
+
// send metrics (unless SEND_CW_METRICS is defined for testing).
|
|
38
|
+
this._CW = null;
|
|
39
|
+
// A queue of metrics waiting to be sent. Each is a single
|
|
40
|
+
// name/value metric, and they accumulate on this queue
|
|
41
|
+
// until batched up into a putMetricData call.
|
|
42
|
+
this._queue = [];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Return the number of metrics waiting to be sent
|
|
46
|
+
* @returns {number}
|
|
47
|
+
*/
|
|
48
|
+
get queueLength() {
|
|
49
|
+
return this._queue.length;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a CloudWatch AWS SDK client, or return a falsy value
|
|
53
|
+
* if this MetricsSender is not actually sending metrics.
|
|
54
|
+
*
|
|
55
|
+
* The client is only created when running in a remote environment
|
|
56
|
+
* (AWS Lambda) or when SEND_CW_METRICS environment variable is set.
|
|
57
|
+
* The client is configured with maxAttempts: 1 to prevent retries
|
|
58
|
+
* and reduce latency under high load.
|
|
59
|
+
*
|
|
60
|
+
* @private
|
|
61
|
+
* @returns {CloudWatchClient|null} The CloudWatch client, or null if not sending metrics
|
|
62
|
+
*/
|
|
63
|
+
_setup() {
|
|
64
|
+
if (MetricsSender._testClient) {
|
|
65
|
+
this._CW = MetricsSender._testClient;
|
|
66
|
+
return this._CW;
|
|
67
|
+
}
|
|
68
|
+
/* istanbul ignore next */
|
|
69
|
+
if (!this._CW && (isRemote() || MetricsSender._override)) {
|
|
70
|
+
// The AWS_REGION variable is defined by the Lambda
|
|
71
|
+
// environment.
|
|
72
|
+
// Setting maxAttempts to 1 will prevent the SDK from retrying.
|
|
73
|
+
// This is necessary because under high load, there will be backpressure
|
|
74
|
+
// on the Lambda function, and causing severe performance issues (400-500ms latency)
|
|
75
|
+
this._CW = new CloudWatchClient({
|
|
76
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
77
|
+
maxAttempts: 1,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return this._CW;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Convert InputMetric to MetricDatum format
|
|
84
|
+
*
|
|
85
|
+
* @private
|
|
86
|
+
* @param metric - Input metric to convert
|
|
87
|
+
* @param defaultTimestamp - Default timestamp to use if not provided
|
|
88
|
+
* @returns Converted metric datum
|
|
89
|
+
*/
|
|
90
|
+
_convertToMetricDatum(metric, defaultTimestamp) {
|
|
91
|
+
const metricData = {
|
|
92
|
+
MetricName: metric.name,
|
|
93
|
+
Value: metric.value || 0,
|
|
94
|
+
Timestamp: metric.timestamp instanceof Date ? metric.timestamp : defaultTimestamp,
|
|
95
|
+
Unit: (metric.unit || 'Count'),
|
|
96
|
+
};
|
|
97
|
+
if (metric.dimensions) {
|
|
98
|
+
const dimensions = [];
|
|
99
|
+
Object.entries(metric.dimensions).forEach(([key, value]) => {
|
|
100
|
+
if (value) {
|
|
101
|
+
dimensions.push({
|
|
102
|
+
Name: key,
|
|
103
|
+
Value: value,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (dimensions.length > 0) {
|
|
108
|
+
metricData.Dimensions = dimensions;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return metricData;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Send metrics to CloudWatch using putMetricData.
|
|
115
|
+
*
|
|
116
|
+
* Errors are caught and logged but not re-thrown. If the client
|
|
117
|
+
* is null (local environment without SEND_CW_METRICS), this method
|
|
118
|
+
* returns immediately without sending.
|
|
119
|
+
*
|
|
120
|
+
* @private
|
|
121
|
+
* @param cw - CloudWatch client (may be null)
|
|
122
|
+
* @param metrics - Array of MetricDatum to send
|
|
123
|
+
* @returns Promise that resolves when the send operation completes (or immediately if client is null)
|
|
124
|
+
*/
|
|
125
|
+
async _putMetricData(cw, metrics) {
|
|
126
|
+
/* istanbul ignore next */
|
|
127
|
+
if (!cw) {
|
|
128
|
+
return Promise.resolve();
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const command = new PutMetricDataCommand({
|
|
132
|
+
MetricData: metrics,
|
|
133
|
+
Namespace: DEFAULT_NAMESPACE,
|
|
134
|
+
});
|
|
135
|
+
await cw.send(command);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
console.warn(`Metrics: error sending data: ${err}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Batch and send metrics. Handles batching into groups of 20 (CloudWatch limit)
|
|
143
|
+
* and sends them asynchronously (fire and forget). Errors are logged but not raised.
|
|
144
|
+
*
|
|
145
|
+
* @private
|
|
146
|
+
* @param metrics - Array of metrics to send
|
|
147
|
+
*/
|
|
148
|
+
_sendBatchedMetrics(metrics) {
|
|
149
|
+
if (metrics.length === 0) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const cw = this._setup();
|
|
153
|
+
const promises = [];
|
|
154
|
+
const batchSize = 20;
|
|
155
|
+
for (let i = 0; i < metrics.length; i += batchSize) {
|
|
156
|
+
const batch = metrics.slice(i, i + batchSize);
|
|
157
|
+
promises.push(this._putMetricData(cw, batch));
|
|
158
|
+
}
|
|
159
|
+
// Wait for all promises to complete, log any errors but don't raise them
|
|
160
|
+
Promise.all(promises).catch(
|
|
161
|
+
/* istanbul ignore next */
|
|
162
|
+
(err) => {
|
|
163
|
+
console.warn(`Metrics: error during batch send: ${err}`);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Send any queued metrics. Returns a Promise that resolves immediately
|
|
168
|
+
* after starting the send operations (fire and forget). Errors are logged
|
|
169
|
+
* but not raised. The queue is cleared before sending begins.
|
|
170
|
+
*
|
|
171
|
+
* @returns Promise that resolves immediately after starting send operations
|
|
172
|
+
*/
|
|
173
|
+
flush() {
|
|
174
|
+
const metricsToSend = [...this._queue];
|
|
175
|
+
this._queue = [];
|
|
176
|
+
this._sendBatchedMetrics(metricsToSend);
|
|
177
|
+
return Promise.resolve();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Add one or more custom metric values to the queue of those waiting
|
|
181
|
+
* to be sent, or send them immediately. This function supports simple
|
|
182
|
+
* name-and-value metrics. It doesn't support more complex CloudWatch types.
|
|
183
|
+
*
|
|
184
|
+
* A metric is an object with at least 'name' (string) and optionally 'value'
|
|
185
|
+
* (number, defaults to 0). It may also optionally include 'timestamp'
|
|
186
|
+
* (defaults to the time of the call to send()), and 'unit', which
|
|
187
|
+
* must be one of Seconds, Microseconds, Milliseconds, Bytes, Kilobytes,
|
|
188
|
+
* Megabytes, Gigabytes, Terabytes, Bits, Kilobits, Megabits, Gigabits,
|
|
189
|
+
* Terabits, Percent, Count, Bytes/Second, Kilobytes/Second,
|
|
190
|
+
* Megabytes/Second, Gigabytes/Second, Terabytes/Second,
|
|
191
|
+
* Bits/Second, Kilobits/Second, Megabits/Second, Gigabits/Second,
|
|
192
|
+
* Terabits/Second, Count/Second or None (defaults to 'Count').
|
|
193
|
+
* There may also be a 'dimensions'
|
|
194
|
+
* object, which has dimension names as keys and dimension
|
|
195
|
+
* values as values. Empty or falsy dimension values are filtered out.
|
|
196
|
+
*
|
|
197
|
+
* In a local development environment, metrics are queued but not sent
|
|
198
|
+
* unless the SEND_CW_METRICS environment variable is set. This allows
|
|
199
|
+
* for testing metric sending behavior locally.
|
|
200
|
+
*
|
|
201
|
+
* The metrics are added to an internal queue so that they can be
|
|
202
|
+
* batched up to send more efficiently. They are only sent when
|
|
203
|
+
* flush() is called, unless immediate is true.
|
|
204
|
+
*
|
|
205
|
+
* @private
|
|
206
|
+
* @param metrics - Array of InputMetric objects to send
|
|
207
|
+
* @param immediate - If true, send metrics immediately instead of queuing (default: false)
|
|
208
|
+
*/
|
|
209
|
+
send(metrics, immediate = false) {
|
|
210
|
+
const now = new Date();
|
|
211
|
+
const metricDataArray = metrics.map((metric) => this._convertToMetricDatum(metric, now));
|
|
212
|
+
if (immediate) {
|
|
213
|
+
// Send immediately without waiting (fire and forget)
|
|
214
|
+
this._sendBatchedMetrics(metricDataArray);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// Add to queue
|
|
218
|
+
this._queue.push(...metricDataArray);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get the singleton MetricsSender instance.
|
|
223
|
+
*
|
|
224
|
+
* Creates a new instance if one doesn't exist, otherwise returns
|
|
225
|
+
* the existing instance.
|
|
226
|
+
*
|
|
227
|
+
* @returns The singleton MetricsSender instance
|
|
228
|
+
*/
|
|
229
|
+
static getSender() {
|
|
230
|
+
if (!MetricsSender._instance) {
|
|
231
|
+
MetricsSender._instance = new MetricsSender();
|
|
232
|
+
}
|
|
233
|
+
return MetricsSender._instance;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Allow the presence of an environment variable to
|
|
237
|
+
// enable sending of CloudWatch metrics (for local
|
|
238
|
+
// integration testing)
|
|
239
|
+
MetricsSender._override = !!process.env.SEND_CW_METRICS;
|
|
240
|
+
//# sourceMappingURL=metrics-sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-sender.js","sourceRoot":"","sources":["../../../src/metrics/metrics-sender.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
2
|
+
export declare class DataStoreNotFoundError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class DataStoreServiceError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class DataStoreUnavailableError extends Error {
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A class for reading entries from the data store.
|
|
13
|
+
*
|
|
14
|
+
* This class uses a singleton pattern.
|
|
15
|
+
* Use DataStore.getDataStore() to get the singleton instance.
|
|
16
|
+
*/
|
|
17
|
+
export declare class DataStore {
|
|
18
|
+
private _tableName;
|
|
19
|
+
private _ddb;
|
|
20
|
+
private static _instance;
|
|
21
|
+
/** @internal Test hook: inject a document client for unit tests */
|
|
22
|
+
static _testDocumentClient: DynamoDBDocumentClient | null;
|
|
23
|
+
/** @internal Test hook: inject logMRTError for unit tests */
|
|
24
|
+
static _testLogMRTError: ((namespace: string, err: unknown, context?: Record<string, unknown>) => void) | null;
|
|
25
|
+
private constructor();
|
|
26
|
+
/**
|
|
27
|
+
* Get or create a DynamoDB document client (for abstraction of attribute values).
|
|
28
|
+
*
|
|
29
|
+
* @private
|
|
30
|
+
* @returns The DynamoDB document client
|
|
31
|
+
* @throws {DataStoreUnavailableError} The data store is unavailable
|
|
32
|
+
*/
|
|
33
|
+
private getClient;
|
|
34
|
+
/**
|
|
35
|
+
* Get or create the singleton DataStore instance.
|
|
36
|
+
*
|
|
37
|
+
* @returns The singleton DataStore instance
|
|
38
|
+
*/
|
|
39
|
+
static getDataStore(): DataStore;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the data store can be used in the current environment.
|
|
42
|
+
*
|
|
43
|
+
* @returns true if the data store is available, false otherwise
|
|
44
|
+
*/
|
|
45
|
+
isDataStoreAvailable(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Fetch an entry from the data store.
|
|
48
|
+
*
|
|
49
|
+
* @param key The data store entry's key
|
|
50
|
+
* @returns An object containing the entry's key and value
|
|
51
|
+
* @throws {DataStoreUnavailableError} The data store is unavailable
|
|
52
|
+
* @throws {DataStoreNotFoundError} An entry with the given key cannot be found
|
|
53
|
+
* @throws {DataStoreServiceError} An internal error occurred
|
|
54
|
+
*/
|
|
55
|
+
getEntry(key: string): Promise<Record<string, unknown> | undefined>;
|
|
56
|
+
}
|