-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
111 lines (99 loc) · 3.13 KB
/
index.js
File metadata and controls
111 lines (99 loc) · 3.13 KB
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
const { SNSClient, PublishCommand } = require("@aws-sdk/client-sns");
const { hostname } = require("os");
const { join, dirname } = require("path");
const { existsSync } = require('fs');
// search upwards and get the top-level package.json we can find:
function findPackageJson(mod) {
if (!mod) return null;
const foundInParent = findPackageJson(mod.parent);
if (foundInParent) {
return foundInParent;
} else {
const f = join(dirname(mod.filename), 'package.json');
if (existsSync(f)) {
let r = {};
try {
r = require(f);
} catch (e) {
console.error(`${f} not readable: no app information available for critical-error`);
}
return r;
} else {
return null;
}
}
}
const app_package = findPackageJson(module) || {};
let Configured_Options = null;
let SNS = null;
let inFlight = 0;
let waitingCallbacks = [];
const sendMessage = async function(params){
try {
inFlight += 1;
await SNS.send(new PublishCommand(params));
} catch (err) {
console.error("SNS send failed", err);
} finally {
inFlight -= 1;
// NOTE: we deliberately do not check if inFlight has reached 0 here.
// If there was an error logging the error we could easily end in a
// loop
const waiting = waitingCallbacks;
waitingCallbacks = [];
for (const cb of waiting) {
cb();
}
}
}
function critical(message_or_error){
if(!Configured_Options){
console.error(new Error("critical() not configured yet!"), message_or_error);
return;
}
const params = Object.assign({}, Configured_Options);
let error_info = {};
if(message_or_error.stack){
error_info = message_or_error;
}else{
Error.captureStackTrace(error_info, critical);
}
params.Message = `${message_or_error} \n(stack:${error_info.stack})`;
console.error(`${params.Subject} ${params.Message}`);
sendMessage(params);
}
critical.configure = function(options){
if(Configured_Options){
console.error(new Error("critical() configuration overwritten"));
}
Configured_Options = Object.assign({}, options);
// the region option is used when constructing SNS, the others when
// publishing
const region = Configured_Options.region;
delete Configured_Options.region;
SNS = new SNSClient({region:region});
Configured_Options.Subject =
Configured_Options.Subject ||
`Error on ${hostname()} ${process.env.NODE_ENV} in ${app_package.name} ${app_package.version}`;
};
critical.waitForCompletion = function waitForCompletion(cb) {
if (!cb) {
return new Promise(resolve => {
waitForCompletion(resolve);
});
}
if (inFlight === 0) {
cb();
}else {
waitingCallbacks.push(cb);
}
}
process.on('uncaughtException', function(err){
try{
critical(err);
}catch(e){
console.error("Error handling uncaught error", e);
console.error("The original error was", err);
}
});
module.exports = critical