?

Log in

No account? Create an account
 
 
07 February 2016 @ 03:45 am
Javascript errors report  
When users open my web site I want to know what JavaScript errors users have (if any).
That's why I append this javascript to almost every page on my web site:
window.onerror = function(errmessage, errurl, errline) {
	var params = {
		list: [],
		add: function(name, value) {
			if (value != null) this.list.push(name + '=' + encodeURIComponent(value));
			return this;
		},
		toString: function() {
			if (this.list.length) return '?' + this.list.join('&');
			return '';
		}
	};
	new Image().src='/jeh' + params.add('errmessage', errmessage)
		.add('errurl', errurl)
		.add('errline', errline)
		.add('r', Math.floor((Math.random() * 10) + 1));
}
That script reports javascript errors from user browser back to our server.
Once per day our server aggregates these errors and emails to developers Javascript Errors report.
This is an example of what that report looks like:


We then review these errors on case-by-case basis and decide whether we want to fix that error or we want to suppress that error from report (because we can not fix it).

Still, there are challenges: sometimes it is hard to separate errors that we can fix from errors we can not fix.
For example, we can not fix the most frequent "Uncaught ReferenceError: google is not defined" error, because it is caused by occasional browsers that do not work well with Google Maps API.
But we do not want to suppress that error either, because sometimes, by mistake, we may introduce problem in our own javascript that would generate the same error messages on mass scale for our users.

See: discussion in ivan-gandhi blog.
 
 
 
serjiojitserserjiojitser on February 7th, 2016 03:21 pm (UTC)
>For example, we can not fix the most frequent "Uncaught ReferenceError: google is not defined"

а можно её обвернуть в try catch с выдачей № браузера?
Dennis Gorelikdennisgorelik on February 7th, 2016 03:25 pm (UTC)
BrowserUserAgent
Do you mean "how to extract BrowserUserAgent from that error"?
You do not need to do that.

When "new Image().src='...'" sends request to your server - your server has all that information available: IPAddress, BrowserUserAgent, Time + all data that is sent in errmessage, errurl, errline parameters.
occam_agaoccam_aga on February 7th, 2016 04:10 pm (UTC)
а готовые решения для диагностики не рассматривались?
Dennis Gorelikdennisgorelik on February 7th, 2016 04:18 pm (UTC)
Не рассматривались.
Только сейчас kika предложил.

Но, мне кажется, не стоит подключать ещё одну систему. Лучше, чтобы всё выполнялось внутри сайта.
журнал закрытjuan_gandhi on February 7th, 2016 06:29 pm (UTC)
A very good idea, I think.
Dennis Gorelikdennisgorelik on February 8th, 2016 01:43 am (UTC)
Do you have similar javascirpt error diagnostic system on your web site?
Сисадмин-любительulrith on February 8th, 2016 08:55 am (UTC)
Interesting!
Why do you need to add a random value at the end of the error url?
Would you like to post server-side script which creates nice results table also? :)
Dennis Gorelikdennisgorelik on February 8th, 2016 09:36 am (UTC)
1) Without adding random value to the URL, the same user would report any given URL only once.
All following image requests would be cached.

With random value the same error can be reported up to 10 times from the same user.

2) Server-side code is quite a little longer and has multiple parts.
- Web handler that receives request from javascript and stores data to JavascriptException database table.
- Windows service that executes every day, produces HTML report and sends it by email.

To give you an idea, here is SQL script for JavascriptException table:
if object_id('JavascriptException') is not null
	drop table JavascriptException
go

create table JavascriptException(
	JavascriptExceptionId int identity(1,1) not null,
	ErrorDate datetime2(4) not null,
	IpAddress varchar(15) not null,
	Username nvarchar(50) not null,
	Url nvarchar(500) null,
	UrlReferrer nvarchar(500) not null,
	BrowserUserAgent nvarchar(500) not null,
	LineNumber int null,
	GroupHash int not null, -- (ErrorMessage).GetHashCode() if ErrorMessage is not null, otherwise 0
	ErrorMessage nvarchar(500) null
)
go

alter table JavascriptException add constraint PK_JavascriptException primary key clustered
(JavascriptExceptionId)
go

-- JavascriptException report to developers.
create nonclustered index IX_ErrorDate on JavascriptException
(ErrorDate)
go

-- DiagnosticJavascriptList.GetList()
create nonclustered index IX_GroupHash on JavascriptException
(GroupHash)
go

Сисадмин-любительulrith on February 8th, 2016 10:06 am (UTC)
Oh thanks!
I'm going to parse the logs with general bash approach...
Dennis Gorelikdennisgorelik on February 8th, 2016 10:09 am (UTC)
What does "general bash approach" involve?
Сисадмин-любительulrith on February 8th, 2016 10:14 am (UTC)
Just to extract strings with errors from the logs to create simple text summary of the day in csv-file for my two fellow developers. :)
Dennis Gorelikdennisgorelik on February 8th, 2016 12:02 pm (UTC)
1) How do errors end up in the logs in your system?

2) Do you plan to manually run csv-file extraction from your log every day?
Сисадмин-любитель: gosdepulrith on February 8th, 2016 12:05 pm (UTC)
1. They're in the apache access log

2. Cron
Dennis Gorelikdennisgorelik on February 8th, 2016 12:12 pm (UTC)
How do browser javascript errors end up in apache access log?
Are you appending javascript similar to what I showed in this posting to your web pages?
Сисадмин-любитель: gosdepulrith on February 8th, 2016 12:21 pm (UTC)
Разумеется я добавил скрипт, иначе о чем вообще мы тут ведем речь? :))
Dennis Gorelikdennisgorelik on February 8th, 2016 12:24 pm (UTC)
You never know - may be you posses some magic skills :-)
Сисадмин-любительulrith on February 8th, 2016 01:24 pm (UTC)
Thank you for the approach and for the implementation example
Сисадмин-любительulrith on February 8th, 2016 10:15 am (UTC)
Also I'm currently thinking how to use Rollbar for better presentation...