Send javascript errors to servers - javascript

I have a script that capture the errors and send them to my server. But I'm worried that if I have a lot of users, and every user gets a couple errors, it may collapse my server.
This is my code:
window.onerror = function(msg, url, num) {
try {
var clientSideErrorInfo = {
message: msg,
url: url,
num: num
};
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://domain/api/v1/browser/', true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify(clientSideErrorInfo));
console.log(clientSideErrorInfo)
} catch (e) {
console.log(e);
// Don't allow for infinitely recursively unhandled errors
return true;
}
};
Is there a way to send a group of logs instead of sending them one by one?
Thanks

Instead of sending the error at the moment you get it, you could collect all errors into a global variable and you send them using an interval. This way you can limit how many errors you want to send at a same time and you could increase your interval as well.
var errorSend = {};
errorSend.listErrors = [];
errorSend.maxErrors = 50;
errorSend.interval = 100;
window.onerror = function(msg, url, num) {
var clientSideErrorInfo = {
message: msg,
url: url,
num: num
};
listErrors.push(clientSideErrorInfo);
console.log(clientSideErrorInfo)
};
function sendErrors() {
if (errorSend.listErrors>errorSend.maxErrors) {
console.log("Too many errors to send");
return;
}
var errors = {list: errorSend.listErrors};
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://domain/api/v1/browser/', true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify(errors));
}
setInterval(sendErrors,errorSend.interval);

Something very simple,umm:
var body =[];
setInterval(function(){
//Using a copy of the error queue
let batch = body.slice();
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://domain/api/v1/browser/', true);
xhr.setRequestHeader("Content-Type", "application/json");
let myJson = JSON.stringify(body);
xhr.send({
data:{
param: myJson
}
});
//Updating the main queue to contain only unsent error messages
body=body.slice(batch.length,body.length);
},time_you_specify);
window.onerror = function(msg, url, num) {
try {
var clientSideErrorInfo = {
message: msg,
url: url,
num: num
};
body.push(clientSideErrorInfo);
console.log(clientSideErrorInfo)
} catch (e) {
console.log(e);
// Don't allow for infinitely recursively unhandled errors
return true;
}
};

Is not problem for this job but if you have a lot of errors in you web app can be problem. First you will need to setup your javascript code to the perfect state. In that case you idea is good ( catch every possible error ) . Just put it in some table on server .
Heres from mozilla dev site about param :
window.onerror = function (msg, url, lineNo, columnNo, error) {
var string = msg.toLowerCase();
var substring = "script error";
if (string.indexOf(substring) > -1){
alert('Script Error: See Browser Console for Detail');
} else {
var message = [
'Message: ' + msg,
'URL: ' + url,
'Line: ' + lineNo,
'Column: ' + columnNo,
'Error object: ' + JSON.stringify(error)
].join(' - ');
alert(message);
}
return false;
};
Very important use (userAgent) detectBrowser data , you must know which device is used also which browser is used -just add data intro your function. In 90% your client error will happend only on specific platforms . For example on android chrome ver < 23 ...
Please don't use interval for this kind of tasks , just on error catch event send error log to the server just like you already did!

It is better to use message queueing infrastructure, if you are expecting millions of messages
some sample

Related

Track javascript runtime errors

Is there any way to capture all type of console errors?
Actually, I want to store all console errors to the database so I can fix serious issues of my PHP website.
Here is my current code to catch errors but this code is not capturing internal server errors and some other kind of errors like
www-widgetapi.js:99 Failed to execute 'postMessage' on 'DOMWindow':
The target origin provided ('https://www.youtube.com') does not match
the recipient window's origin
Current script that I have
function ErrorSetting(msg, file_loc, line_no) {
var e_msg=msg;
var e_file=file_loc;
var e_line=line_no;
var error_d = "Error in file: " + file_loc +
"\nline number:" + line_no +
"\nMessage:" + msg;
if(logJsErrors){
theData = "file="+file_loc+"&line="+line_no+"&err="+msg;
ajaxCtrl(
function(){
return true;
},Helpers.RootURL()+"/logs/index",theData
);
}
if(isDebugging){
console.error(error_d);
}
return true;
}
window.onerror = ErrorSetting;
I really appreciate your efforts.
Thank you :)
You could perform a kind of prototype of console.log, when you call console.log an ajax is fired, so you could do somethig like this:
(function () {
var postCons = console.log;
console.log = function (err) {
var xhttp = new XMLHttpRequest();
postCons.apply(this, arguments);
xhttp.open("POST", "log.php", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {//you could avoid this step
alert(this.responseText);//response from php
}
};
xhttp.send("data="+encodeURI(err));
}
})()
In log.php you could do whatever you want with $_POST['data'] , you could use something like urldecode($_POST['data']) .

