Merge pull request #3 from Fine0830/feat-monitor
Feat: add report ways and support JS errors
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..564fb76
--- /dev/null
+++ b/index.js
@@ -0,0 +1,20 @@
+/**
+ * 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 './src/index';
+
+export default ClientMonitor;
diff --git a/package.json b/package.json
index 3e7f1c5..8efbe41 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,8 @@
{
"name": "skywalking-client-js",
- "version": "1.0.0",
+ "version": "0.1.0",
"description": "js monitor",
- "main": "index.js",
- "author": "Qiuxia Fan",
- "license": "MIT",
+ "main": "dist/index.js",
"dependencies": {
"clean-webpack-plugin": "3.0.0",
"express": "^4.17.1",
diff --git a/server.js b/server.js
index c2f6683..345cf7e 100644
--- a/server.js
+++ b/server.js
@@ -1,34 +1,35 @@
/**
-* 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.
-*/
-const express = require('express');
-const webpack = require('webpack');
-const webpackDevMiddleware = require('webpack-dev-middleware');
+ * 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.
+ */
+const express = require("express");
+const webpack = require("webpack");
+const webpackDevMiddleware = require("webpack-dev-middleware");
const app = express();
-const config = require('./webpack.config.js');
+const config = require("./webpack.config.js");
const compiler = webpack(config);
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
-app.use(webpackDevMiddleware(compiler, {
- publicPath: config.output.publicPath
-}));
-
+app.use(
+ webpackDevMiddleware(compiler, {
+ publicPath: config.output.publicPath
+ })
+);
// Serve the files on port 3000.
-app.listen(3000, function () {
- console.log('Example app listening on port 3000!\n');
-});
\ No newline at end of file
+app.listen(3000, function() {
+ console.log("Example app listening on port 3000!\n");
+});
diff --git a/src/errors/jsErrors.ts b/src/errors/jsErrors.ts
new file mode 100644
index 0000000..cb7756d
--- /dev/null
+++ b/src/errors/jsErrors.ts
@@ -0,0 +1,39 @@
+/**
+ * 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 BaseMonitor from '../services/base';
+import { GradeTypeEnum } from '../services/constant';
+import { ErrorsCategory } from '../services/constant';
+
+class JSErrors extends BaseMonitor {
+ public handleErrors(options: {reportUrl: string}) {
+ window.onerror = (message, url, line, col, error) => {
+ this.logInfo = {
+ reportUrl: options.reportUrl,
+ category: ErrorsCategory.JS_ERROR,
+ grade: GradeTypeEnum.ERROR,
+ errorUrl: url,
+ line,
+ col,
+ errorInfo: error,
+ message,
+ };
+ this.traceInfo();
+ };
+ }
+}
+export default new JSErrors();
diff --git a/src/monitor.ts b/src/monitor.ts
index c84030c..b24faf0 100644
--- a/src/monitor.ts
+++ b/src/monitor.ts
@@ -14,10 +14,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import JSErrors from './errors/jsErrors';
+import { TClientMonitor, TErrorsType } from './types';
-export default class ClientMonitor {
+const ClientMonitor = {
+ errorTypes: {
+ jsErrors: true,
+ promiseErrors: true,
+ consoleErrors: false,
+ vueErrors: false,
+ reactErrors: false,
+ ajaxErrors: true,
+ resourceErrors: true,
+ } as TErrorsType,
- public init() {
- // console.log('enter');
- }
-}
+ register(options: TClientMonitor & TErrorsType) {
+ this.errorTypes = options;
+ if (this.errorTypes.jsErrors) {
+ this.errorTypes.jsErrors = options.jsErrors;
+ JSErrors.handleErrors({reportUrl: options.reportUrl});
+ }
+ if (this.errorTypes.promiseErrors) {
+ this.errorTypes.promiseErrors = options.promiseErrors || this.errorTypes.promiseErrors;
+ }
+ if (this.errorTypes.resourceErrors) {
+ this.errorTypes.resourceErrors = options.resourceErrors;
+ }
+ if (this.errorTypes.ajaxErrors) {
+ this.errorTypes.ajaxErrors = options.ajaxErrors || this.errorTypes.ajaxErrors;
+ }
+ },
+};
+
+export default ClientMonitor;
diff --git a/src/services/base.ts b/src/services/base.ts
new file mode 100644
index 0000000..5437912
--- /dev/null
+++ b/src/services/base.ts
@@ -0,0 +1,78 @@
+/**
+ * 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 Task from './task';
+import { ErrorsCategory, GradeTypeEnum } from './constant';
+import { errorInfoFeilds } from './types';
+
+export default class BaseMonitor {
+ public logInfo: errorInfoFeilds & {reportUrl: string} = {
+ category: ErrorsCategory.UNKNOW_ERROR,
+ grade: GradeTypeEnum.INFO,
+ errorUrl: '',
+ line: 0,
+ col: 0,
+ errorInfo: '',
+ message: '',
+ reportUrl: '',
+ };
+
+ public traceInfo() {
+ this.handleRecordError();
+ setTimeout(() => {
+ Task.fireTasks();
+ }, 100);
+ }
+
+ private handleRecordError() {
+ try {
+ if (!this.logInfo.message) {
+ return;
+ }
+ if (this.logInfo.reportUrl && this.logInfo.errorUrl &&
+ this.logInfo.errorUrl.toLowerCase().includes(this.logInfo.reportUrl.toLowerCase())) {
+ return;
+ }
+ const errorInfo = this.handleErrorInfo();
+
+ Task.addTask(this.logInfo.reportUrl, errorInfo);
+
+ } catch (error) {
+ // console.log(error);
+ }
+ }
+
+ private handleErrorInfo() {
+ let message = `error category:${this.logInfo.category}\r\n log info:${this.logInfo.message}\r\n
+ error url: ${this.logInfo.errorUrl}\r\n `;
+ switch (this.logInfo.category) {
+ case ErrorsCategory.JS_ERROR:
+ message += `error line number: ${this.logInfo.line}\r\n error col number:${this.logInfo.col}\r\n`;
+ if (this.logInfo.errorInfo && this.logInfo.errorInfo.stack) {
+ message += `error stack: ${this.logInfo.errorInfo.stack}\r\n`;
+ }
+ break;
+ default:
+ message += `other error: ${this.logInfo.errorInfo}\r\n`;
+ break;
+ }
+ const recordInfo = {
+ ...this.logInfo,
+ message,
+ };
+ return recordInfo;
+ }
+}
diff --git a/src/services/constant.ts b/src/services/constant.ts
new file mode 100644
index 0000000..8a1b711
--- /dev/null
+++ b/src/services/constant.ts
@@ -0,0 +1,33 @@
+/**
+ * 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.
+ */
+export enum ErrorsCategory {
+ AJAX_ERROR = 'ajaxError',
+ RESOURCE_ERROR = 'resourceError',
+ VUE_ERROR = 'vueError',
+ PROMISE_ERROR = 'promiseError',
+ JS_ERROR = 'jsError',
+ CONSOLE_INFO = 'consoleInfo',
+ CONSOLE_WARN = 'consoleWarn',
+ CONSOLE_ERROR = 'consoleError',
+ CROSS_SCRIPT_ERROR = 'crossSrciptError',
+ UNKNOW_ERROR = 'unknowError',
+}
+export enum GradeTypeEnum {
+ INFO = 'Info',
+ WARNING = 'Warning',
+ ERROR = 'Error',
+}
diff --git a/src/services/report.ts b/src/services/report.ts
new file mode 100644
index 0000000..a6e080a
--- /dev/null
+++ b/src/services/report.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.
+ */
+
+class Report {
+
+ private url: string = '';
+
+ constructor(url: string) {
+ this.url = url;
+ }
+
+ public sendByXhr(data: any) {
+ if (!this.checkUrl(this.url)) {
+ return;
+ }
+ 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);
+ }
+ }
+
+ private reportByImg(data: any) {
+ if (!this.checkUrl(this.url)) {
+ return;
+ }
+ try {
+ const imgObj = new Image();
+
+ imgObj.src = `${this.url}?v=${new Date().getTime()}&${this.formatParams(data)}`;
+ } catch (error) {
+ // console.log(error);
+ }
+ }
+
+ private formatParams(data: any) {
+ return Object.keys(data).map((name: string) =>
+ `${encodeURIComponent(name)}=${encodeURIComponent(data[name])}`,
+ ).join('&');
+ }
+
+ private checkUrl(url: string) {
+ if (!url) {
+ return;
+ }
+ const urlRule = /^[hH][tT][tT][pP]([sS]?):\/\//;
+ return urlRule.test(url);
+ }
+}
+export default Report;
diff --git a/src/services/task.ts b/src/services/task.ts
new file mode 100644
index 0000000..4f51a17
--- /dev/null
+++ b/src/services/task.ts
@@ -0,0 +1,39 @@
+/**
+ * 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 Report from './report';
+
+class TaskQueue {
+ private queues: any[] = [];
+
+ public addTask(reportUrl: string, data: any) {
+ this.queues.push({reportUrl, data});
+ }
+
+ public fireTasks() {
+ if (!this.queues || !this.queues.length) {
+ return;
+ }
+ const item = this.queues[0];
+ if (item.reportUrl) {
+ new Report(item.reportUrl).sendByXhr(item.data);
+ }
+ this.queues.splice(0, 1);
+ this.fireTasks();
+ }
+}
+
+export default new TaskQueue();
diff --git a/src/services/types.d.ts b/src/services/types.d.ts
new file mode 100644
index 0000000..d296077
--- /dev/null
+++ b/src/services/types.d.ts
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+export interface TraceFields {
+ reportUrl: string;
+ serviceName?: string;
+ errorInfo: errorInfoFeilds;
+ performanceInfo?: performanceInfoFields;
+ resources?: any;
+ pageId?: string;
+ deviceInfo?: any;
+}
+export interface performanceInfoFields {
+ redirectTime: string;
+ dnsTime: string;
+ reqTime: string;
+ analysisTime: string;
+ blankTime: string;
+ domReadyTime: string;
+ loadPage: string;
+}
+
+export interface errorInfoFeilds {
+ category: string;
+ grade: string;
+ message: any;
+ errorUrl: string;
+ line: number;
+ col: number;
+ errorInfo: any;
+}
diff --git a/src/types.d.ts b/src/types.d.ts
new file mode 100644
index 0000000..b7f6058
--- /dev/null
+++ b/src/types.d.ts
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ */
+export interface TClientMonitor {
+ reportUrl: string;
+ modulesName?: string;
+}
+
+export interface TErrorsType {
+ jsErrors: boolean;
+ promiseErrors: boolean;
+ consoleErrors: boolean;
+ vueErrors: boolean;
+ reactErrors: boolean;
+ ajaxErrors: boolean;
+ resourceErrors: boolean;
+}
diff --git a/webpack.config.js b/webpack.config.js
index b37677e..812f1d0 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -35,7 +35,7 @@
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
- filename: 'monitor.js',
+ filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},