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
1111module 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 + ) ) ? ) (?: - ( [ \d A - Z a - z \- ] + (?: \. [ \d A - Z a - z \- ] + ) * ) ) ? (?: \+ ( [ \d A - Z a - z \- ] + (?: \. [ \d A - Z a - 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