Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

injecting log to any javascript function #51

Open
wants to merge 10 commits into
base: master
from
@@ -1,14 +1,15 @@
loggly-jslogger
===============

Client-side (browser) logger to use with Loggly gen2. Check out Loggly's [Javascript logging documentation](https://www.loggly.com/docs/javascript/) to learn more.
Client-side (browser) logger to use with Loggly gen2. Check out Loggly's [Javascript logging documentation](https://www.loggly.com/docs/javascript/) to learn more.

Installation
------------


Place the following on your page, and replace the logglyKey value with the key provided by the website:
```html
<script type="text/javascript" src="//cloudfront.loggly.com/js/loggly.tracker-latest.min.js" async></script>
<script type="text/javascript" src="https://rawgit.com/aws-logger/loggly-jslogger/master/src/loggly.tracker.js" async></script>
<script>
var _LTracker = _LTracker || [];
_LTracker.push({
@@ -48,7 +49,7 @@ myBetterLogger.push({'logglyKey': 'your-customer-token' }); // push a loggly ke

Send Console Errors to Loggly
----
Keeping <strong>sendConsoleErrors</strong> value to <i>true</i> will send all the unhandled errors to the Loggly with the detailed information like error message, URL, line number and column number. This script also take cares of all the previously defined window.onerror functions.
Keeping <strong>sendConsoleErrors</strong> value to <i>true</i> will send all the unhandled errors to the Loggly with the detailed information like error message, URL, line number and column number. This script also take cares of all the previously defined window.onerror functions.

Send Tags to Loggly
----
@@ -113,3 +114,90 @@ You can build min and map file by using the command below:
npm install
grunt
```

Intercept and log any JavaScript function calls
----------

You may not like the mixing the Loggly logging codes everywhere inside your application codes. This creates undesirable dependencies on the Loggly and makes your codes ugly.

Instead you may rather prefer transparently send messages passed into the console.log, console.warn, console.info and console.error to the Loggly. Or you may even not like the console.log() functions as well. You prefer to decide which part of the code you would like to log when some issues happens on live instead of making decisition at development time. So you would like to use the configuration to control the logging behaviour transparently from the applications.

Also you may like to enable this automatic logging for only some percentage of user sessions, instead of all users.


For example if you would to log the console.error() function, you just need to put the code below as soon as you have initialised the Loggly:
```Javascript
_LTracker.injectLog({
enable:100,
target:"console.error",
name:"error"
});
```
The value of ```enable``` attribute is set 100. This means thar the Loggly will log the console.error() function for 100% percent of the users, which means all user sessions.

The value of the ```target``` attribute specifies which javascript function it needs to monitor. It has to have atleast one "." to specify the target object and target method the Loggly needs to monitor.

The functions that the Loggly intercept will not be affected. For example, console.error() will still continually print messages to the console as usual. The injected codes will simply send the messages to loggly after executing the original console function. For example, if the application executes the following code:
```Javascript
console.error("Something wrong");
```
Then the injected code will transparently executes the following code:

```Javascript
_LTracker.push({
error:"Something wrong"
});
```

The name of the variable ```error``` is coming from the ```name``` attribute passed into the ```_LTracker.injectLog``` in the previous example.

If the input parameter is an object, for example:

```Javascript
console.error({errorcode:"Error01", description:"Something goes wrong"});
```
the injected code will execute:

```Javascript
_LTracker.push({
error:{errorcode:"Error01", description:"Something goes wrong"}
})
```
If multiple parameters are passed in to the function:

```Javascript
console.error("Something wrong", {errorCode:"001", errorCotent:"wierd error"});
```

The injected code will execute:
```Javascript
_LTracker.push({
error:{param1:"Something wrong", param2:{errorCode:"001", errorCotent:"wierd error"}}
})
```

On other hand if the injected function has the return value, for example if the following is executed as soon as the Loggly is initializez:

```Javascript
LTracker.injectLog({
"name":"localStorageGetItem",
"target":"localStorage.getItem",
"enable":100
});
```
The Loggly will monitor ```localStorage.getItem``` function.

So if the application executes:
```Javascript
var username=localStorage.getItem("username");
```

