Skip to content
This repository has been archived by the owner on Jun 13, 2023. It is now read-only.

Commit

Permalink
feat(web): detect redirection (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
NavaBeginsky authored Jul 16, 2021
1 parent d06a451 commit eb916eb
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 83 deletions.
3 changes: 0 additions & 3 deletions packages/react/src/index.ts

This file was deleted.

86 changes: 31 additions & 55 deletions packages/react/src/instrumentation/redirectInstrumentation.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,38 @@
/* eslint max-len: ["error", { "ignoreComments": true }] */

/* eslint no-param-reassign: ["error", { "props": true, "ignorePropertyModificationsFor": ["parentSpan"] }] */
const EpsagonUtils = require('@epsagon/web').EpsagonUtils;

function addEpsSpanAttrs(span, parentSpan) {
if(parentSpan.identifyFields){
const { userId, userName, userEmail, companyId, companyName } = parentSpan.identifyFields;
if (userId) span.setAttribute('user.id', parentSpan.identifyFields.userId);
if (userName) span.setAttribute('user.name', parentSpan.identifyFields.name);
if (userEmail) span.setAttribute('user.email', parentSpan.identifyFields.email);
if (companyId) span.setAttribute('company.id', parentSpan.identifyFields.companyId);
if (companyName) span.setAttribute('company.name', parentSpan.identifyFields.companyName);
}
if(parentSpan.tags){
for(let key in parentSpan.tags){
span.setAttribute(key, parentSpan.tags[key]);
}
}
}


function ReactRedirectInstrumentation(history, tracer, parentSpan) {
const getInitPathName = () => {
if (history && history.location) {
return history.location.pathname;
}

return undefined;
};

let span;
const startSpan = (originPath) => {
span = tracer.startSpan('route_change', {
attributes: {
operation: 'route_change',
type: 'browser',
previousPage: originPath,
},

const startSpan = (originPath, newPath) => {
return tracer.startSpan('route_change', {
attributes: {
operation: 'route_change',
type: 'browser',
previousPage: originPath,
path: newPath,
},
});
};

history.listen((location, action) => {
let currentPath = `${location.pathname}${window.location.hash}`
if (action && (action.toLowerCase() === 'push' || action.toLowerCase() === 'pop') && (parentSpan.path != currentPath)) {
let span = startSpan(parentSpan.path, location.pathname)
parentSpan.currentSpan = span;
if(location.hash && location.hash.length){span.setAttribute('hash', location.hash)};
if(location.search && location.search.length){span.setAttribute('search', location.search)};
if(location.state && location.state.length){span.setAttribute('history.state', location.state)};
span.setAttribute('action', action);
span.setStatus({ code: 0 });
EpsagonUtils.addEpsSpanAttrs(span, parentSpan);
span.end();
parentSpan.path = currentPath;
}

});
};

const initPathName = getInitPathName();
startSpan(initPathName);

history.listen((location, action) => {
if (action && (action.toLowerCase() === 'push' || action.toLowerCase() === 'pop')) {
if (span) {
parentSpan.currentSpan = span;
span.setAttribute('path', location.pathname);
span.setAttribute('hash', location.hash);
span.setAttribute('search', location.search);
span.setAttribute('history.state', location.state);
span.setAttribute('action', action);
span.setStatus({ code: 0 });
addEpsSpanAttrs(span, parentSpan);
span.end();
startSpan(location.pathname);
}
}
});
}

}

export default ReactRedirectInstrumentation;
6 changes: 3 additions & 3 deletions packages/react/src/web-tracer.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import ReactRedirectInstrumentation from './instrumentation/redirectInstrumentation';

const Epsagon = require('@epsagon/web');
export {identify, tag} from '@epsagon/web'
const webInit = require('@epsagon/web').init;
export {identify, tag} from '@epsagon/web';

// to pass into the init - app_name: str, token: str
function init(configData) {
const { tracer, epsSpan } = Epsagon.init(configData);
const { tracer, epsSpan } = webInit(configData);

if (configData.history) {
ReactRedirectInstrumentation(configData.history, tracer, epsSpan);
Expand Down
2 changes: 1 addition & 1 deletion packages/react/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"include": [
"src/**/*"
"src/*"
],
"compilerOptions": {
"allowJs": true,
Expand Down
22 changes: 3 additions & 19 deletions packages/web/src/instrumentation/documentLoadInstrumentation.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
import EpsagonUtils from '../utils';

const api = require('@opentelemetry/api');

Expand All @@ -8,22 +9,6 @@ class EpsagonDocumentLoadInstrumentation extends DocumentLoadInstrumentation {
this.epsParentSpan = parentSpan;
}

addEpsSpanAttrs(span) {
if(this.epsParentSpan.identifyFields){
const { userId, userName, userEmail, companyId, companyName } = this.epsParentSpan.identifyFields;
if (userId) span.setAttribute('user.id', userId);
if (userName) span.setAttribute('user.name', userName);
if (userEmail) span.setAttribute('user.email', userEmail);
if (companyId) span.setAttribute('company.id', companyId);
if (companyName) span.setAttribute('company.name', companyName);
}
if(this.epsParentSpan.tags){
for(let key in this.epsParentSpan.tags){
span.setAttribute(key, this.epsParentSpan.tags[key])
}
}
}

_onDocumentLoaded(event = false) {
// Timeout is needed as load event doesn't have yet the performance metrics for loadEnd.
// Support for event "loadend" is very limited and cannot be used
Expand All @@ -45,8 +30,7 @@ class EpsagonDocumentLoadInstrumentation extends DocumentLoadInstrumentation {
if (initialSpan && !this.epsParentSpan.currentSpan) {
this.epsParentSpan.currentSpan = initialSpan;
}
console.log(initialSpan)
this.addEpsSpanAttrs(initialSpan);
EpsagonUtils.addEpsSpanAttrs(initialSpan, this.epsParentSpan);
return initialSpan;
}

Expand Down Expand Up @@ -78,7 +62,7 @@ class EpsagonDocumentLoadInstrumentation extends DocumentLoadInstrumentation {
// "stack": stack
},
}, this.epsParentSpan.currentSpan ? api.trace.setSpan(api.context.active(), this.epsParentSpan.currentSpan) : undefined);
this.addEpsSpanAttrs(span);
EpsagonUtils.addEpsSpanAttrs(span, this.epsParentSpan);
span.setStatus({ code: 2 });
span.end();
}
Expand Down
38 changes: 38 additions & 0 deletions packages/web/src/instrumentation/redirectInstrumentation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import EpsagonUtils from '../utils';

class EpsagonRedirectInstrumentation{

constructor(tracer, parentSpan, resetTimer) {
this.parentSpan = parentSpan;
this.parentSpan.path = `${window.location.pathname}${window.location.hash}`;
this.tracer = tracer;
setInterval(()=>{
let currentPath = `${window.location.pathname}${window.location.hash}`;
if (this.parentSpan.path && currentPath != parentSpan.path){
this.createRouteChangeSpan(this.parentSpan.path, currentPath);
this.parentSpan.path = currentPath;
}
}, resetTimer)
}

createRouteChangeSpan = (oldPath, newPath) => {
let span = this.tracer.startSpan('route_change', {
attributes: {
"operation": "route_change",
"type": "browser",
"previousPage": oldPath,
"path": newPath,
"http.url": window.location.href
}
});
this.parentSpan.currentSpan = span;
if(window.location.hash){
span.setAttribute('hash', window.location.hash);
}
EpsagonUtils.addEpsSpanAttrs(span, this.parentSpan);
span.setStatus({ code: 0 });
span.end();
}
}

export default EpsagonRedirectInstrumentation;
17 changes: 17 additions & 0 deletions packages/web/src/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@

class EpsagonUtils {

static addEpsSpanAttrs(span, parentSpan) {
if(parentSpan.identifyFields){
const { userId, userName, userEmail, companyId, companyName } = parentSpan.identifyFields;
if (userId) span.setAttribute('user.id', parentSpan.identifyFields.userId);
if (userName) span.setAttribute('user.name', parentSpan.identifyFields.name);
if (userEmail) span.setAttribute('user.email', parentSpan.identifyFields.email);
if (companyId) span.setAttribute('company.id', parentSpan.identifyFields.companyId);
if (companyName) span.setAttribute('company.name', parentSpan.identifyFields.companyName);
}
if(parentSpan.tags){
for(let key in parentSpan.tags){
span.setAttribute(key, parentSpan.tags[key]);
}
}
}

static parseURL(httpUrl, span, spanAttributes, attributesLength, metadataOnly) {
if (httpUrl.indexOf('?') < 0 && httpUrl.indexOf(';') < 0) {
const path = httpUrl.substring(httpUrl.indexOf(span.name) + span.name.length);
Expand Down
8 changes: 6 additions & 2 deletions packages/web/src/web-tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import EpsagonFetchInstrumentation from './instrumentation/fetchInstrumentation'
import EpsagonXMLHttpRequestInstrumentation from './instrumentation/xmlHttpInstrumentation';
import EpsagonDocumentLoadInstrumentation from './instrumentation/documentLoadInstrumentation'
import EpsagonExporter from './exporter';
import EpsagonUtils from './utils';
import EpsagonRedirectInstrumentation from './instrumentation/redirectInstrumentation';
const {CompositePropagator, HttpTraceContextPropagator} = require("@opentelemetry/core")
const parser = require('ua-parser-js');
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
Expand Down Expand Up @@ -141,8 +143,10 @@ function init (configData) {
],
});

const resetTimer = 3000;
new EpsagonRedirectInstrumentation(tracer, epsSpan, resetTimer);

return { tracer, epsSpan };
}


export { init, identify, tag }
export { init, identify, tag, EpsagonUtils }

0 comments on commit eb916eb

Please sign in to comment.