mynth-logger 1.2.0 → 2.0.2
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/.github/workflows/CI.yaml +4 -26
- package/.github/workflows/publish.yml +1 -1
- package/README.md +21 -11
- package/dist/src/format.d.ts +2 -0
- package/dist/src/format.js +38 -0
- package/dist/src/logging.d.ts +2 -20
- package/dist/src/logging.js +11 -76
- package/dist/src/reporters/datadog.d.ts +5 -0
- package/dist/src/reporters/datadog.js +21 -0
- package/dist/src/reporters/discord.d.ts +5 -0
- package/dist/src/reporters/discord.js +81 -0
- package/dist/tests/app.js +8 -2
- package/dist/tests/index.test.js +2 -10
- package/package.json +24 -17
- package/src/format.ts +43 -0
- package/src/logging.ts +11 -108
- package/src/reporters/datadog.ts +23 -0
- package/src/reporters/discord.ts +66 -0
- package/tests/app.ts +8 -1
- package/tests/index.test.ts +2 -13
- package/tsconfig.json +8 -3
- package/dist/src/run.d.ts +0 -1
- package/dist/src/run.js +0 -10
- package/dist/src/transports/datadog-stdout.d.ts +0 -3
- package/dist/src/transports/datadog-stdout.js +0 -55
- package/dist/src/transports/discord.d.ts +0 -3
- package/dist/src/transports/discord.js +0 -45
- package/src/run.ts +0 -10
- package/src/transports/datadog-stdout.ts +0 -33
- package/src/transports/discord.ts +0 -65
|
@@ -17,7 +17,7 @@ jobs:
|
|
|
17
17
|
- name: Set up Node.js
|
|
18
18
|
uses: actions/setup-node@v3
|
|
19
19
|
with:
|
|
20
|
-
node-version: 18
|
|
20
|
+
node-version: 18.18
|
|
21
21
|
check-latest: true
|
|
22
22
|
|
|
23
23
|
- name: Update npm
|
|
@@ -29,28 +29,6 @@ jobs:
|
|
|
29
29
|
- name: Run tests
|
|
30
30
|
run: npm run test
|
|
31
31
|
|
|
32
|
-
test-pretty:
|
|
33
|
-
runs-on: ubuntu-latest
|
|
34
|
-
timeout-minutes: 10
|
|
35
|
-
steps:
|
|
36
|
-
- name: Checkout repository
|
|
37
|
-
uses: actions/checkout@v3
|
|
38
|
-
|
|
39
|
-
- name: Set up Node.js
|
|
40
|
-
uses: actions/setup-node@v3
|
|
41
|
-
with:
|
|
42
|
-
node-version: 18
|
|
43
|
-
check-latest: true
|
|
44
|
-
|
|
45
|
-
- name: Update npm
|
|
46
|
-
run: npm install -g npm@latest
|
|
47
|
-
|
|
48
|
-
- name: Install dependencies
|
|
49
|
-
run: npm ci --include dev
|
|
50
|
-
|
|
51
|
-
- name: Run tests
|
|
52
|
-
run: npm run test:pretty
|
|
53
|
-
|
|
54
32
|
test-run:
|
|
55
33
|
runs-on: ubuntu-latest
|
|
56
34
|
timeout-minutes: 10
|
|
@@ -61,7 +39,7 @@ jobs:
|
|
|
61
39
|
- name: Set up Node.js
|
|
62
40
|
uses: actions/setup-node@v3
|
|
63
41
|
with:
|
|
64
|
-
node-version: 18
|
|
42
|
+
node-version: 18.18
|
|
65
43
|
check-latest: true
|
|
66
44
|
|
|
67
45
|
- name: Update npm
|
|
@@ -71,7 +49,7 @@ jobs:
|
|
|
71
49
|
run: npm ci --include dev
|
|
72
50
|
|
|
73
51
|
- name: Run tests
|
|
74
|
-
run:
|
|
52
|
+
run: npx tsx tests/app.ts
|
|
75
53
|
|
|
76
54
|
lint:
|
|
77
55
|
runs-on: ubuntu-latest
|
|
@@ -84,7 +62,7 @@ jobs:
|
|
|
84
62
|
- name: Set up Node.js
|
|
85
63
|
uses: actions/setup-node@v3
|
|
86
64
|
with:
|
|
87
|
-
node-version: 18
|
|
65
|
+
node-version: 18.18
|
|
88
66
|
check-latest: true
|
|
89
67
|
|
|
90
68
|
- name: Update npm
|
package/README.md
CHANGED
|
@@ -34,13 +34,6 @@ analysis, and alerting.
|
|
|
34
34
|
npm install mynth-logger
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
**For local development**, install `pino-pretty` to enable colorful log
|
|
38
|
-
output:
|
|
39
|
-
|
|
40
|
-
``` bash
|
|
41
|
-
npm install --save-dev pino-pretty
|
|
42
|
-
```
|
|
43
|
-
|
|
44
37
|
### Usage
|
|
45
38
|
|
|
46
39
|
**Import and set up logging** in your entrypoint script:
|
|
@@ -59,12 +52,29 @@ formatting the logs appropriately based on the environment:
|
|
|
59
52
|
console.log('This is a log message');
|
|
60
53
|
```
|
|
61
54
|
|
|
62
|
-
In **development
|
|
55
|
+
In **development** (when NODE\_ENV isn’t set to `production`), you’ll
|
|
56
|
+
see colorful logs in the terminal.
|
|
63
57
|
|
|
64
|
-
In **production
|
|
58
|
+
In **production** (when NODE\_ENV is set to `production`), logs will be
|
|
59
|
+
output in JSON format to stdout.
|
|
65
60
|
|
|
66
61
|
## Configuration
|
|
67
62
|
|
|
68
63
|
No additional configuration is required to start using Mynth Logger.
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
|
|
65
|
+
## Discord
|
|
66
|
+
|
|
67
|
+
To send a message to Discord:
|
|
68
|
+
|
|
69
|
+
``` typescript
|
|
70
|
+
console.info("Sending this message to discord", {
|
|
71
|
+
discord: true,
|
|
72
|
+
color: "2404635",
|
|
73
|
+
title: "This is a test",
|
|
74
|
+
webhookUrl,
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A valid Discord webhook URL needs to be passed in as a parameter. This
|
|
79
|
+
will be used to send the message to Discord, but it won’t be outputted
|
|
80
|
+
to the logs.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.format = void 0;
|
|
4
|
+
const json_1 = require("@ungap/structured-clone/json");
|
|
5
|
+
const formatItem = (item) => {
|
|
6
|
+
if (typeof item === "undefined") {
|
|
7
|
+
return "undefined";
|
|
8
|
+
}
|
|
9
|
+
// Remove colors from strings
|
|
10
|
+
if (typeof item === "string") {
|
|
11
|
+
// eslint-disable-next-line no-control-regex
|
|
12
|
+
return item.replace(/\x1b\[[0-9;]*m/g, "");
|
|
13
|
+
}
|
|
14
|
+
// Check if this is an Error
|
|
15
|
+
if (item &&
|
|
16
|
+
typeof item === "object" &&
|
|
17
|
+
"message" in item &&
|
|
18
|
+
typeof item.message === "string")
|
|
19
|
+
return item.message;
|
|
20
|
+
// Check if this is a string
|
|
21
|
+
if (typeof item === "string")
|
|
22
|
+
return item;
|
|
23
|
+
const stringified = (() => {
|
|
24
|
+
try {
|
|
25
|
+
return (0, json_1.stringify)(item);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return String(item);
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
31
|
+
return stringified.replace(/^'|'$/g, "");
|
|
32
|
+
};
|
|
33
|
+
const format = (items) => {
|
|
34
|
+
return Array.from(items)
|
|
35
|
+
.map((item) => formatItem(item))
|
|
36
|
+
.join(" ");
|
|
37
|
+
};
|
|
38
|
+
exports.format = format;
|
package/dist/src/logging.d.ts
CHANGED
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
untilFinished: Promise<void>;
|
|
4
|
-
};
|
|
5
|
-
declare enum KnownTransports {
|
|
6
|
-
Discord = "./transports/discord.js",
|
|
7
|
-
Stdout = "./transports/datadog-stdout.js"
|
|
8
|
-
}
|
|
9
|
-
type Target = {
|
|
10
|
-
target: KnownTransports;
|
|
11
|
-
level: string;
|
|
12
|
-
options: object;
|
|
13
|
-
};
|
|
14
|
-
type Params = {
|
|
15
|
-
options?: LoggerOptions;
|
|
16
|
-
pretty?: boolean;
|
|
17
|
-
targets?: Target[];
|
|
18
|
-
};
|
|
19
|
-
declare const setupLogging: (args?: Params) => AwaitableLogger;
|
|
20
|
-
export { AwaitableLogger, KnownTransports, setupLogging };
|
|
1
|
+
declare const setupLogging: () => import("consola").ConsolaInstance;
|
|
2
|
+
export { setupLogging };
|
package/dist/src/logging.js
CHANGED
|
@@ -3,81 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.setupLogging =
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
// Remove colors from strings
|
|
19
|
-
if (typeof item === "string") {
|
|
20
|
-
// eslint-disable-next-line no-control-regex
|
|
21
|
-
return item.replace(/\x1b\[[0-9;]*m/g, "");
|
|
22
|
-
}
|
|
23
|
-
// Check if this is an Error
|
|
24
|
-
if (item &&
|
|
25
|
-
typeof item === "object" &&
|
|
26
|
-
"message" in item &&
|
|
27
|
-
typeof item.message === "string")
|
|
28
|
-
return item.message;
|
|
29
|
-
// Check if this is a string
|
|
30
|
-
if (typeof item === "string")
|
|
31
|
-
return item;
|
|
32
|
-
const stringified = (() => {
|
|
33
|
-
try {
|
|
34
|
-
return (0, json_1.stringify)(item);
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return String(item);
|
|
38
|
-
}
|
|
39
|
-
})();
|
|
40
|
-
return stringified.replace(/^'|'$/g, "");
|
|
41
|
-
};
|
|
42
|
-
const format = (items) => {
|
|
43
|
-
return Array.from(items)
|
|
44
|
-
.map((item) => formatItem(item))
|
|
45
|
-
.join(" ");
|
|
46
|
-
};
|
|
47
|
-
const overrideConsole = (logger) => {
|
|
48
|
-
console.log = function (...args) {
|
|
49
|
-
logger.info(format(Array.from(args)));
|
|
50
|
-
};
|
|
51
|
-
console.info = function (...args) {
|
|
52
|
-
logger.info(format(Array.from(args)));
|
|
53
|
-
};
|
|
54
|
-
console.warn = function (...args) {
|
|
55
|
-
logger.warn(format(Array.from(args)));
|
|
56
|
-
};
|
|
57
|
-
console.error = function (...args) {
|
|
58
|
-
logger.error(format(Array.from(args)));
|
|
59
|
-
};
|
|
60
|
-
console.debug = function (...args) {
|
|
61
|
-
logger.debug(format(Array.from(args)));
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
const setupLogging = (args = {}) => {
|
|
65
|
-
const transportTargets = [
|
|
66
|
-
{
|
|
67
|
-
target: KnownTransports.Stdout,
|
|
68
|
-
level: "debug",
|
|
69
|
-
options: { pretty: args.pretty != false },
|
|
70
|
-
},
|
|
71
|
-
...(args.targets || []),
|
|
72
|
-
];
|
|
73
|
-
const transport = pino_1.default.transport({
|
|
74
|
-
targets: transportTargets,
|
|
75
|
-
});
|
|
76
|
-
const logger = (0, pino_1.default)(args.options || { level: "debug" }, transport);
|
|
77
|
-
logger.untilFinished = new Promise((resolve) => {
|
|
78
|
-
transport.on("ready", resolve);
|
|
79
|
-
});
|
|
80
|
-
typeof window === "undefined" && overrideConsole(logger);
|
|
81
|
-
return logger;
|
|
6
|
+
exports.setupLogging = void 0;
|
|
7
|
+
const consola_1 = require("consola");
|
|
8
|
+
const datadog_js_1 = __importDefault(require("./reporters/datadog.js"));
|
|
9
|
+
const discord_js_1 = __importDefault(require("./reporters/discord.js"));
|
|
10
|
+
const setupLogging = () => {
|
|
11
|
+
const consola = (0, consola_1.createConsola)({ fancy: true, level: 5 });
|
|
12
|
+
if (process.env.NODE_ENV === "production")
|
|
13
|
+
consola.setReporters([datadog_js_1.default]);
|
|
14
|
+
consola.setReporters([discord_js_1.default, ...consola.options.reporters]);
|
|
15
|
+
consola.wrapConsole();
|
|
16
|
+
return consola;
|
|
82
17
|
};
|
|
83
18
|
exports.setupLogging = setupLogging;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const format_js_1 = require("../format.js");
|
|
4
|
+
const levelMap = {
|
|
5
|
+
0: "error",
|
|
6
|
+
1: "warn",
|
|
7
|
+
2: "info",
|
|
8
|
+
3: "info",
|
|
9
|
+
4: "debug",
|
|
10
|
+
5: "debug",
|
|
11
|
+
};
|
|
12
|
+
const Reporter = {
|
|
13
|
+
log: (logObj) => {
|
|
14
|
+
const message = JSON.stringify({
|
|
15
|
+
level: levelMap[logObj.level] || "debug",
|
|
16
|
+
message: (0, format_js_1.format)(logObj.args),
|
|
17
|
+
});
|
|
18
|
+
process.stdout.write(`${message}\n`);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
exports.default = Reporter;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const format_js_1 = require("../format.js");
|
|
30
|
+
const arktype_1 = require("arktype");
|
|
31
|
+
const axios_1 = __importDefault(require("axios"));
|
|
32
|
+
const axios_retry_1 = __importStar(require("axios-retry"));
|
|
33
|
+
const Discord = (0, arktype_1.type)({
|
|
34
|
+
discord: (0, arktype_1.type)("boolean").narrow((v) => v),
|
|
35
|
+
color: "string",
|
|
36
|
+
title: "string",
|
|
37
|
+
webhookUrl: "string",
|
|
38
|
+
});
|
|
39
|
+
const NullDiscord = { discord: false };
|
|
40
|
+
const Reporter = {
|
|
41
|
+
log: (logObj) => {
|
|
42
|
+
const [discord, args] = getDiscord(logObj.args);
|
|
43
|
+
if (!discord.discord)
|
|
44
|
+
return;
|
|
45
|
+
sendToDiscord((0, format_js_1.format)(args), discord);
|
|
46
|
+
// Filter Discord data before the other reporters
|
|
47
|
+
// process the message
|
|
48
|
+
logObj.args = args;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
const getDiscord = (args) => {
|
|
52
|
+
for (let i = 0; i < args.length; i++) {
|
|
53
|
+
const discord = Discord(args[i]);
|
|
54
|
+
if (discord instanceof arktype_1.type.errors)
|
|
55
|
+
continue;
|
|
56
|
+
return [discord, args.filter((_, j) => j !== i)];
|
|
57
|
+
}
|
|
58
|
+
return [NullDiscord, args];
|
|
59
|
+
};
|
|
60
|
+
const sendToDiscord = async (description, options) => {
|
|
61
|
+
const axiosInstance = axios_1.default.create();
|
|
62
|
+
(0, axios_retry_1.default)(axiosInstance, {
|
|
63
|
+
retries: 3,
|
|
64
|
+
retryDelay: axios_retry_1.exponentialDelay,
|
|
65
|
+
});
|
|
66
|
+
try {
|
|
67
|
+
await axiosInstance.post(options.webhookUrl, {
|
|
68
|
+
embeds: [
|
|
69
|
+
{
|
|
70
|
+
title: options.title,
|
|
71
|
+
description,
|
|
72
|
+
color: options.color,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error("Unable to send message to Discord", error);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
exports.default = Reporter;
|
package/dist/tests/app.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
3
|
+
const mynth_logger_1 = require("mynth-logger");
|
|
4
4
|
const run = async () => {
|
|
5
|
-
(0,
|
|
5
|
+
(0, mynth_logger_1.setupLogging)();
|
|
6
6
|
console.log("Hello, this is a log");
|
|
7
7
|
console.info("Hello, this is an info log");
|
|
8
8
|
console.debug("Hello, this is a debug log");
|
|
@@ -57,5 +57,11 @@ const run = async () => {
|
|
|
57
57
|
}
|
|
58
58
|
console.log("This is concatenating an object", {});
|
|
59
59
|
console.log("This is an object with bigint", { name: "bigint", value: 100n });
|
|
60
|
+
console.info("Sending this message to discord", {
|
|
61
|
+
discord: true,
|
|
62
|
+
color: "2404635",
|
|
63
|
+
title: "This is a test",
|
|
64
|
+
webhookUrl: process.env["DISCORD_TEST_WEB_HOOK"],
|
|
65
|
+
});
|
|
60
66
|
};
|
|
61
67
|
run();
|
package/dist/tests/index.test.js
CHANGED
|
@@ -4,17 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const ava_1 = __importDefault(require("ava"));
|
|
7
|
-
const
|
|
8
|
-
let logger;
|
|
9
|
-
const sleep = (ms) => {
|
|
10
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
|
-
};
|
|
7
|
+
const mynth_logger_1 = require("mynth-logger");
|
|
12
8
|
ava_1.default.before(() => {
|
|
13
|
-
|
|
14
|
-
});
|
|
15
|
-
ava_1.default.afterEach(async () => {
|
|
16
|
-
await sleep(100);
|
|
17
|
-
logger && (await logger.untilFinished);
|
|
9
|
+
(0, mynth_logger_1.setupLogging)();
|
|
18
10
|
});
|
|
19
11
|
ava_1.default.serial("logs display to terminal", (t) => {
|
|
20
12
|
console.debug("Hello ava");
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mynth-logger",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Package to format logs for mynth microservices.",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "npx tsc",
|
|
9
|
-
"test": "npx
|
|
10
|
-
"test:pretty": "npx tsc && TEST_PRETTY=true npx ava",
|
|
8
|
+
"build": "rm -rf dist && npx tsc",
|
|
9
|
+
"test": "npx ava",
|
|
11
10
|
"logs": "npx tsc && node dist/src/run.js",
|
|
12
11
|
"prettier": "npx prettier -w '**/*.{js,jsx,ts,tsx,json,yml.j2,yml,yaml,.*}'",
|
|
13
12
|
"lint": "concurrently \"npx prettier --check '**/*.{js,jsx,ts,tsx,json,yml.j2,yml,yaml,.*}'\" \"npx eslint . --max-warnings=0\""
|
|
@@ -23,27 +22,35 @@
|
|
|
23
22
|
},
|
|
24
23
|
"dependencies": {
|
|
25
24
|
"@ungap/structured-clone": "^1.2.0",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
25
|
+
"arktype": "^2.0.0-dev.16",
|
|
26
|
+
"axios": "^1.7.2",
|
|
27
|
+
"axios-retry": "^4.3.0",
|
|
28
|
+
"consola": "^3.2.3"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^20.
|
|
31
|
+
"@types/node": "^20.12.12",
|
|
31
32
|
"@types/ungap__structured-clone": "^1.2.0",
|
|
32
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
33
|
-
"ava": "^
|
|
34
|
-
"concurrently": "^8.2.
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
|
34
|
+
"ava": "^6.1.3",
|
|
35
|
+
"concurrently": "^8.2.2",
|
|
35
36
|
"eslint": "^8.47.0",
|
|
36
37
|
"eslint-plugin-ava": "^14.0.0",
|
|
37
|
-
"eslint-plugin-file-extension-in-import-ts": "^1.0
|
|
38
|
-
"eslint-plugin-import": "^2.
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"typescript": "^5.1.6"
|
|
38
|
+
"eslint-plugin-file-extension-in-import-ts": "^2.1.0",
|
|
39
|
+
"eslint-plugin-import": "^2.29.1",
|
|
40
|
+
"prettier": "^3.2.5",
|
|
41
|
+
"tsx": "^4.11.0",
|
|
42
|
+
"typescript": "^5.4.5"
|
|
43
43
|
},
|
|
44
44
|
"ava": {
|
|
45
45
|
"files": [
|
|
46
|
-
"
|
|
46
|
+
"**/*.test.ts"
|
|
47
|
+
],
|
|
48
|
+
"extensions": {
|
|
49
|
+
"ts": "module"
|
|
50
|
+
},
|
|
51
|
+
"nodeArguments": [
|
|
52
|
+
"--loader=tsx",
|
|
53
|
+
"--no-warnings"
|
|
47
54
|
]
|
|
48
55
|
}
|
|
49
56
|
}
|
package/src/format.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { stringify } from "@ungap/structured-clone/json";
|
|
2
|
+
|
|
3
|
+
const formatItem = (item: unknown): string => {
|
|
4
|
+
if (typeof item === "undefined") {
|
|
5
|
+
return "undefined";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Remove colors from strings
|
|
9
|
+
if (typeof item === "string") {
|
|
10
|
+
// eslint-disable-next-line no-control-regex
|
|
11
|
+
return item.replace(/\x1b\[[0-9;]*m/g, "");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Check if this is an Error
|
|
15
|
+
if (
|
|
16
|
+
item &&
|
|
17
|
+
typeof item === "object" &&
|
|
18
|
+
"message" in item &&
|
|
19
|
+
typeof item.message === "string"
|
|
20
|
+
)
|
|
21
|
+
return item.message;
|
|
22
|
+
|
|
23
|
+
// Check if this is a string
|
|
24
|
+
if (typeof item === "string") return item;
|
|
25
|
+
|
|
26
|
+
const stringified = (() => {
|
|
27
|
+
try {
|
|
28
|
+
return stringify(item);
|
|
29
|
+
} catch {
|
|
30
|
+
return String(item);
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
return stringified.replace(/^'|'$/g, "");
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const format = (items: unknown[]): string => {
|
|
38
|
+
return Array.from(items)
|
|
39
|
+
.map((item) => formatItem(item))
|
|
40
|
+
.join(" ");
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export { format };
|
package/src/logging.ts
CHANGED
|
@@ -1,113 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { createConsola } from "consola";
|
|
2
|
+
import DatadogReporter from "./reporters/datadog.js";
|
|
3
|
+
import DiscordReporter from "./reporters/discord.js";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
enum KnownTransports {
|
|
9
|
-
Discord = "./transports/discord.js",
|
|
10
|
-
Stdout = "./transports/datadog-stdout.js",
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type Target = {
|
|
14
|
-
target: KnownTransports;
|
|
15
|
-
level: string;
|
|
16
|
-
options: object;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type Params = {
|
|
20
|
-
options?: LoggerOptions;
|
|
21
|
-
pretty?: boolean;
|
|
22
|
-
targets?: Target[];
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const formatItem = (item: unknown): string => {
|
|
26
|
-
if (typeof item === "undefined") {
|
|
27
|
-
return "undefined";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Remove colors from strings
|
|
31
|
-
if (typeof item === "string") {
|
|
32
|
-
// eslint-disable-next-line no-control-regex
|
|
33
|
-
return item.replace(/\x1b\[[0-9;]*m/g, "");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Check if this is an Error
|
|
37
|
-
if (
|
|
38
|
-
item &&
|
|
39
|
-
typeof item === "object" &&
|
|
40
|
-
"message" in item &&
|
|
41
|
-
typeof item.message === "string"
|
|
42
|
-
)
|
|
43
|
-
return item.message;
|
|
44
|
-
|
|
45
|
-
// Check if this is a string
|
|
46
|
-
if (typeof item === "string") return item;
|
|
47
|
-
|
|
48
|
-
const stringified = (() => {
|
|
49
|
-
try {
|
|
50
|
-
return stringify(item);
|
|
51
|
-
} catch {
|
|
52
|
-
return String(item);
|
|
53
|
-
}
|
|
54
|
-
})();
|
|
55
|
-
|
|
56
|
-
return stringified.replace(/^'|'$/g, "");
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const format = (items: unknown[]): string => {
|
|
60
|
-
return Array.from(items)
|
|
61
|
-
.map((item) => formatItem(item))
|
|
62
|
-
.join(" ");
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const overrideConsole = (logger: Logger) => {
|
|
66
|
-
console.log = function (...args) {
|
|
67
|
-
logger.info(format(Array.from(args)));
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
console.info = function (...args) {
|
|
71
|
-
logger.info(format(Array.from(args)));
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
console.warn = function (...args) {
|
|
75
|
-
logger.warn(format(Array.from(args)));
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
console.error = function (...args) {
|
|
79
|
-
logger.error(format(Array.from(args)));
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
console.debug = function (...args) {
|
|
83
|
-
logger.debug(format(Array.from(args)));
|
|
84
|
-
};
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const setupLogging = (args: Params = {}): AwaitableLogger => {
|
|
88
|
-
const transportTargets = [
|
|
89
|
-
{
|
|
90
|
-
target: KnownTransports.Stdout,
|
|
91
|
-
level: "debug",
|
|
92
|
-
options: { pretty: args.pretty != false },
|
|
93
|
-
},
|
|
94
|
-
...(args.targets || []),
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
const transport = pino.transport({
|
|
98
|
-
targets: transportTargets,
|
|
99
|
-
});
|
|
5
|
+
const setupLogging = () => {
|
|
6
|
+
const consola = createConsola({ fancy: true, level: 5 });
|
|
100
7
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
) as AwaitableLogger;
|
|
105
|
-
logger.untilFinished = new Promise<void>((resolve) => {
|
|
106
|
-
transport.on("ready", resolve);
|
|
107
|
-
});
|
|
8
|
+
if (process.env.NODE_ENV === "production")
|
|
9
|
+
consola.setReporters([DatadogReporter]);
|
|
10
|
+
consola.setReporters([DiscordReporter, ...consola.options.reporters]);
|
|
108
11
|
|
|
109
|
-
|
|
110
|
-
return
|
|
12
|
+
consola.wrapConsole();
|
|
13
|
+
return consola;
|
|
111
14
|
};
|
|
112
15
|
|
|
113
|
-
export {
|
|
16
|
+
export { setupLogging };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { LogObject, LogLevel } from "consola";
|
|
2
|
+
import { format } from "../format.js";
|
|
3
|
+
|
|
4
|
+
const levelMap: Record<LogLevel, string> = {
|
|
5
|
+
0: "error",
|
|
6
|
+
1: "warn",
|
|
7
|
+
2: "info",
|
|
8
|
+
3: "info",
|
|
9
|
+
4: "debug",
|
|
10
|
+
5: "debug",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const Reporter = {
|
|
14
|
+
log: (logObj: LogObject) => {
|
|
15
|
+
const message = JSON.stringify({
|
|
16
|
+
level: levelMap[logObj.level] || "debug",
|
|
17
|
+
message: format(logObj.args),
|
|
18
|
+
});
|
|
19
|
+
process.stdout.write(`${message}\n`);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default Reporter;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { LogObject } from "consola";
|
|
2
|
+
import { format } from "../format.js";
|
|
3
|
+
import { type } from "arktype";
|
|
4
|
+
import axios from "axios";
|
|
5
|
+
import axiosRetry, { exponentialDelay } from "axios-retry";
|
|
6
|
+
|
|
7
|
+
const Discord = type({
|
|
8
|
+
discord: type("boolean").narrow((v) => v),
|
|
9
|
+
color: "string",
|
|
10
|
+
title: "string",
|
|
11
|
+
webhookUrl: "string",
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type Discord = typeof Discord.infer;
|
|
15
|
+
|
|
16
|
+
const NullDiscord = { discord: false } as const;
|
|
17
|
+
|
|
18
|
+
type NullDiscord = typeof NullDiscord;
|
|
19
|
+
|
|
20
|
+
const Reporter = {
|
|
21
|
+
log: (logObj: LogObject) => {
|
|
22
|
+
const [discord, args] = getDiscord(logObj.args);
|
|
23
|
+
if (!discord.discord) return;
|
|
24
|
+
|
|
25
|
+
sendToDiscord(format(args), discord);
|
|
26
|
+
|
|
27
|
+
// Filter Discord data before the other reporters
|
|
28
|
+
// process the message
|
|
29
|
+
logObj.args = args;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const getDiscord = (args: unknown[]): [Discord | NullDiscord, unknown[]] => {
|
|
34
|
+
for (let i = 0; i < args.length; i++) {
|
|
35
|
+
const discord = Discord(args[i]);
|
|
36
|
+
if (discord instanceof type.errors) continue;
|
|
37
|
+
|
|
38
|
+
return [discord, args.filter((_, j) => j !== i)];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return [NullDiscord, args];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const sendToDiscord = async (description: string, options: Discord) => {
|
|
45
|
+
const axiosInstance = axios.create();
|
|
46
|
+
axiosRetry(axiosInstance, {
|
|
47
|
+
retries: 3,
|
|
48
|
+
retryDelay: exponentialDelay,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
await axiosInstance.post(options.webhookUrl, {
|
|
53
|
+
embeds: [
|
|
54
|
+
{
|
|
55
|
+
title: options.title,
|
|
56
|
+
description,
|
|
57
|
+
color: options.color,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error("Unable to send message to Discord", error);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default Reporter;
|
package/tests/app.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setupLogging } from "
|
|
1
|
+
import { setupLogging } from "mynth-logger";
|
|
2
2
|
|
|
3
3
|
const run = async () => {
|
|
4
4
|
setupLogging();
|
|
@@ -59,6 +59,13 @@ const run = async () => {
|
|
|
59
59
|
console.log("This is concatenating an object", {});
|
|
60
60
|
|
|
61
61
|
console.log("This is an object with bigint", { name: "bigint", value: 100n });
|
|
62
|
+
|
|
63
|
+
console.info("Sending this message to discord", {
|
|
64
|
+
discord: true,
|
|
65
|
+
color: "2404635",
|
|
66
|
+
title: "This is a test",
|
|
67
|
+
webhookUrl: process.env["DISCORD_TEST_WEB_HOOK"],
|
|
68
|
+
});
|
|
62
69
|
};
|
|
63
70
|
|
|
64
71
|
run();
|
package/tests/index.test.ts
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
import test from "ava";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
let logger: AwaitableLogger | undefined;
|
|
5
|
-
|
|
6
|
-
const sleep = (ms: number) => {
|
|
7
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
|
-
};
|
|
2
|
+
import { setupLogging } from "mynth-logger";
|
|
9
3
|
|
|
10
4
|
test.before(() => {
|
|
11
|
-
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test.afterEach(async () => {
|
|
15
|
-
await sleep(100);
|
|
16
|
-
logger && (await logger.untilFinished);
|
|
5
|
+
setupLogging();
|
|
17
6
|
});
|
|
18
7
|
|
|
19
8
|
test.serial("logs display to terminal", (t) => {
|
package/tsconfig.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"baseUrl": "./",
|
|
3
|
+
"baseUrl": "./src",
|
|
4
4
|
"target": "es2022",
|
|
5
5
|
"module": "CommonJS",
|
|
6
6
|
"moduleResolution": "Node",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"forceConsistentCasingInFileNames": true,
|
|
11
11
|
"outDir": "./dist",
|
|
12
12
|
"declaration": true,
|
|
13
|
-
"declarationDir": "dist"
|
|
14
|
-
|
|
13
|
+
"declarationDir": "dist",
|
|
14
|
+
"paths": {
|
|
15
|
+
"mynth-logger": ["index"]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*", "tests/**/*"],
|
|
19
|
+
"exclude": ["node_modules"]
|
|
15
20
|
}
|
package/dist/src/run.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/src/run.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const index_js_1 = require("./index.js");
|
|
4
|
-
const run = (pretty = true) => {
|
|
5
|
-
(0, index_js_1.setupLogging)({ pretty });
|
|
6
|
-
console.debug("hello world");
|
|
7
|
-
};
|
|
8
|
-
run();
|
|
9
|
-
// Use `run(false)` to disable pino-pretty
|
|
10
|
-
// pino-pretty will also be disabled if it's not installed
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
const pino_abstract_transport_1 = __importDefault(require("pino-abstract-transport"));
|
|
30
|
-
const loadPretty = async () => {
|
|
31
|
-
try {
|
|
32
|
-
return await Promise.resolve().then(() => __importStar(require("pino-pretty")));
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
const isPrettyDisabled = (opts) => {
|
|
39
|
-
return opts && typeof opts === "object" && "pretty" in opts && !opts.pretty;
|
|
40
|
-
};
|
|
41
|
-
const transport = async (opts) => {
|
|
42
|
-
if (!isPrettyDisabled(opts)) {
|
|
43
|
-
const pretty = await loadPretty();
|
|
44
|
-
if (pretty)
|
|
45
|
-
return pretty.default({ colorize: true, ignore: "pid,time,hostname" });
|
|
46
|
-
}
|
|
47
|
-
return (0, pino_abstract_transport_1.default)(async (source) => {
|
|
48
|
-
for await (const log of source) {
|
|
49
|
-
const level = "level" in log ? String(log.level) : "error";
|
|
50
|
-
const msg = "msg" in log ? String(log.msg) : String(log);
|
|
51
|
-
process.stdout.write(`${JSON.stringify({ level, msg })}\n`);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
exports.default = transport;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const pino_abstract_transport_1 = __importDefault(require("pino-abstract-transport"));
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const invariant = (condition, message) => {
|
|
9
|
-
if (condition)
|
|
10
|
-
return;
|
|
11
|
-
throw new Error(message);
|
|
12
|
-
};
|
|
13
|
-
const cast = (opts) => {
|
|
14
|
-
invariant(opts && typeof opts === "object", "Discord transport options must be specified");
|
|
15
|
-
invariant("color" in opts && typeof opts.color === "string", "Color must be provided");
|
|
16
|
-
invariant("title" in opts && typeof opts.title === "string", "Title must be provided");
|
|
17
|
-
invariant("webhookUrl" in opts && typeof opts.webhookUrl === "string", "Webhook URL must be provided");
|
|
18
|
-
return {
|
|
19
|
-
color: opts.color,
|
|
20
|
-
title: opts.title,
|
|
21
|
-
webhookUrl: opts.webhookUrl,
|
|
22
|
-
filter: "filter" in opts ? String(opts.filter) : "",
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
const transport = async (opts) => {
|
|
26
|
-
const options = cast(opts);
|
|
27
|
-
return (0, pino_abstract_transport_1.default)(async (source) => {
|
|
28
|
-
for await (const log of source) {
|
|
29
|
-
const description = "msg" in log ? String(log.msg) : String(log);
|
|
30
|
-
if (!options.filter ||
|
|
31
|
-
(options.filter in log && log[options.filter])) {
|
|
32
|
-
await axios_1.default.post(options.webhookUrl, {
|
|
33
|
-
embeds: [
|
|
34
|
-
{
|
|
35
|
-
title: options.title,
|
|
36
|
-
description,
|
|
37
|
-
color: options.color,
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
};
|
|
45
|
-
exports.default = transport;
|
package/src/run.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { setupLogging } from "./index.js";
|
|
2
|
-
|
|
3
|
-
const run = (pretty: boolean = true) => {
|
|
4
|
-
setupLogging({ pretty });
|
|
5
|
-
console.debug("hello world");
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
run();
|
|
9
|
-
// Use `run(false)` to disable pino-pretty
|
|
10
|
-
// pino-pretty will also be disabled if it's not installed
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import build from "pino-abstract-transport";
|
|
2
|
-
import { DestinationStream } from "pino";
|
|
3
|
-
|
|
4
|
-
const loadPretty = async () => {
|
|
5
|
-
try {
|
|
6
|
-
return await import("pino-pretty");
|
|
7
|
-
} catch {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const isPrettyDisabled = (opts: unknown) => {
|
|
13
|
-
return opts && typeof opts === "object" && "pretty" in opts && !opts.pretty;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const transport = async (opts: unknown): Promise<DestinationStream> => {
|
|
17
|
-
if (!isPrettyDisabled(opts)) {
|
|
18
|
-
const pretty = await loadPretty();
|
|
19
|
-
if (pretty)
|
|
20
|
-
return pretty.default({ colorize: true, ignore: "pid,time,hostname" });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return build(async (source: AsyncIterable<object>) => {
|
|
24
|
-
for await (const log of source) {
|
|
25
|
-
const level = "level" in log ? String(log.level) : "error";
|
|
26
|
-
const msg = "msg" in log ? String(log.msg) : String(log);
|
|
27
|
-
|
|
28
|
-
process.stdout.write(`${JSON.stringify({ level, msg })}\n`);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default transport;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import build from "pino-abstract-transport";
|
|
2
|
-
import axios from "axios";
|
|
3
|
-
import { DestinationStream } from "pino";
|
|
4
|
-
|
|
5
|
-
const invariant: (
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
-
condition: any,
|
|
8
|
-
message: string
|
|
9
|
-
) => asserts condition = (condition, message) => {
|
|
10
|
-
if (condition) return;
|
|
11
|
-
throw new Error(message);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const cast = (opts: unknown) => {
|
|
15
|
-
invariant(
|
|
16
|
-
opts && typeof opts === "object",
|
|
17
|
-
"Discord transport options must be specified"
|
|
18
|
-
);
|
|
19
|
-
invariant(
|
|
20
|
-
"color" in opts && typeof opts.color === "string",
|
|
21
|
-
"Color must be provided"
|
|
22
|
-
);
|
|
23
|
-
invariant(
|
|
24
|
-
"title" in opts && typeof opts.title === "string",
|
|
25
|
-
"Title must be provided"
|
|
26
|
-
);
|
|
27
|
-
invariant(
|
|
28
|
-
"webhookUrl" in opts && typeof opts.webhookUrl === "string",
|
|
29
|
-
"Webhook URL must be provided"
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
color: opts.color,
|
|
34
|
-
title: opts.title,
|
|
35
|
-
webhookUrl: opts.webhookUrl,
|
|
36
|
-
filter: "filter" in opts ? String(opts.filter) : "",
|
|
37
|
-
};
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const transport = async (opts: unknown): Promise<DestinationStream> => {
|
|
41
|
-
const options = cast(opts);
|
|
42
|
-
|
|
43
|
-
return build(async (source: AsyncIterable<object>) => {
|
|
44
|
-
for await (const log of source) {
|
|
45
|
-
const description = "msg" in log ? String(log.msg) : String(log);
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
!options.filter ||
|
|
49
|
-
(options.filter in log && log[options.filter as keyof typeof log])
|
|
50
|
-
) {
|
|
51
|
-
await axios.post(options.webhookUrl, {
|
|
52
|
-
embeds: [
|
|
53
|
-
{
|
|
54
|
-
title: options.title,
|
|
55
|
-
description,
|
|
56
|
-
color: options.color,
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export default transport;
|