mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-12-29 00:10:54 +05:30
#315: improve logger errors serialization
This commit is contained in:
parent
25b60c1fac
commit
2b879d428e
154
src/services/logger/abbreviate.js
Normal file
154
src/services/logger/abbreviate.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
const STRING_MAX_LENGTH = 128*1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a copy of any object without non-serializable elements to make result safe for JSON.stringify().
|
||||||
|
* Guaranteed to never throw.
|
||||||
|
*
|
||||||
|
* @param {any} obj Any data structure
|
||||||
|
* @param {object} options
|
||||||
|
* @param {function} options.filter - callback that is called on every object's key with (key,value) and should return
|
||||||
|
* value to use (may return undefined to remove unwanted keys). See nodeFilter and browserFilter.
|
||||||
|
* @param {number} options.depth - maximum recursion depth. Elements deeper than that are stringified with util.inspect()
|
||||||
|
* @param {number} options.maxSize - roughly maximum allowed size of data after JSON serialisation (but it's not guaranteed
|
||||||
|
* that it won't exceed the limit)
|
||||||
|
*
|
||||||
|
* @see https://github.com/ftlabs/js-abbreviate
|
||||||
|
*/
|
||||||
|
function abbreviate(obj, options) {
|
||||||
|
if (!options) options = {};
|
||||||
|
|
||||||
|
var filter = options.filter || function(k,v){return v;};
|
||||||
|
var maxDepth = options.depth || 10;
|
||||||
|
var maxSize = options.maxSize || 1*1024*1024;
|
||||||
|
|
||||||
|
return abbreviateRecursive(undefined, obj, filter, {sizeLeft: maxSize}, maxDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
function limitStringLength(str) {
|
||||||
|
if (str.length > STRING_MAX_LENGTH) {
|
||||||
|
return str.substring(0, STRING_MAX_LENGTH/2) + ' … ' + str.substring(str.length - STRING_MAX_LENGTH/2);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function abbreviateRecursive(key, obj, filter, state, maxDepth) {
|
||||||
|
if (state.sizeLeft < 0) {
|
||||||
|
return '**skipped**';
|
||||||
|
}
|
||||||
|
|
||||||
|
state.sizeLeft -= 5; // rough approximation of JSON overhead
|
||||||
|
|
||||||
|
obj = filter(key, obj);
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch(typeof obj) {
|
||||||
|
case 'object':
|
||||||
|
if (null === obj) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxDepth < 0) {
|
||||||
|
break; // fall back to stringification
|
||||||
|
}
|
||||||
|
|
||||||
|
var newobj = Array.isArray(obj) ? [] : {};
|
||||||
|
for(var i in obj) {
|
||||||
|
newobj[i] = abbreviateRecursive(i, obj[i], filter, state, maxDepth-1);
|
||||||
|
if (state.sizeLeft < 0) break;
|
||||||
|
}
|
||||||
|
return newobj;
|
||||||
|
|
||||||
|
case 'string':
|
||||||
|
obj = limitStringLength(obj);
|
||||||
|
state.sizeLeft -= obj.length;
|
||||||
|
return obj;
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
case 'boolean':
|
||||||
|
case 'undefined':
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
} catch(e) {/* fall back to inspect*/}
|
||||||
|
|
||||||
|
try {
|
||||||
|
obj = limitStringLength('' + obj);
|
||||||
|
state.sizeLeft -= obj.length;
|
||||||
|
return obj;
|
||||||
|
} catch(e) {
|
||||||
|
return "**non-serializable**";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function commonFilter(key, val) {
|
||||||
|
if ('function' === typeof val) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val instanceof Date) {
|
||||||
|
return "**Date** " + val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val instanceof Error) {
|
||||||
|
var err = {
|
||||||
|
// These properties are implemented as magical getters and don't show up in for in
|
||||||
|
stack: val.stack,
|
||||||
|
message: val.message,
|
||||||
|
name: val.name,
|
||||||
|
};
|
||||||
|
for(var i in val) {
|
||||||
|
err[i] = val[i];
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nodeFilter(key, val) {
|
||||||
|
|
||||||
|
// domain objects are huge and have circular references
|
||||||
|
if (key === 'domain' && 'object' === typeof val && val._events) {
|
||||||
|
return "**domain ignored**";
|
||||||
|
}
|
||||||
|
if (key === 'domainEmitter') {
|
||||||
|
return "**domainEmitter ignored**";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val === global) {
|
||||||
|
return "**global**";
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonFilter(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
function browserFilter(key, val) {
|
||||||
|
if (val === window) {
|
||||||
|
return "**window**";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val === document) {
|
||||||
|
return "**document**";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val instanceof HTMLElement) {
|
||||||
|
var outerHTML = val.outerHTML;
|
||||||
|
if ('undefined' != typeof outerHTML) {
|
||||||
|
return "**HTMLElement** " + outerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonFilter(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
abbreviate,
|
||||||
|
nodeFilter,
|
||||||
|
browserFilter
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function(obj) {
|
||||||
|
return abbreviate(obj, {
|
||||||
|
filter: browserFilter
|
||||||
|
})
|
||||||
|
};
|
3
src/services/logger/index.js
Normal file
3
src/services/logger/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import logger from './logger';
|
||||||
|
|
||||||
|
export default logger;
|
@ -1,5 +1,7 @@
|
|||||||
import Raven from 'raven-js';
|
import Raven from 'raven-js';
|
||||||
|
|
||||||
|
import abbreviate from './abbreviate';
|
||||||
|
|
||||||
const isTest = process.env.__TEST__; // eslint-disable-line
|
const isTest = process.env.__TEST__; // eslint-disable-line
|
||||||
const isProduction = process.env.__PROD__; // eslint-disable-line
|
const isProduction = process.env.__PROD__; // eslint-disable-line
|
||||||
|
|
||||||
@ -72,6 +74,8 @@ const logger = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context = abbreviate(context); // prepare data for JSON.stringify
|
||||||
|
|
||||||
console[method](message, context); // eslint-disable-line
|
console[method](message, context); // eslint-disable-line
|
||||||
|
|
||||||
Raven.captureException(message, {
|
Raven.captureException(message, {
|
Loading…
Reference in New Issue
Block a user