Skip to content

Commit f33943b

Browse files
committed
Implemented many new plugins.
1 parent eec9dde commit f33943b

File tree

3 files changed

+284
-7
lines changed

3 files changed

+284
-7
lines changed

src/example/index.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head lang="en">
4+
<meta charset="UTF-8">
5+
<title>Exceptionless Test</title>
6+
</head>
7+
<body>
8+
<script type="application/javascript" src="../node_modules/es6-promise/dist/es6-promise.js"></script>
9+
<script type="application/javascript" src="../node_modules/stackframe/dist/stackframe.js"></script>
10+
<script type="application/javascript" src="../node_modules/error-stack-parser/dist/error-stack-parser.js"></script>
11+
<script type="application/javascript" src="../node_modules/stack-generator/dist/stack-generator.js"></script>
12+
<script type="application/javascript" src="../node_modules/stacktrace-gps/dist/stacktrace-gps.js"></script>
13+
<script type="application/javascript" src="../node_modules/stacktrace-js/dist/stacktrace.js"></script>
14+
<script type="application/javascript" src="../dist/exceptionless.js"></script>
15+
16+
<script type="application/javascript" src="math.js"></script>
17+
<script type="application/javascript" src="index.js"></script>
18+
<script type="application/javascript">
19+
'use strict';
20+
21+
var client = Exceptionless.ExceptionlessClient.default;
22+
client.config.apiKey = 'LhhP1C9gijpSKCslHHCvwdSIz298twx271n1l6xw';
23+
client.config.serverUrl = 'http://localhost:50000';
24+
25+
client.config.log = new Exceptionless.ConsoleLog();
26+
client.register();
27+
</script>
28+
29+
<button onclick="throwDivisionByZero()">Division By Zero</button>
30+
<button onclick="throwIndexOutOfRange()">Index Out Of Range</button>
31+
</body>
32+
</html>

src/exceptionless-spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ module Exceptionless {
182182
.then(processResponse, processResponse)
183183
.then(done);
184184
}, 5000);
185+
186+
it('should submit invalid object data', (done) => {
187+
//{setPropertybject: {foo: 'bar'}}, function() {
188+
// throw new Error('foo');
189+
//});
190+
});
185191
});
186192

187193
describe('Storage', () => {
@@ -258,4 +264,31 @@ module Exceptionless {
258264
expect(storage.count()).toBe(0);
259265
});
260266
});
267+
268+
// TODO: We should move this logic out into an exported utils class to make it easier to test.
269+
describe('ModuleInfoPlugin', () => {
270+
it('should parse version from script source', () => {
271+
function getVersion(source:string) {
272+
if (!source) {
273+
return null;
274+
}
275+
276+
var versionRegex = /(v?((\d+)\.(\d+)(\.(\d+))?)(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?)/;
277+
var matches = versionRegex.exec(source);
278+
if (matches && matches.length > 0) {
279+
return matches[0];
280+
}
281+
282+
return null;
283+
}
284+
285+
expect(getVersion('https://code.jquery.com/jquery-2.1.3.js')).toBe('2.1.3');
286+
expect(getVersion('//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css')).toBe('3.3.4');
287+
expect(getVersion('https://cdnjs.cloudflare.com/ajax/libs/1140/2.0/1140.css')).toBe('2.0');
288+
expect(getVersion('https://cdnjs.cloudflare.com/ajax/libs/Base64/0.3.0/base64.min.js')).toBe('0.3.0');
289+
expect(getVersion('https://cdnjs.cloudflare.com/ajax/libs/angular-google-maps/2.1.0-X.10/angular-google-maps.min.js')).toBe('2.1.0-X.10');
290+
expect(getVersion('https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/2.1.8-M1/swagger-ui.min.js')).toBe('2.1.8-M1');
291+
expect(getVersion('https://cdnjs.cloudflare.com/BLAH/BLAH.min.js')).toBe(null);
292+
});
293+
});
261294
}

src/exceptionless.ts

Lines changed: 219 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/// <reference path="typings/tsd.d.ts" />
22
/// <reference path="stacktrace.d.ts" />
3+
34
// TODO: We'll need a poly fill for promises.
4-
// TODO: Process Errors
5+
// TODO: Verify that stack traces are parsed properly.
56
// TODO: Handle Server Settings
67
// TODO: Lock configuration.
78
// TODO: Look into using templated strings `${1 + 1}`.
89
// TODO: Add plugin for populating module info.
9-
// TODO: Add plugin for populating defaults.
1010

