@procube/pino-transmit-http
Version:
A pino browser transmit that send log statements over HTTP
130 lines • 4.59 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_throttle_1 = __importDefault(require("lodash.throttle"));
const lodash_debounce_1 = __importDefault(require("lodash.debounce"));
const msgpack_1 = require("@msgpack/msgpack");
const pako_1 = require("pako");
const defaultOptions = {
throttle: 500,
asJson: false,
url: "/log",
};
function exception2string(e) {
if (typeof e === "string") {
return e;
}
if (e instanceof Error) {
if (e.stack) {
return e.stack;
}
return e.message;
}
if (typeof e.toString === "function") {
return e.toString();
}
return "Unknown error";
}
function concatenateUint8Arrays(arrayOfArrays) {
const totalLength = arrayOfArrays.reduce((total, arr) => total + arr.length, 0);
const result = new Uint8Array(totalLength);
let offset = 0;
for (const arr of arrayOfArrays) {
result.set(arr, offset);
offset += arr.length;
}
return result;
}
function transmitHttp(inOpts, _logger) {
const opts = { ...defaultOptions, ...inOpts };
if (typeof window === "undefined" ||
!window.navigator ||
!window.navigator.sendBeacon) {
console.error("pino-transmit-http: sendBeacon is not available.");
return undefined;
}
let collection = [];
async function rawSend() {
if (collection.length === 0) {
return;
}
try {
console.log(`sending logs: ${JSON.stringify(collection)}`);
// const collectionData = concatenateUint8Arrays(
// collection.map((item) => encode(item)),
// )
// const gzippedBody = gzip(encode(collectionData))
const body = opts.asJson ? JSON.stringify(collection) : (0, msgpack_1.encode)(collection);
const gzippedBody = (0, pako_1.gzip)(body);
collection = [];
await fetch(opts.url, {
method: "POST",
mode: "same-origin",
headers: {
"Content-Encoding": "gzip",
"Content-Type": opts.asJson ? "application/json" : "application/msgpack",
},
body: gzippedBody,
});
}
catch (e) {
console.error(`pino-transmit-http: failed to send logs: ${exception2string(e)}`);
}
}
function flush() {
if (collection.length === 0) {
return;
}
console.log(`sending logs as flush: ${JSON.stringify(collection)}`);
const collectionData = concatenateUint8Arrays(collection.map((item) => (0, msgpack_1.encode)(item)));
collection = [];
const gzippedBody = (0, pako_1.gzip)(collectionData);
window.navigator.sendBeacon(opts.url, gzippedBody);
}
let send;
if (opts.debounce !== null && opts.debounce !== undefined) {
send = (0, lodash_debounce_1.default)(rawSend, opts.debounce);
}
else if (opts.throttle !== null && opts.throttle !== undefined) {
send = (0, lodash_throttle_1.default)(rawSend, opts.throttle, {
trailing: true,
leading: false,
});
}
else {
console.warn("pino-transmit-http: Either throttle or debounce option must be passed to pino-transmit-http. Falling back to throttle by %dms", defaultOptions.throttle);
send = (0, lodash_throttle_1.default)(rawSend, defaultOptions.throttle, {
trailing: true,
leading: false,
});
}
if (typeof window !== "undefined") {
window.addEventListener("unload", function onUnload() {
send = flush;
flush(); // flush logs, no await as we are in an unload event
});
window.addEventListener("resize", function onResize() {
flush();
});
}
return {
level: opts.level,
send: function (_level, logEvent) {
try {
collection.push({
time: logEvent.ts / 1000,
level: logEvent.level.label,
...logEvent.messages[0],
});
send();
}
catch (e) {
console.error(`pino-transmit-http: Failed to transmit logs: ${exception2string(e)}`);
}
},
};
}
exports.default = transmitHttp;
//# sourceMappingURL=index.js.map