Populate table as data chunks are received

I have a problem with my code and I'm struggling finding why it doesn't work as expected.
I have an API that returns data async. and I want the frontend side to add that data as soon as it's being received. What I expect is an API that returns, say 200 items, then javascript to load those 200 items to a table, meanwhile the API keeps returning another 200 items, and then javascript appends them to the table, and so on until there is no more data left.
I'm using vanilla Javascript 5, prototype-based MVC pattern. Perhaps I'm not getting something simple or its far more complex than I expected.
resultView.js
//this function gets executed by some other code not relevant
ResultView.prototype.execute = function(serverName, databaseName, query){
var response = resultController.getData(serverName, databaseName, query);
console.log("response: ", response); //prints undefined
response.done(function(data){ // Uncaught TypeError: Cannot read property 'done' of undefined
console.log("response done: ", response); //doesn't even execute
data.forEach(populateTable); //this code should populates the table
});
}
resultController.js
ResultController.prototype.getData = function(serverName, databaseName, query){
return resultModel.getData(serverName, databaseName, query);
};
resultModel.js
ResultModel.prototype.getData = function (serverName, databaseName, query) {
var dataSend = {
//the code that is being sent
};
var result = "";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onprogress = function () {
result += xhr.responseText;
if(xhr.readyState == 4){
console.log("return: ", result); //shows the results properly each time they are received
return result; //not sure about this return
}
}
xhr.send(JSON.stringify(dataSend));
};
}
I know the data is being received in the API, and the data is returned properly in the front end, the issue must be how I am trying to handle it.
Currently, the results I am getting on the console.log at resultModel.js are the expected, the problem seems to be when calling it from resultView.js, I guess when the function calls response.done(), but I am unable to fix it.
Anyone knows how can I approach a solution?
Thanks in advance.
EDIT:
Partially thanks to Ionut, I've managed to make the resultView.js return better datas, but I still have the problem at the resultView.js, when I try to use response.done(...) it tells me it can't do done() of undefined, but the data should be able to be returned. This is my code in resultModel.js now, the rest remains unchanged.
resultModel.js
var xhr = new XMLHttpRequest();
console.log("Sending the request...");
xhr.open("POST", urlBase + "QueryResults", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
console.log("return: ", xhr.responseText); //data is logged properly
return xhr.responseText; //it should be returned properly
}
};
xhr.send(JSON.stringify(queryRequest));
You should add a callback function to manage the full response.
If you want to implement something like lazy-loading you should request your API to send you batches of a smaller number of items, you process them then request more until you get them all.
Here is a basic http request.
console.log('Sending the request ...');
var xhr = new XMLHttpRequest();
xhr.open('GET', "//ipinfo.io/json", true);
xhr.send();
xhr.onreadystatechange = processRequest;
function processRequest(e) {
console.log('Getting the response ...');
if (xhr.readyState == 4 && xhr.status == 200) {
var response = JSON.parse(xhr.responseText);
console.log('Your ip address is ' + response.ip);
} else {
console.log('Error state=' + xhr.readyState + ', status=' + xhr.status);
}
}

Azure Mobile Service and Javascript

