vtlab-generic-functions 1.0.18 → 1.0.19
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/cloudwatch/index.js +57 -11
- package/config/index.js +2 -10
- package/package.json +1 -1
- package/rds/index.js +1 -1
package/cloudwatch/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
const { SQSClient, SendMessageCommand } = require('@aws-sdk/client-sqs');
|
|
2
2
|
const { randomUUID } = require('crypto');
|
|
3
3
|
const config = require('../config');
|
|
4
|
+
const s3bucket = require("../s3bucket");
|
|
5
|
+
const secretsManager = require("../config");
|
|
4
6
|
|
|
5
7
|
if (!global.LOG_STREAM_NAME) {
|
|
6
8
|
global.LOG_STREAM_NAME = `${process.env.AWS_LAMBDA_FUNCTION_NAME}-${process.env.AWS_LAMBDA_LOG_STREAM_NAME}-${randomUUID()}`;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
const safeStringify = obj => {
|
|
10
12
|
//this avoids circular references
|
|
11
13
|
const cache = new Set();
|
|
12
14
|
return JSON.stringify(obj, (key, value) => {
|
|
@@ -19,15 +21,39 @@ function safeStringify(obj) {
|
|
|
19
21
|
}
|
|
20
22
|
return value;
|
|
21
23
|
});
|
|
22
|
-
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const generateTimestampWithRandomLetters = () => {
|
|
27
|
+
const getRandomLetter = () => {
|
|
28
|
+
const letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
29
|
+
return letters.charAt(Math.floor(Math.random() * letters.length));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getRandomLetters = (count) => {
|
|
33
|
+
let result = '';
|
|
34
|
+
for (let i = 0; i < count; i++) {
|
|
35
|
+
result += getRandomLetter();
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
41
|
+
const randomLetters = getRandomLetters(4);
|
|
42
|
+
|
|
43
|
+
return `${timestamp}${randomLetters}`;
|
|
44
|
+
};
|
|
23
45
|
|
|
24
46
|
const putLogEvents = async (logEvents = [], logGroupName, logLevel = 2, logStreamName = null) => {
|
|
25
47
|
if (logLevel === 0) {
|
|
26
48
|
return;
|
|
27
49
|
}
|
|
28
50
|
|
|
29
|
-
if
|
|
30
|
-
|
|
51
|
+
if(!logStreamName){
|
|
52
|
+
logStreamName = global.LOG_STREAM_NAME;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!logGroupName || !logStreamName) {
|
|
56
|
+
throw new Error('logEvents and logGroupName and logStreamName are required');
|
|
31
57
|
}
|
|
32
58
|
|
|
33
59
|
let awsCredentials = await config.get('awsCredentials');
|
|
@@ -82,20 +108,40 @@ const putLogEvents = async (logEvents = [], logGroupName, logLevel = 2, logStrea
|
|
|
82
108
|
}
|
|
83
109
|
|
|
84
110
|
let cloudWatchLogEvents = [];
|
|
85
|
-
|
|
111
|
+
//max 8kb log event
|
|
112
|
+
let maxBytes = 8*1024;
|
|
86
113
|
for (let logEvent of logEvents) {
|
|
87
114
|
if (logEvent.length > maxBytes) {
|
|
88
|
-
|
|
89
|
-
|
|
115
|
+
let bucketOptions = {
|
|
116
|
+
ACL: "private", ContentType: 'text/plain'
|
|
117
|
+
}
|
|
118
|
+
//get first 300 chars
|
|
119
|
+
const logFirst300Chars = logEvent.substring(0, 300);
|
|
120
|
+
try {
|
|
121
|
+
let groupFolder = logGroupName.replace(/\//g, '_');
|
|
122
|
+
let streamName = logStreamName.replace(/\//g, '_');
|
|
123
|
+
const path = `${process.env.NODE_ENV}/errors/${groupFolder}/${streamName}/${generateTimestampWithRandomLetters()}.txt`;
|
|
124
|
+
//upload logevent to s3
|
|
125
|
+
let bucketConfirmedPath = await s3bucket.uploadToS3(path, logEvent, bucketOptions, "s3LogsBucket");
|
|
126
|
+
console.log("bucketConfirmedPath", bucketConfirmedPath);
|
|
127
|
+
// get bucket name from s3 secrets
|
|
128
|
+
let bucket = await secretsManager.get('s3LogsBucket');
|
|
129
|
+
let signedURL = await s3bucket.generatePresignedUrl(bucket, path);
|
|
130
|
+
|
|
131
|
+
// Set event with the signed URL
|
|
132
|
+
cloudWatchLogEvents.push({
|
|
133
|
+
message: `${logLevel} ${logFirst300Chars}... Payload size too big. Read the full log here: ${path} ${signedURL}`,
|
|
134
|
+
timestamp: new Date().getTime()
|
|
135
|
+
});
|
|
136
|
+
} catch (e) {
|
|
90
137
|
cloudWatchLogEvents.push({
|
|
91
|
-
message: `${logLevel} ${
|
|
138
|
+
message: `${logLevel} ${logFirst300Chars}... Payload size too big. Error uploading to S3: ${e.message}`,
|
|
92
139
|
timestamp: new Date().getTime()
|
|
93
140
|
});
|
|
94
141
|
}
|
|
95
142
|
} else {
|
|
96
143
|
cloudWatchLogEvents.push({
|
|
97
|
-
message: `${logLevel} ${logEvent}`,
|
|
98
|
-
timestamp: new Date().getTime()
|
|
144
|
+
message: `${logLevel} ${logEvent}`, timestamp: new Date().getTime()
|
|
99
145
|
});
|
|
100
146
|
}
|
|
101
147
|
}
|
|
@@ -113,7 +159,7 @@ const putLogEvents = async (logEvents = [], logGroupName, logLevel = 2, logStrea
|
|
|
113
159
|
MessageBody: JSON.stringify({
|
|
114
160
|
logEvents: [event],
|
|
115
161
|
logGroupName: logGroupName,
|
|
116
|
-
logStreamName: logStreamName
|
|
162
|
+
logStreamName: logStreamName,
|
|
117
163
|
logLevel: logLevel
|
|
118
164
|
}),
|
|
119
165
|
QueueUrl
|
package/config/index.js
CHANGED
|
@@ -16,27 +16,19 @@ const getObjectByString = (obj, key) => {
|
|
|
16
16
|
// Cache object
|
|
17
17
|
let cache = {};
|
|
18
18
|
|
|
19
|
-
const getConfigValuesFromS3Bucket = async (configKey = null,
|
|
19
|
+
const getConfigValuesFromS3Bucket = async (configKey = null, ifValuesFromRoot = null) => {
|
|
20
20
|
const { NODE_ENV, TOOK_SECRETS_BUCKET, TOOK_SECRETS_DEVELOP, TOOK_SECRETS_PRODUCTION } = process.env;
|
|
21
21
|
let defaultEnvironment = NODE_ENV;
|
|
22
|
-
let valuesFromRoot;
|
|
23
|
-
if(env==="rds" || env==="notificationEmailForDebug") {
|
|
24
|
-
valuesFromRoot = env;
|
|
25
|
-
env = null;
|
|
26
|
-
}
|
|
27
22
|
const availableEnvironments = ['production', 'develop', 'staging', 'uat', 'demo', 'test', 'testing'];
|
|
28
23
|
if (!defaultEnvironment || !availableEnvironments.includes(defaultEnvironment)) {
|
|
29
24
|
defaultEnvironment = 'develop';
|
|
30
25
|
}
|
|
31
|
-
|
|
26
|
+
const effectiveEnvironment = ifValuesFromRoot || defaultEnvironment;
|
|
32
27
|
let secretName = TOOK_SECRETS_DEVELOP;
|
|
33
28
|
if (effectiveEnvironment === 'production') {
|
|
34
29
|
secretName = TOOK_SECRETS_PRODUCTION;
|
|
35
30
|
}
|
|
36
31
|
const secretsBucketName = TOOK_SECRETS_BUCKET;
|
|
37
|
-
if(valuesFromRoot) {
|
|
38
|
-
effectiveEnvironment = valuesFromRoot;
|
|
39
|
-
}
|
|
40
32
|
|
|
41
33
|
// Check cache first
|
|
42
34
|
if (cache[effectiveEnvironment] && (!configKey || cache[effectiveEnvironment][configKey])) {
|
package/package.json
CHANGED
package/rds/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const {getValueOrNull} = require('../utils/index');
|
|
|
9
9
|
*/
|
|
10
10
|
const connectMyRDS = async (databaseName) => {
|
|
11
11
|
try {
|
|
12
|
-
const dbParams = await config.get(databaseName
|
|
12
|
+
const dbParams = await config.get(`databaseName.rds`);
|
|
13
13
|
|
|
14
14
|
if (!dbParams) {
|
|
15
15
|
throw new Error('Database name is not valid in the Secret Manager');
|