Merge pull request #4 from Fine0830/feat-error-monitor

Feat support ajax and promise error types
diff --git a/src/errors/ajax.ts b/src/errors/ajax.ts
new file mode 100644
index 0000000..e0d0616
--- /dev/null
+++ b/src/errors/ajax.ts
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Base from '../services/base';
+import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+
+class AjaxErrors extends Base {
+  public handleError(options: {reportUrl: string; serviceName: string}) {
+    if (!window.XMLHttpRequest) {
+      return;
+    }
+    this.reportUrl = options.reportUrl;
+    this.serviceName = options.serviceName;
+
+    const xhrSend = XMLHttpRequest.prototype.send;
+    const xhrEvent = (event: any) => {
+      try {
+        if (event && event.currentTarget && event.currentTarget.status !== 200) {
+          this.logInfo = {
+            category: ErrorsCategory.AJAX_ERROR,
+            grade: GradeTypeEnum.ERROR,
+            errorUrl: event.target.responseURL,
+            message: event.target.response,
+            errorInfo: {
+              status: event.target.status,
+              statusText: event.target.statusText,
+            },
+          };
+          this.traceInfo();
+        }
+      } catch (error) {
+        console.log(error);
+      }
+    };
+    XMLHttpRequest.prototype.send = function() {
+      if (this.addEventListener) {
+        this.addEventListener('error', xhrEvent);
+        this.addEventListener('load', xhrEvent);
+        this.addEventListener('abort', xhrEvent);
+      } else {
+        const stateChange = this.onreadystatechange;
+        this.onreadystatechange = function(event: any) {
+          stateChange.apply(this, arguments);
+          if (this.readyState === 4) {
+            xhrEvent(event);
+          }
+        };
+      }
+      return xhrSend.apply(this, arguments);
+    };
+  }
+}
+
+export default new AjaxErrors();
diff --git a/src/errors/index.ts b/src/errors/index.ts
new file mode 100644
index 0000000..b213fd0
--- /dev/null
+++ b/src/errors/index.ts
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import JSErrors from './js';
+import PromiseErrors from './promise';
+import AjaxErrors from './ajax';
+
+export {
+  JSErrors, PromiseErrors, AjaxErrors,
+};
diff --git a/src/errors/jsErrors.ts b/src/errors/js.ts
similarity index 79%
rename from src/errors/jsErrors.ts
rename to src/errors/js.ts
index cb7756d..e6b81f8 100644
--- a/src/errors/jsErrors.ts
+++ b/src/errors/js.ts
@@ -15,15 +15,15 @@
  * limitations under the License.
  */
 
-import BaseMonitor from '../services/base';
-import { GradeTypeEnum } from '../services/constant';
-import { ErrorsCategory } from '../services/constant';
+import Base from '../services/base';
+import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
 