1111
module Exceptionless {
1212
export class ExceptionlessClient {
@@ -190,6 +190,8 @@ module Exceptionless {
190190
public submissionClient:ISubmissionClient = new SubmissionClient();
191191
public storage:IStorage<any> = new InMemoryStorage<any>();
192192
public queue:IEventQueue;
193+
public defaultTags:string[] = [];
194+
public defaultData:Object = {};
193195

194196
constructor(apiKey:string, serverUrl?:string) {
195197
this.apiKey = apiKey;
@@ -843,6 +845,10 @@ module Exceptionless {
843845
}
844846

845847
public setProperty(name:string, value:any): EventBuilder {
848+
if (!name || (value === undefined || value == null)) {
849+
return this;
850+
}
851+
846852
if (!this.target.data) {
847853
this.target.data = {};
848854
}
@@ -958,11 +964,46 @@ module Exceptionless {
958964
}
959965

960966
public static addDefaultPlugins(config:Configuration): void {
961-
//config.AddPlugin<ConfigurationDefaultsPlugin>();
962-
//config.AddPlugin<EnvironmentInfoPlugin>();
967+
config.addPlugin(new ConfigurationDefaultsPlugin());
963968
config.addPlugin(new ErrorPlugin());
964-
//config.AddPlugin<DuplicateCheckerPlugin>();
965-
//config.AddPlugin<SubmissionMethodPlugin>();
969+
config.addPlugin(new DuplicateCheckerPlugin());
970+
config.addPlugin(new ModuleInfoPlugin());
971+
config.addPlugin(new RequestInfoPlugin());
972+
config.addPlugin(new SubmissionMethodPlugin());
973+
}
974+
}
975+
976+
class ConfigurationDefaultsPlugin implements IEventPlugin {
977+
public priority:number = 10;
978+
public name:string = 'ConfigurationDefaultsPlugin';
979+
980+
run(context:Exceptionless.EventPluginContext): Promise<any> {
981+
if (!!context.client.config.defaultTags) {
982+
if (!context.event.tags) {
983+
context.event.tags = [];
984+
}
985+
986+
for (var index = 0; index < context.client.config.defaultTags.length; index++) {
987+
var tag = context.client.config.defaultTags[index];
988+
if (tag && context.client.config.defaultTags.indexOf(tag) < 0) {
989+
context.event.tags.push(tag)
990+
}
991+
}
992+
}
993+
994+
if (!!context.client.config.defaultData) {
995+
if (!context.event.data) {
996+
context.event.data = {};
997+
}
998+
999+
for (var key in context.client.config.defaultData) {
1000+
if (!!context.client.config.defaultData[key]) {
1001+
context.event.data[key] = context.client.config.defaultData[key];
1002+
}
1003+
}
1004+
}
1005+
1006+
return Promise.resolve();
9661007
}
9671008
}
9681009

@@ -980,7 +1021,7 @@ module Exceptionless {
9801021
}
9811022

9821023
class ErrorPlugin implements IEventPlugin {
983-
public priority:number = 50;
1024+
public priority:number = 30;
9841025
public name:string = 'ErrorPlugin';
9851026

9861027
run(context:Exceptionless.EventPluginContext): Promise<any> {
@@ -1037,6 +1078,162 @@ module Exceptionless {
10371078
}
10381079
}
10391080

1081+
class ModuleInfoPlugin implements IEventPlugin {
1082+
public priority:number = 40;
1083+
public name:string = 'ModuleInfoPlugin';
1084+
1085+
run(context:Exceptionless.EventPluginContext):Promise<any> {
1086+
console.log(context);
1087+
if (!context.event.data || !context.event.data['@error'] || !!context.event.data['@error'].modules) {
1088+
return Promise.resolve();
1089+
}
1090+
1091+
try {
1092+
var modules:IModule[] = [];
1093+
var scripts = document.getElementsByTagName('script');
1094+
if (scripts && scripts.length > 0) {
1095+
for (var index = 0; index < scripts.length; index++) {
1096+
if (scripts[index].src) {
1097+
modules.push({ module_id: index, name: scripts[index].src, version: this.getVersion(scripts[index].src) });
1098+
} else if (!!scripts[index].innerHTML) {
1099+
modules.push({ module_id: index, name: 'Script Tag', version: this.getHashCode(scripts[index].innerHTML) });
1100+
}
1101+
}
1102+
1103+
context.event.data['@error'].modules = modules;
1104+
}
1105+
} catch (e) {
1106+
context.log.error('Unable to get module info. Exception: ' + e.message);
1107+
}
1108+
1109+
return Promise.resolve();
1110+
}
1111+
1112+
private getVersion(source:string): string {
1113+
if (!source) {
1114+
return null;
1115+
}
1116+
1117+
var versionRegex = /(v?((\d+)\.(\d+)(\.(\d+))?)(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?)/;
1118+
var matches = versionRegex.exec(source);
1119+
if (matches && matches.length > 0) {
1120+
return matches[0];
1121+
}
1122+
1123+
return null;
1124+
}
1125+
1126+
private getHashCode(source:string): string {
1127+
if (!source || source.length === 0) {
1128+
return null;
1129+
}
1130+
1131+
var hash:number = 0;
1132+
for (var index = 0; index < source.length; index++) {
1133+
var character = source.charCodeAt(index);
1134+
hash = ((hash << 5) - hash) + character;
1135+
hash |= 0;
1136+
}
1137+
1138+
return hash.toString();
1139+
}
1140+
1141+
private get
1142+
}
1143+
1144+
class DuplicateCheckerPlugin implements IEventPlugin {
1145+
public priority:number = 50;
1146+
public name:string = 'DuplicateCheckerPlugin';
1147+
1148+
run(context:Exceptionless.EventPluginContext):Promise<any> {
1149+
// TODO: Implement
1150+
return Promise.resolve();
1151+
}
1152+
}
1153+
1154+
class RequestInfoPlugin implements IEventPlugin {
1155+
public priority:number = 60;
1156+
public name:string = 'RequestInfoPlugin';
1157+
1158+
run(context:Exceptionless.EventPluginContext):Promise<any> {
1159+
if (!!context.event.data && !!context.event.data['@request']) {
1160+
return Promise.resolve();
1161+
}
1162+
1163+
if (!context.event.data) {
1164+
context.event.data = {};
1165+
}
1166+
1167+
var requestInfo:IRequestInfo = {
1168+
user_agent: navigator.userAgent,
1169+
is_secure: location.protocol === 'https:',
1170+
host: location.hostname,
1171+
port: location.port && location.port !== '' ? parseInt(location.port) : 80,
1172+
path: location.pathname,
1173+
//client_ip_address: 'TODO',
1174+
cookies: this.getCookies(),
1175+
query_string: this.getQueryString(),
1176+
};
1177+
1178+
if (document.referrer && document.referrer !== '') {
1179+
requestInfo.referrer = document.referrer;
1180+
}
1181+
1182+
context.event.data['@request'] = requestInfo;
1183+
return Promise.resolve();
1184+
}
1185+
1186+
private getCookies(): any {
1187+
if (!document.cookie) {
1188+
return null;
1189+
}
1190+
1191+
var result = {};
1192+
1193+
var cookies = document.cookie.split(', ');
1194+
for (var index = 0; index < cookies.length; index++) {
1195+
var cookie = cookies[index].split('=');
1196+
result[cookie[0]] = cookie[1];
1197+
}
1198+
1199+
return result;
1200+
}
1201+
1202+
private getQueryString(): any {
1203+
var query:string = location.search.substring(1);
1204+
var pairs = query.split('&');
1205+
if (pairs.length === 0) {
1206+
return null;
1207+
}
1208+
1209+
var result = {};
1210+
for (var index = 0; index < pairs.length; index++) {
1211+
var pair = pairs[index].split('=');
1212+
result[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
1213+
}
1214+
1215+
return result;
1216+
}
1217+
}
1218+
1219+
class SubmissionMethodPlugin implements IEventPlugin {
1220+
public priority:number = 100;
1221+
public name:string = 'SubmissionMethodPlugin';
1222+
1223+
run(context:Exceptionless.EventPluginContext):Promise<any> {
1224+
var submissionMethod:string = context.contextData.getSubmissionMethod();
1225+
if (!!submissionMethod) {
1226+
if (!context.event.data) {
1227+
context.event.data = {};
1228+
}
1229+
1230+
context.event.data['@submission_method'] = submissionMethod;
1231+
}
1232+
1233+
return Promise.resolve();
1234+
}
1235+
}
1236+
10401237
interface IParameter {
10411238
data?:any;
10421239
generic_arguments?:string[];
@@ -1089,6 +1286,21 @@ module Exceptionless {
10891286
modules?:IModule[]
10901287
}
10911288

1289+
interface IRequestInfo {
1290+
user_agent?:string;
1291+
http_method?:string;
1292+
is_secure?:boolean;
1293+
host?:string;
1294+
port?:number;
1295+
path?:string;
1296+
referrer?:string;
1297+
client_ip_address?:string;
1298+
cookies?:any;
1299+
post_data?:any;
1300+
query_string?:any;
1301+
data?:any
1302+
}
1303+
10921304
export interface IUserDescription {
10931305
email_address?:string;
10941306
description?:string;

0 commit comments

Comments
 (0)