Monitoring & Analytics - Tag Errors that affect Users (and ignore the million others)
Customer
SPB Insurance
Problem
Chat sessions failed at times and no one new about it.

Solution
Germain has the ability to detect in real-time, the errors that affect users, and ignore the ones that don’t.
Errors that are considered critical, can be tagged, analyzed at scale and alert can be sent whenever one occurs, without getting spammed by minor/insignificant errors.
Each User Error can be “replayed” so it is easy to understand what the user did BEFORE experiencing it.
Automatic analysis of the Error is performed and available on the RCA dashboard, with information like stack traces, etc

Configure
Germain Workspace > Left Menu > Analytics > UX Monitoring Profiles > Init Script

var settings = germainApm.getDefaultSettings(loaderArgs, agentConfig);
settings.plugins.feedback.enabled = false;
//settings.constants.logLevel = 'TRACE';
settings.constants.logLevelToEmitAsFacts = 'WARN';
settings.application.metadataProviders['user.name'] = function (window) {
return new germainApm.native.Promise(function (resolve) {
germainApm.utils.waitForElements(window, '.user-info .d-flex', function (elements) {
var el = elements[0];
if (el && el.innerText) {
resolve(el.innerText.replace(/\s\s+/g, ' '));
}
else {
resolve(undefined);
}
}, undefined, 10, 1000);
});
};
settings.plugins.pageLoad.factProcessor = function (userClick, events) {
for (var i = 0; i < events.length; i++) {
if (events[i].event.type === 'document ready') {
var page = events[i].page;
if (page && page.title)
userClick.name = 'Navigation ' + page.title;
}
}
};
settings.plugins.network.eventProcessor = function (event) {
var response = event.response;
try {
if (event.status === 0 || event.status >= 400) {
if (event.url && event.url.pathname) {
var pathname_1 = event.url.pathname;
if (pathname_1 && pathname_1 !== '/v1/events' && pathname_1 !== '/server/cometd') {
if (pathname_1.match('/genesys/2/chat/GWE.*/refresh')) {
event.businessObject = 'Chat Refresh Error';
}
else if (~pathname_1.indexOf('/api/contract/getProductOffer')) {
event.businessObject = 'Product Offer Error';
}
else if (pathname_1.match('/api/contract/subscriptions/.*/verify-otp') ||
~pathname_1.indexOf('/api/contract/findSubscriptionInfobySubscriptionNumber') ||
~pathname_1.indexOf('/api/contract/findSubscriptionsInfo') ||
~pathname_1.indexOf('/api/logistical/generate_bon_transport_byClaimNumber/SV') ||
~pathname_1.indexOf('/api/logistical/generate_bon_transport/CRDN/FIND') ||
~pathname_1.indexOf('/api/logistical/generate_bon_transport/TS/FIND') ||
~pathname_1.indexOf('/api/contact/createContact') ||
~pathname_1.indexOf('/api/claims/getclaimbyNumber')) {
event.businessObject = 'Error';
if (response) {
try {
var object = JSON.parse(response);
if (object) {
if (object.type)
event.businessObject = object.type;
if (object.message)
event.businessObject = event.businessObject + ":" + object.message;
if (event.businessObject)
event.businessObject = event.businessObject.substring(0, 50).trim();
}
}
catch (e) { }
}
}
}
}
}
}
catch (e) { }
};
settings.plugins.pageLoad.factProcessor = function (userClick, events) {
for (var i = 0; i < events.length; i++) {
var event_1 = events[i].event;
if (event_1.type === 'request') {
if (event_1.success !== undefined)
userClick.success = event_1.success;
}
}
};
settings.plugins.click.factProcessor = function (fact, event, fireEvent, settings) {
try {
var target = event.target;
if (target instanceof HTMLElement) {
if (fact.displayedName === 'Résilier mon assurance' || fact.displayedName === 'Déclarer un sinistre' || fact.displayedName === 'Suivre mes sinistres') {
var container_1 = target.closest('.contract-info-row');
if (container_1) {
var adhesionContainer = container_1.querySelector('p.text-gray');
if (adhesionContainer) {
var content = adhesionContainer.innerText;
if (content && ~content.indexOf("Numéro d'adhésion")) {
// set n. adhesion
fact.businessObject = content.replace("Numéro d'adhésion :", '').trim();
}
}
}
}
// extract username
var container = document.querySelector('.user-info .d-flex');
if (container) {
var content = container.innerText;
if (content) {
content = content.replace(/\s\s+/g, ' ');
germainApm.rootWindow && germainApm.rootWindow.submitData({ time: Date.now(), type: 'assign metadata', fieldPath: 'user.name', value: content });
}
}
}
}
catch (e) { }
};