All files errorTransformer.js

100% Statements 18/18
100% Branches 4/4
100% Functions 4/4
100% Lines 18/18
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                        1x                     1x 1x   1x     6x 6x 6x 6x                                                                             7x   7x   7x 7x           7x 6x       16x     7x   7x     1x  
/**
 * The purpose of this file is to provide redux-logger middleware for error logging
 * To be applied as errorTransformer, or even actionTransformer
 * @exports redux-logger compatible error logging middleware
 * @export TraceKit, to avoid adding dependency to customer's code
 **/
 
import TraceKit_ from 'tracekit';
import 'whatwg-fetch';
 
import { sendReport, getDefaultTransport } from './transport';
 
const defaultOptions = {
	stackTraceLimit: Error.stackTraceLimit,
	linesOfContext: 15,
};
 
/**
 * @param rethrowErrorHandler - handler for rethrown errors
 * @returns Report, wrapped TraceKit.report method which no longer rethrows an error
**/
function safeWrapReport(rethrowErrorHandler) {
	function report(ex) {
		try {
			TraceKit_.fallback(ex);
		} catch (e) {
			rethrowErrorHandler(ex);
		}
	}
	report.subscribe = TraceKit_.report.subscribe;
	report.unsubscribe = TraceKit_.report.unsubscribe;
	TraceKit_.fallback = TraceKit_.report;
	return report;
}
 
/**
 * @param logServerUrl - string, fetch-compatible logger instance URL
 * @param transport - object, {
 *   send: function that accepts (payload, fetchOptions) and returns Promise, {
 *     payload: string or json object, report
 *     fetchOptions: object, options that transport.send accepts { headers, method, etc }
 *   }
 *   successHandler: function to be called on successful report,
 *                   takes response text, return is ignored,
 *   failedTryHandler: function to be called on transport.send error,
 *                     takes {
 *                       error: Error object thrown inside of transfer.send,
 *                       payload: string or json object, report before middleware was applied,
 *                       transportOpts: reference to the transport object,
 *                       attempt: # of try to send report,
 *                     }, return is ignored, by default tries to repeat request,
 *   failedReportHandler: function to be called on report general failure,
 *                        takes Error object, return is ignored,
 *   payloadMiddleware: function to be applied on payload, to attach store state, time, etc,
 *   retryCount: number # of max retries, by-default 2, set to 0 if you don't want retries
 *   retryTimeout: number in ms, by-default 60 seconds,
 * }
 * @param options - object {
 *   stackTraceLimit: number, max call stack size, applied globally on Error object,
 *   linesOfContext: number, should be odd and >=3, by-default 15,
 *   rethrowError: boolean, tells to either monkey-patch TraceKit.report method or no, false by-def,
 *   otherTraceKitOptions can be any options that TraceKit understands
 * }
 * @returns function, redux-logger compatible middleware for messages
 **/
export default function initErrorTransformer(logServerUrl, transport = {}, options = {}) {
	const {
		stackTraceLimit,
		rethrowErrorHandler,
		linesOfContext,
		...otherTraceKitOptions
	} = Object.assign(defaultOptions, options);
 
	const mergedTransport = Object.assign(getDefaultTransport(logServerUrl), transport);
 
	Error.stackTraceLimit = stackTraceLimit;
	Object.assign(TraceKit_, {
		fetchContext: !!linesOfContext,
		linesOfContext,
		...otherTraceKitOptions,
	});
 
	if (rethrowErrorHandler) {
		TraceKit_.report = safeWrapReport(rethrowErrorHandler);
	}
 
	function listener(payload) {
		return sendReport(payload, mergedTransport);
	}
 
	TraceKit_.report.subscribe(listener);
 
	return listener;
}
 
export const TraceKit = TraceKit_;