-class JSErrors extends BaseMonitor {
-  public handleErrors(options: {reportUrl: string}) {
+class JSErrors extends Base {
+  public handleErrors(options: {reportUrl: string; serviceName: string}) {
     window.onerror = (message, url, line, col, error) => {
+      this.reportUrl = options.reportUrl;
+      this.serviceName = options.serviceName;
       this.logInfo = {
-        reportUrl: options.reportUrl,
         category: ErrorsCategory.JS_ERROR,
         grade: GradeTypeEnum.ERROR,
         errorUrl: url,
diff --git a/src/errors/promise.ts b/src/errors/promise.ts
new file mode 100644
index 0000000..01d2209
--- /dev/null
+++ b/src/errors/promise.ts
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Base from '../services/base';
+import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+
+class PromiseErrors extends Base {
+  public handleErrors(options: {reportUrl: string; serviceName: string}) {
+    window.addEventListener('unhandledrejection', (event) => {
+      try {
+        let url = '';
+        if (!event || !event.reason) {
+          return;
+        }
+        this.reportUrl = options.reportUrl;
+        this.serviceName = options.serviceName;
+        if (event.reason.config && event.reason.config.url) {
+          url = event.reason.config.url;
+        }
+        this.logInfo = {
+          category: ErrorsCategory.PROMISE_ERROR,
+          grade: GradeTypeEnum.ERROR,
+          errorUrl: url,
+          message: event.reason,
+          errorInfo: event.reason,
+        };
+        this.traceInfo();
+      } catch (error) {
+        console.log(error);
+      }
+    });
+  }
+}
+export default new PromiseErrors();
diff --git a/src/monitor.ts b/src/monitor.ts
index b24faf0..a164606 100644
--- a/src/monitor.ts
+++ b/src/monitor.ts
@@ -14,11 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import JSErrors from './errors/jsErrors';
-import { TClientMonitor, TErrorsType } from './types';
+
+import { CustomOptionsType } from './types';
+import { JSErrors, PromiseErrors, AjaxErrors } from './errors/index';
 
 const ClientMonitor = {
-  errorTypes: {
+  customOptions: {
     jsErrors: true,
     promiseErrors: true,
     consoleErrors: false,
@@ -26,22 +27,26 @@
     reactErrors: false,
     ajaxErrors: true,
     resourceErrors: true,
-  } as TErrorsType,
+  } as CustomOptionsType,
 
-  register(options: TClientMonitor & TErrorsType) {
-    this.errorTypes = options;
-    if (this.errorTypes.jsErrors) {
-      this.errorTypes.jsErrors = options.jsErrors;
-      JSErrors.handleErrors({reportUrl: options.reportUrl});
+  register(options: CustomOptionsType) {
+    const { serviceName, reportUrl } = options;
+
+    this.customOptions = options;
+    if (this.customOptions.jsErrors) {
+      this.customOptions.jsErrors = options.jsErrors;
+      JSErrors.handleErrors({reportUrl, serviceName});
     }
-    if (this.errorTypes.promiseErrors) {
-      this.errorTypes.promiseErrors = options.promiseErrors || this.errorTypes.promiseErrors;
+    if (this.customOptions.promiseErrors) {
+      this.customOptions.promiseErrors = options.promiseErrors || this.customOptions.promiseErrors;
+      PromiseErrors.handleErrors({reportUrl, serviceName});
     }
-    if (this.errorTypes.resourceErrors) {
-      this.errorTypes.resourceErrors = options.resourceErrors;
+    if (this.customOptions.resourceErrors) {
+      this.customOptions.resourceErrors = options.resourceErrors;
     }
-    if (this.errorTypes.ajaxErrors) {
-      this.errorTypes.ajaxErrors = options.ajaxErrors || this.errorTypes.ajaxErrors;
+    if (this.customOptions.ajaxErrors) {
+      this.customOptions.ajaxErrors = options.ajaxErrors || this.customOptions.ajaxErrors;
+      AjaxErrors.handleError({reportUrl, serviceName});
     }
   },
 };
diff --git a/src/services/base.ts b/src/services/base.ts
index 5437912..fa655c9 100644
--- a/src/services/base.ts
+++ b/src/services/base.ts
@@ -18,8 +18,10 @@
 import { ErrorsCategory, GradeTypeEnum } from './constant';
 import { errorInfoFeilds } from './types';
 
-export default class BaseMonitor {
-  public logInfo: errorInfoFeilds & {reportUrl: string} = {
+export default class Base {
+  public reportUrl: string;
+  public serviceName: string;
+  public logInfo: errorInfoFeilds = {
     category: ErrorsCategory.UNKNOW_ERROR,
     grade: GradeTypeEnum.INFO,
     errorUrl: '',
@@ -27,7 +29,6 @@
     col: 0,
     errorInfo: '',
     message: '',
-    reportUrl: '',
   };
 
   public traceInfo() {
@@ -42,13 +43,13 @@
       if (!this.logInfo.message) {
         return;
       }
-      if (this.logInfo.reportUrl && this.logInfo.errorUrl &&
-        this.logInfo.errorUrl.toLowerCase().includes(this.logInfo.reportUrl.toLowerCase())) {
+      if (this.reportUrl && this.logInfo.errorUrl &&
+        this.logInfo.errorUrl.toLowerCase().includes(this.reportUrl.toLowerCase())) {
         return;
       }
       const errorInfo = this.handleErrorInfo();
 
-      Task.addTask(this.logInfo.reportUrl, errorInfo);
+      Task.addTask(this.reportUrl, errorInfo);
 
     } catch (error) {
       // console.log(error);
@@ -73,6 +74,10 @@
       ...this.logInfo,
       message,
     };
-    return recordInfo;
+    return {
+      errorLogs: recordInfo,
+      serviceName: this.serviceName,
+      reportUrl: this.reportUrl,
+    };
   }
 }
diff --git a/src/services/report.ts b/src/services/report.ts
index a6e080a..55ff209 100644
--- a/src/services/report.ts
+++ b/src/services/report.ts
@@ -27,14 +27,16 @@
     if (!this.checkUrl(this.url)) {
       return;
     }
+
+    delete data.reportUrl;
+    console.log(data);
     try {
       const xhr = new XMLHttpRequest();
       xhr.open('POST', this.url, true);
       xhr.setRequestHeader('Content-Type', 'application/json');
-      console.log(data);
       xhr.send(JSON.stringify(data));
     } catch (error) {
-    //   console.log(error);
+      console.log(error);
     }
   }
 
diff --git a/src/services/types.d.ts b/src/services/types.d.ts
index d296077..f1ae5a6 100644
--- a/src/services/types.d.ts
+++ b/src/services/types.d.ts
@@ -15,8 +15,7 @@
  * limitations under the License.
  */
 export interface TraceFields {
-  reportUrl: string;
-  serviceName?: string;
+  serviceName: string;
   errorInfo: errorInfoFeilds;
   performanceInfo?: performanceInfoFields;
   resources?: any;
@@ -38,7 +37,7 @@
   grade: string;
   message: any;
   errorUrl: string;
-  line: number; 
-  col: number;
-  errorInfo: any;
+  line?: number; 
+  col?: number;
+  errorInfo?: any;
 }
diff --git a/src/types.d.ts b/src/types.d.ts
index b7f6058..e916ee6 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -14,12 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-export interface TClientMonitor {
-  reportUrl: string;
-  modulesName?: string;
-}
 
-export interface TErrorsType {
+export interface CustomOptionsType {
+  reportUrl: string;
+  serviceName?: string;
   jsErrors: boolean;
   promiseErrors: boolean;
   consoleErrors: boolean;