UNPKG

@procube/pino-transmit-http

Version:

A pino browser transmit that send log statements over HTTP

124 lines 4.17 kB
import throttle from "lodash.throttle"; import debounce from "lodash.debounce"; import { encode } from "@msgpack/msgpack"; import { gzip } from "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; } export default 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) : encode(collection); const gzippedBody = 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) => encode(item))); collection = []; const gzippedBody = gzip(collectionData); window.navigator.sendBeacon(opts.url, gzippedBody); } let send; if (opts.debounce !== null && opts.debounce !== undefined) { send = debounce(rawSend, opts.debounce); } else if (opts.throttle !== null && opts.throttle !== undefined) { send = throttle(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 = throttle(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)}`); } }, }; } //# sourceMappingURL=index.js.map