pino
pino copied to clipboard
Recipe for email notifications?
I'm digging this library and learning more about it. Grazie for all the hard work
Surprised there is no email support yet in the Pino Ecosystem: https://github.com/pinojs/pino/blob/main/docs/ecosystem.md
So, raising two issues here:
- Lack of support for email reports (yes, I could do a PR and I am trying to fix, see next issue)
- Better TypeScript compatibility would be good. Yes, I've read https://getpino.io/#/docs/transports?id=typescript-compatibility, yet, encourage altering the API for better target support.
I'll explain ...
I've already searched in many places and haven't found a transporter yet for sending out emails at an error level. So I already tried implementing my own like:
transportTargets.push({
target: "./getLoggerEmailTransport.ts",
level: LogLevel.ERROR,
});
and
import build from "pino-abstract-transport";
import sendServerError from "../email/sendServerError";
function getLoggerEmailTransport() {
const transport = build(async function (source) {
for await (const obj of source) {
try {
sendServerError(obj);
} catch (err) {
console.log("Failed to report error", err);
}
}
});
return transport;
}
export default getLoggerEmailTransport;
... which will use the nodemailer.
This fails under ts-node or jiti with the following error message:
import build from "pino-abstract-transport";
^^^^^^
SyntaxError: Cannot use import statement outside a module
That's because of this difficult code inside pino's transport-stream:
if (toLoad.endsWith('.ts') || toLoad.endsWith('.cts')) {
// TODO: add support for the TSM modules loader ( https://github.com/lukeed/tsm ).
if (process[Symbol.for('ts-node.register.instance')]) {
realRequire('ts-node/register')
} else if (process.env && process.env.TS_NODE_DEV) {
realRequire('ts-node-dev')
}
// TODO: Support ES imports once tsc, tap & ts-node provide better compatibility guarantees.
fn = realRequire(decodeURIComponent(target))
} else {
fn = (await realImport(toLoad))
}
Yeah, there is the TODO comment to improve this. It's a bit ugly. I wonder why the target has to be a string. Can't it be a file import right away, something like this?
import getLoggerEmailTransport from "./getLoggerEmailTransport"
transportTargets.push({
target: getLoggerEmailTransport, <---- this, reuse the import, no string
level: LogLevel.ERROR,
});
Enough questions :)
Thoughts? Happy to discuss further here.