Hi there i am stuck and somehow don't find the solution. It seems simple but, well ok. Here it goes. I have a mobile service in Azure and i want to reach that one with javascript. How do i get around the 401 Unauthorized? I tried with the documentation supplied from MS but no luck. This is what i got so far (adding the key to the url is not working of course) what can i add to get it to work?
var client = new WindowsAzure.MobileServiceClient(
"https://cdshop.azure-mobile.net/",
"vGpqzyApJXXXXXXXXblQCWne73"
);
var getJSON = function (url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function () {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
xhr.send();
};
$(function () {
$('#clickme').click(function () {
getJSON('http://cdshop.azure-mobile.net/api/cds/total?key=vGpqzyApJXXXXXXXXblQCWne73', function (err, data) {
if (err != null) {
alert('Something went wrong: ' + err);
} else {
alert('Your Json result is: ' + data.result);
result.innerText = data.result;
}
});
});
});
If you are creating your own HTTP requests, you need to set a request header called X-ZUMO-APPLICATION with your Application Key, e.g. "vGpqzyApJXXXXXXXXblQCWne73", for tables and APIs that are set to "application" or "users". (Assuming you are still using Mobile Services; the newer App Service does not use this X-ZUMO-APPLICATION header.) Tables and APIs set for "users" also need an X-ZUMO-AUTH request header with the user's authentication token.
Alternatively, you can use the MobileServiceClient you created in the first line, and it will do this for you. This page has examples for calling APIs and tables. For your example:
client.invokeApi("cds", {
body: null,
method: "get"
}).done(function (data) {
alert('Your Json result is: ' + data.result);
result.innerText = data.result;
}, function(error) {
alert('Something went wrong: ' + error);
});

Ajax - Function to check if url exists before send request

I am writing a function to grab a json file from a website/server and save it in local storage with the code:
function donators() {
var jsonURL = "http://mywebsite.com/donators.json";
var xhr = new XMLHttpRequest();
xhr.open("GET", jsonURL, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
localDataStore.set("fb_donators", xhr.responseText);
}
};
xhr.send();
}
The above code works perfectly fine when the json file can be reached, but if my server goes down and the file cannot be reached my script halts at the line with xhr.send() with the error:
GET http://mywebsite.com/donators.json net::ERR_NAME_NOT_RESOLVED
Is there a way I can detect check if url can be reached before the send request to stop the send the request and allow the rest of my script to continue to run instead of getting halted at xhr.send()?
Thanks!
You can use a try block for this. It still requires the HTTP request, but it will fail gracefully and you can handle the error any way you'd like.
function donators() {
var jsonURL = "http://mywebsite.com/donators.json";
var xhr = new XMLHttpRequest();
xhr.open("GET", jsonURL, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
localDataStore.set("fb_donators", xhr.responseText);
}
};
xhr.timeout = 5000;
xhr.ontimeout = function() {
alert( 'The operation timed out.' );
}
try { xhr.send(); } catch( err ) {
alert( 'Error getting data: ' + err.message );
}
}

replace setInterval with setTimeout

thanks in advance for your help! I am working with (and super new to) JavaScript, node.js with express, and sqlite3. I am trying to make an AJAX request to get a list of all the messages that have been posted to the chatroom page:
var meta = document.querySelector('meta[name=roomName]');
var roomName = meta.content;
window.addEventListener('load', function(){
var intervalID = setInterval(updateMessages, 4000);
}, false);
function updateMessages() {
var req = new XMLHttpRequest();
req.open('GET', '/' + roomName + '/messages.json', true);
req.send();
document.getElementById('messages').innerHTML = req.responseText;
}
Two questions: 1. I think I should be using setTimeout instead of setInterval. How would I go about switching to using this method? 2. Is the server-side code below that corresponds to the code above correct? How do I get access to the data that comes back after this request?
app.get('/:roomName/messages.json', function(request, response){
var roomName = request.params.roomName;
var sql = "SELECT ALL body FROM messages where room="+roomName+";";
conn.query(sql, function(error, result) {
if(error) {
console.log("There was an error.");
}
response.send(result);
});
});
setInterval is the appropriate thing to use here.
However, keep in mind that you will never see any messages because AJAX is asynchronous, so req.responseText won't have anything. You should use a readystatechange event:
req.open(......);
req.onreadystatechange = function() {
if( this.readyState == 4) {
document.getElementById('messages').innerHTML = this.responseText;
}
};
req.send();

Categories