and if the returned value from the localStorage is "dilshat"

then injected code executes the following:
```Javascript
_LTracker.push({
localStorageGetItem:{input:"username", output:"dilshat"}
})
```
You can test it here https://jsfiddle.net/dilshat/1t0y6dp1/
@@ -48,7 +48,7 @@
var _onerror = window.onerror;
//send console error messages to Loggly
window.onerror = function (msg, url, line, col, err){
tracker.push({
tracker.push({
category: 'BrowserJsException',
exception: {
message: msg,
@@ -159,18 +159,41 @@
track: function (data) {
// inject session id
data.sessionId = this.session_id;
var toStringValue=function(obj){
//In Samsung TV Orsay, JSON.stringify will be in infinite loop when in circular reference, and a difference reference passed in the second parameter. So we have to use counter to get out of the infinite loop.
var objectData=[];
var objectName=[];
var count=0;
return JSON.stringify(obj, function(key, val) {
count++;
if(count>10){
return;
}
if (typeof val === "object") {
var ind=objectData.indexOf(val);
if (ind >= 0) {
return "$"+objectName[ind];
}
else{
objectData.push(val);
objectName.push(key);
}
}
return val;
});

};
try {
//creating an asynchronous XMLHttpRequest
var xmlHttp = new XMLHttpRequest();
xmlHttp.open('POST', this.inputUrl, true); //true for asynchronous request

if (tracker.useUtfEncoding === true) {
xmlHttp.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');
} else {
xmlHttp.setRequestHeader('Content-Type', 'text/plain');
}
xmlHttp.send(JSON.stringify(data));

} catch (ex) {
if (window && window.console && typeof window.console.log === 'function') {
console.log("Failed to log to loggly because of this exception:\n" + ex);
@@ -194,7 +217,122 @@
},
setCookie: function (value) {
document.cookie = LOGGLY_SESSION_KEY + '=' + value;
}
},
injectedList:{},
buildInjectLog: function(inputParameters, outputParameters, errorObject){
if(errorObject){
if(!inputParameters){
inputParameters="";
}
if(!outputParameters){
outputParameters="";
}
return {
error:errorObject,
input:inputParameters,
output:outputParameters
};
}
else if(outputParameters){
if(!inputParameters){
inputParameters="";
}
return {
input:inputParameters,
output:outputParameters
};
}
else if((!inputParameters) || inputParameters.length==0){
return "";
}
else if(inputParameters.length==1){
if(inputParameters[0]){
return inputParameters[0];
}
else{
return "";
}

}
else {
return inputParameters;
}

},

injectLog:function(request){
if(!request.enable){
return;
}
if(request.enable<(Math.random()*100)){
return;
}
if(!request.target){
return;
}

if(!request.name){
return;
}
if(this.injectedList[request.target]){
return;
}
var targetparts=request.target.split(".");
if(targetparts.length<=1){
return;
}
var targetObject=null;
if(request.targetBase && typeof request.targetBase === 'object'){
targetObject=request.targetBase;
}
else{
targetObject=this.getTargetObjectFromString(targetparts[0]);
}

for(var i=1;(i+1)<targetparts.length;i++){
if(!targetObject){
return null;
}
targetObject=targetObject[targetparts[i]];
}
if(!targetObject){
return;
}
var methodName=targetparts[targetparts.length-1];
var targetFunction=targetObject[methodName];
if(!targetFunction){
return;
}
this.injectedList[request.target]=targetFunction;
var that=this;
targetObject[methodName]=function(){

var returnValue=null;
var errorObject=null;
try{
returnValue=targetFunction.apply(targetObject, arguments);
}
catch(error){
errorObject=error;
}
var data={};
data[request.name]=that.buildInjectLog(arguments,returnValue,errorObject);
that.track(data);
if(errorObject){
throw errorObject;
}
return returnValue;
};
},
getTargetObjectFromString:function(targetObjectName){
try{
return eval(targetObjectName);
}
catch(error){
this.track({logglyconfigerror: "loggly config eval error:"+error+" the device may not support evail, consider use targetBase"});
}
}

};

var existing = window._LTracker;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.