@evo/gotcha-log
Advanced tools
Comparing version
@@ -1,5 +0,5 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
@@ -9,35 +9,40 @@ exports.initConfig = initConfig; | ||
var _utils = require('./utils'); | ||
var _utils = require("./utils"); | ||
function Config(site, host, txid) { | ||
if (!site) (0, _utils.logWarn)('missing site for gotcha'); | ||
if (!host) (0, _utils.logWarn)('missing host for gotcha'); | ||
this.getSite = function () { | ||
return site; | ||
}; | ||
this.getHost = function () { | ||
return host; | ||
}; | ||
this.getTXID = function () { | ||
return txid; | ||
}; | ||
if (!site) (0, _utils.logWarn)('missing site for gotcha'); | ||
if (!host) (0, _utils.logWarn)('missing host for gotcha'); | ||
this.getSite = function () { | ||
return site; | ||
}; | ||
this.getHost = function () { | ||
return host; | ||
}; | ||
this.getTXID = function () { | ||
return txid; | ||
}; | ||
} | ||
var config = void 0; | ||
var config; | ||
function hasGlobalGotcha() { | ||
return window && window._GOTCHA_IS_HERE; | ||
return window && window._GOTCHA_IS_HERE; | ||
} | ||
function initConfig(site, host, txid) { | ||
config = new Config(site, host, txid); | ||
config = new Config(site, host, txid); | ||
} | ||
function getConfig() { | ||
if (config) return config; | ||
if (hasGlobalGotcha()) { | ||
config = new Config(window.GOTCHA_SITE, window.GOTCHA_HOST, window.GOTCHA_TXID); | ||
return config; | ||
} | ||
throw new Error('[GOTCHA-LOG] You should call initGotchaLogger before log'); | ||
if (config) return config; | ||
if (hasGlobalGotcha()) { | ||
config = new Config(window.GOTCHA_SITE, window.GOTCHA_HOST, window.GOTCHA_TXID); | ||
return config; | ||
} | ||
throw new Error('[GOTCHA-LOG] You should call initGotchaLogger before log'); | ||
} |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -6,5 +6,10 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
var ERROR_TYPE = exports.ERROR_TYPE = 'error'; | ||
var LOG_TYPE = exports.LOG_TYPE = 'log'; | ||
var LOG_EVENT = exports.LOG_EVENT = 'gotchaLog'; | ||
var ERR_EVENT = exports.ERR_EVENT = 'gotchaErr'; | ||
exports.ERR_EVENT = exports.LOG_EVENT = exports.LOG_TYPE = exports.ERROR_TYPE = void 0; | ||
var ERROR_TYPE = 'error'; | ||
exports.ERROR_TYPE = ERROR_TYPE; | ||
var LOG_TYPE = 'log'; | ||
exports.LOG_TYPE = LOG_TYPE; | ||
var LOG_EVENT = 'gotchaLog'; | ||
exports.LOG_EVENT = LOG_EVENT; | ||
var ERR_EVENT = 'gotchaErr'; | ||
exports.ERR_EVENT = ERR_EVENT; |
@@ -1,82 +0,104 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.isObject = isObject; | ||
exports.formatExtra = exports.extractKeysValues = exports.addTypeToKey = void 0; | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } | ||
exports.isObject = isObject; | ||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } | ||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } | ||
function _iterableToArrayLimit(arr, i) { var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } | ||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } | ||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function isObject(obj) { | ||
try { | ||
return Boolean(Object.keys(obj).length && obj.constructor === Object); | ||
} catch (err) { | ||
return false; | ||
} | ||
try { | ||
return Boolean(Object.keys(obj).length && obj.constructor === Object); | ||
} catch (err) { | ||
return false; | ||
} | ||
} | ||
var TYPE_MAP = { | ||
number: 'int', | ||
string: 'str', | ||
boolean: 'bool' | ||
number: 'int', | ||
string: 'str', | ||
"boolean": 'bool' | ||
}; | ||
var addTypeToKey = exports.addTypeToKey = function addTypeToKey(key, value) { | ||
var valueType = typeof value === 'undefined' ? 'undefined' : _typeof(value); | ||
if (TYPE_MAP[valueType]) { | ||
return key + '_' + TYPE_MAP[valueType]; | ||
} | ||
return ''; | ||
var addTypeToKey = function addTypeToKey(key, value) { | ||
var valueType = _typeof(value); | ||
if (TYPE_MAP[valueType]) { | ||
return "".concat(key, "_").concat(TYPE_MAP[valueType]); | ||
} | ||
return ''; | ||
}; | ||
var extractKeysValues = exports.extractKeysValues = function extractKeysValues(obj) { | ||
var parentKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; | ||
exports.addTypeToKey = addTypeToKey; | ||
return Object.keys(obj).reduce(function (result, key) { | ||
var value = obj[key]; | ||
var pKey = parentKey ? parentKey + '_' + key : key; | ||
if (isObject(value)) { | ||
return result.concat(extractKeysValues(value, pKey)); | ||
} | ||
return result.concat([[pKey, value]]); | ||
}, []); | ||
var extractKeysValues = function extractKeysValues(obj) { | ||
var parentKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; | ||
return Object.keys(obj).reduce(function (result, key) { | ||
var value = obj[key]; | ||
var pKey = parentKey ? "".concat(parentKey, "_").concat(key) : key; | ||
if (isObject(value)) { | ||
return result.concat(extractKeysValues(value, pKey)); | ||
} | ||
return result.concat([[pKey, value]]); | ||
}, []); | ||
}; | ||
exports.extractKeysValues = extractKeysValues; | ||
function getArrayTypeMap(arr, key) { | ||
var arrTypeKeys = {}; | ||
arr.forEach(function (v) { | ||
var arrKey = addTypeToKey(key, v); | ||
if (!arrKey) return; | ||
if (!arrTypeKeys[arrKey]) { | ||
arrTypeKeys[arrKey] = []; | ||
} | ||
arrTypeKeys[arrKey].push(v); | ||
}); | ||
return arrTypeKeys; | ||
var arrTypeKeys = {}; | ||
arr.forEach(function (v) { | ||
var arrKey = addTypeToKey(key, v); | ||
if (!arrKey) return; | ||
if (!arrTypeKeys[arrKey]) { | ||
arrTypeKeys[arrKey] = []; | ||
} | ||
arrTypeKeys[arrKey].push(v); | ||
}); | ||
return arrTypeKeys; | ||
} | ||
var formatExtra = exports.formatExtra = function formatExtra(extra) { | ||
var result = {}; | ||
var formatExtra = function formatExtra(extra) { | ||
var result = {}; | ||
extractKeysValues(extra).forEach(function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2), | ||
key = _ref2[0], | ||
value = _ref2[1]; | ||
extractKeysValues(extra).forEach(function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2), | ||
key = _ref2[0], | ||
value = _ref2[1]; | ||
if (Array.isArray(value)) { | ||
var arrayTypeMap = getArrayTypeMap(value, key); | ||
Object.keys(arrayTypeMap).forEach(function (k) { | ||
result[k] = arrayTypeMap[k]; | ||
}); | ||
return; | ||
} | ||
if (Array.isArray(value)) { | ||
var arrayTypeMap = getArrayTypeMap(value, key); | ||
Object.keys(arrayTypeMap).forEach(function (k) { | ||
result[k] = arrayTypeMap[k]; | ||
}); | ||
return; | ||
} | ||
var formattedKey = addTypeToKey(key, value); | ||
if (formattedKey) { | ||
result[formattedKey] = value; | ||
} | ||
}); | ||
var formattedKey = addTypeToKey(key, value); | ||
return result; | ||
}; | ||
if (formattedKey) { | ||
result[formattedKey] = value; | ||
} | ||
}); | ||
return result; | ||
}; | ||
exports.formatExtra = formatExtra; |
@@ -1,5 +0,5 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
@@ -10,26 +10,28 @@ exports.log = log; | ||
var _formatExtra = require('./formatExtra'); | ||
var _formatExtra = require("./formatExtra"); | ||
var _config = require('./config'); | ||
var _config = require("./config"); | ||
var _transport = require('./transport'); | ||
var _transport = require("./transport"); | ||
function log(msg, extra) { | ||
if (extra) { | ||
extra = (0, _formatExtra.formatExtra)(extra); | ||
} | ||
var conf = (0, _config.getConfig)(); | ||
(0, _transport.postLog)(msg, extra, conf); | ||
if (extra) { | ||
extra = (0, _formatExtra.formatExtra)(extra); | ||
} | ||
var conf = (0, _config.getConfig)(); | ||
(0, _transport.postLog)(msg, extra, conf); | ||
} | ||
function error(msg, extra) { | ||
if (extra) { | ||
extra = (0, _formatExtra.formatExtra)(extra); | ||
} | ||
var conf = (0, _config.getConfig)(); | ||
(0, _transport.postErr)(msg, extra, conf); | ||
if (extra) { | ||
extra = (0, _formatExtra.formatExtra)(extra); | ||
} | ||
var conf = (0, _config.getConfig)(); | ||
(0, _transport.postErr)(msg, extra, conf); | ||
} | ||
function initGotchaLogger(site, host, txid) { | ||
(0, _config.initConfig)(site, host, txid); | ||
(0, _config.initConfig)(site, host, txid); | ||
} |
@@ -1,63 +0,78 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.xhrPOST = xhrPOST; | ||
exports.postLog = postLog; | ||
exports.postErr = postErr; | ||
var _utils = require('./utils'); | ||
var _utils = require("./utils"); | ||
var _defs = require('./defs'); | ||
var _defs = require("./defs"); | ||
function buildMessage(_ref) { | ||
var site = _ref.site, | ||
message = _ref.message, | ||
type = _ref.type, | ||
extra = _ref.extra; | ||
var screen = window.screen; | ||
return { | ||
message: message, | ||
filename: 'default', | ||
line: 0, | ||
column: 0, | ||
screenWidth: screen && screen.availWidth, | ||
screenHeight: screen && screen.availHeight, | ||
currentUrl: window.location.href, | ||
site: site, | ||
type: type, | ||
ctx: extra | ||
}; | ||
var site = _ref.site, | ||
message = _ref.message, | ||
type = _ref.type, | ||
extra = _ref.extra; | ||
var _window = window, | ||
screen = _window.screen; | ||
return { | ||
message: message, | ||
filename: 'default', | ||
line: 0, | ||
column: 0, | ||
screenWidth: screen && screen.availWidth, | ||
screenHeight: screen && screen.availHeight, | ||
currentUrl: window.location.href, | ||
site: site, | ||
type: type, | ||
ctx: extra | ||
}; | ||
} | ||
function xhrPOST(endpoint, jsonPayload, txid) { | ||
var payload = JSON.stringify(jsonPayload); | ||
try { | ||
var xhr = new window.XMLHttpRequest(); | ||
if (process.env.NODE_ENV === 'dev') { | ||
xhr.onerror = function () { | ||
(0, _utils.logWarn)('POST request failed'); | ||
}; | ||
} | ||
var payload = JSON.stringify(jsonPayload); | ||
xhr.open('POST', endpoint, true); | ||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); | ||
if (txid) { | ||
xhr.setRequestHeader('X-Request-ID', txid); | ||
} | ||
xhr.send(payload); | ||
} catch (e) { | ||
(0, _utils.logWarn)('Error sending POST xhr'); | ||
try { | ||
var xhr = new window.XMLHttpRequest(); | ||
if (process.env.NODE_ENV === 'dev') { | ||
xhr.onerror = function () { | ||
(0, _utils.logWarn)('POST request failed'); | ||
}; | ||
} | ||
xhr.open('POST', endpoint, true); | ||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); | ||
if (txid) { | ||
xhr.setRequestHeader('X-Request-ID', txid); | ||
} | ||
xhr.send(payload); | ||
} catch (e) { | ||
(0, _utils.logWarn)('Error sending POST xhr'); | ||
} | ||
} | ||
function postLog(message, extra, config) { | ||
var payload = buildMessage({ message: message, site: config.getSite(), type: _defs.LOG_TYPE, extra: extra }); | ||
xhrPOST(config.getHost(), payload, config.getTXID()); | ||
var payload = buildMessage({ | ||
message: message, | ||
site: config.getSite(), | ||
type: _defs.LOG_TYPE, | ||
extra: extra | ||
}); | ||
xhrPOST(config.getHost(), payload, config.getTXID()); | ||
} | ||
function postErr(message, extra, config) { | ||
var payload = buildMessage({ message: message, site: config.getSite(), type: _defs.ERROR_TYPE, extra: extra }); | ||
xhrPOST(config.getHost(), payload, config.getTXID()); | ||
var payload = buildMessage({ | ||
message: message, | ||
site: config.getSite(), | ||
type: _defs.ERROR_TYPE, | ||
extra: extra | ||
}); | ||
xhrPOST(config.getHost(), payload, config.getTXID()); | ||
} |
@@ -1,18 +0,19 @@ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.logWarn = logWarn; | ||
exports.logInfo = logInfo; | ||
function logWarn(msg) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
console.warn && console.warn('[GOTCHA-LOG] ' + msg); | ||
} | ||
if (process.env.NODE_ENV !== 'production') { | ||
console.warn && console.warn("[GOTCHA-LOG] ".concat(msg)); | ||
} | ||
} | ||
function logInfo(msg) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
console.log && console.log('[GOTCHA-LOG] ' + msg); | ||
} | ||
if (process.env.NODE_ENV !== 'production') { | ||
console.log && console.log("[GOTCHA-LOG] ".concat(msg)); | ||
} | ||
} |
{ | ||
"name": "@evo/gotcha-log", | ||
"version": "1.4.0", | ||
"version": "1.5.1", | ||
"description": "", | ||
@@ -8,5 +8,8 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"prepublish": "vagga build", | ||
"preversion": "vagga lint && vagga test" | ||
"test": "NODE_ENV=test mocha tests/**/", | ||
"prepublishOnly": "npm run build", | ||
"lint": "eslint --fix src tests", | ||
"preversion": "npm run lint && npm run test", | ||
"prepare": "husky install", | ||
"build": "babel src -d dist" | ||
}, | ||
@@ -20,17 +23,19 @@ "repository": { | ||
"devDependencies": { | ||
"@evo/eslint-config-uaprom": "^2.0.0", | ||
"babel-cli": "^6.24.1", | ||
"babel-core": "^6.24.1", | ||
"babel-preset-env": "^1.3.3", | ||
"babel-register": "6.24.1", | ||
"chai": "^3.5.0", | ||
"eslint": "^3.19.0", | ||
"eslint-plugin-import": "^2.2.0", | ||
"eslint-plugin-jsx-a11y": "^4.0.0", | ||
"eslint-plugin-react": "^6.10.3", | ||
"jsdom": "9.12.0", | ||
"jsdom-global": "2.1.1", | ||
"mocha": "^3.2.0", | ||
"sinon": "4.1.2" | ||
"@babel/cli": "^7.13.16", | ||
"@babel/core": "^7.13.16", | ||
"@babel/preset-env": "^7.13.15", | ||
"@babel/register": "^7.13.16", | ||
"@evo/eslint-config-uaprom": "^6.0.0", | ||
"chai": "^4.3.4", | ||
"eslint": "^7.25.0", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-jsx-a11y": "^6.4.1", | ||
"eslint-plugin-react": "^7.23.2", | ||
"eslint-scope": "^5.1.1", | ||
"husky": "^6.0.0", | ||
"jsdom": "16.5.3", | ||
"jsdom-global": "3.0.2", | ||
"mocha": "^8.3.2", | ||
"sinon": "10.0.0" | ||
} | ||
} |
@@ -72,1 +72,71 @@ ## gotcha-log | ||
## @evo/gotcha-log/src/metrics | ||
There was a need to transfer the numerical data of event metrics to the backend from the frontend to save them in the Prometheus. | ||
For this purpose a sub-module of metrics was created. | ||
The design of the module has been inspired by the package [prom-client](https://github.com/siimon/prom-client) | ||
All metrics are uploaded to backend using [window.sendBeacon()](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon). If browser does not support this API, it will fallbacks to `XMLHttpRequest()` | ||
> NOTE: | ||
> | ||
> Before add metrics to your project, you must add your project config to [gotcha-server](https://gitlab.evo.dev/gotcha/gotcha-server#write-prometheus-metrics-from-frontend) | ||
### Usage: | ||
Common usage: | ||
```js | ||
// at start of your application, initialize metrics module | ||
import {initGotchaMetrics, metric} from '@evo/gotcha-log/src/metrics'; | ||
initGotchaMetrics({ | ||
project: <project-id>, // do not forget, to add your project to gotcha-server config | ||
host: <gotcha-backend-host> | ||
}); | ||
// create metric: metric(<name>, [<value>], [<labels>]) | ||
metric( | ||
'pageview', // metric name | ||
1, // value | ||
{page:'koshyk'} // labels | ||
) | ||
``` | ||
Also you can create metric instance manually: | ||
```js | ||
import { Counter } from '@evo/gotcha-log/src/metrics'; | ||
const reduxActionsErrorsCounter=new Counter({ | ||
name: 'redux-errors' | ||
}); | ||
reduxActionsErrorsCounter.inc(123, {action: 'createOrder', version: '1.2.3'}) | ||
// or | ||
const incCounter=reduxActionsErrorsCounter.getStandaloneInc( {action: 'createOrder', version: '1.2.3'}) | ||
incCounter(3) // which is equivalent to reduxActionsErrorsCounter.inc(3, {action: 'createOrder', version: '1.2.3'}) | ||
``` | ||
All metrics will upload to backend automatically each 5s. You can stop uploading by calling: | ||
```js | ||
import { stopUploadByInterval } from '@evo/gotcha-log/src/metrics'; | ||
stopUploadByInterval() | ||
``` | ||
And resume it by calling: | ||
```js | ||
import { startUploadByInterval } from '@evo/gotcha-log/src/metrics'; | ||
startUploadByInterval() | ||
``` | ||
> NOTE: | ||
> | ||
> `startUploadByInterval` and `stopUploadByInterval` also add `beforeonload` event listener, | ||
> which will upload the last metrics to backend, before user leaves current page | ||
Send metrics to backend immediately: | ||
```js | ||
import { immediatelyUploadMetrics } from '@evo/gotcha-log/src/metrics'; | ||
immediatelyUploadMetrics() | ||
``` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
17
70%1
-50%141
95.83%34960
-82.83%16
14.29%719
-87.6%2
100%