You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2022/04/26 11:29:02 UTC

[skywalking-client-js] branch master updated: feat: reset custom configurations when the page router changed for SPA (#86)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-client-js.git


The following commit(s) were added to refs/heads/master by this push:
     new 639731f  feat: reset custom configurations when the page router changed for SPA (#86)
639731f is described below

commit 639731fad4dc7bf1147640cc57a9d135a0315737
Author: Fine0830 <fi...@outlook.com>
AuthorDate: Tue Apr 26 19:28:58 2022 +0800

    feat: reset custom configurations when the page router changed for SPA (#86)
---
 src/errors/ajax.ts              | 16 ++++++++++++----
 src/errors/frames.ts            | 16 +++++++++-------
 src/errors/js.ts                | 16 ++++++++++++----
 src/errors/promise.ts           | 16 ++++++++++++----
 src/errors/resource.ts          | 20 ++++++++++++++------
 src/errors/vue.ts               | 19 ++++++++++++-------
 src/monitor.ts                  | 20 ++++++++++++++++++--
 src/trace/interceptors/fetch.ts | 39 ++++++++++++++++++---------------------
 src/trace/interceptors/xhr.ts   | 25 +++++++++++++++++--------
 src/trace/segment.ts            |  9 +++++++--
 10 files changed, 131 insertions(+), 65 deletions(-)

diff --git a/src/errors/ajax.ts b/src/errors/ajax.ts
index f2e2825..839f450 100644
--- a/src/errors/ajax.ts
+++ b/src/errors/ajax.ts
@@ -18,14 +18,21 @@
 import uuid from '../services/uuid';
 import Base from '../services/base';
 import { GradeTypeEnum, ErrorsCategory, ReportTypes } from '../services/constant';
+import { CustomReportOptions } from '../types';
 
 class AjaxErrors extends Base {
+  private infoOpt: CustomReportOptions = {
+    service: '',
+    pagePath: '',
+    serviceVersion: '',
+  };
   // get http error info
-  public handleError(options: { service: string; serviceVersion: string; pagePath: string; collector: string }) {
+  public handleError(options: CustomReportOptions) {
     // XMLHttpRequest Object
     if (!window.XMLHttpRequest) {
       return;
     }
+    this.infoOpt = options;
     window.addEventListener(
       'xhrReadyStateChange',
       (event: CustomEvent<XMLHttpRequest & { getRequestConfig: any[] }>) => {
@@ -42,10 +49,8 @@ class AjaxErrors extends Base {
         }
 
         this.logInfo = {
+          ...this.infoOpt,
           uniqueId: uuid(),
-          service: options.service,
-          serviceVersion: options.serviceVersion,
-          pagePath: options.pagePath,
           category: ErrorsCategory.AJAX_ERROR,
           grade: GradeTypeEnum.ERROR,
           errorUrl: detail.getRequestConfig[1],
@@ -57,6 +62,9 @@ class AjaxErrors extends Base {
       },
     );
   }
+  setOptions(opt: CustomReportOptions) {
+    this.infoOpt = opt;
+  }
 }
 
 export default new AjaxErrors();
diff --git a/src/errors/frames.ts b/src/errors/frames.ts
index 7471a8d..e8d2c75 100644
--- a/src/errors/frames.ts
+++ b/src/errors/frames.ts
@@ -18,17 +18,19 @@
 import uuid from '../services/uuid';
 import Base from '../services/base';
 import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+import { CustomReportOptions } from '../types';
 
 class FrameErrors extends Base {
-  public handleErrors(
-    options: { service: string; serviceVersion: string; pagePath: string; collector?: string },
-    error: Error,
-  ) {
+  private infoOpt: CustomReportOptions = {
+    service: '',
+    pagePath: '',
+    serviceVersion: '',
+  };
+  public handleErrors(options: CustomReportOptions, error: Error) {
+    this.infoOpt = options;
     this.logInfo = {
+      ...this.infoOpt,
       uniqueId: uuid(),
-      service: options.service,
-      serviceVersion: options.serviceVersion,
-      pagePath: options.pagePath,
       category: ErrorsCategory.JS_ERROR,
       grade: GradeTypeEnum.ERROR,
       errorUrl: error.name || location.href,
diff --git a/src/errors/js.ts b/src/errors/js.ts
index 9ff7f49..da00952 100644
--- a/src/errors/js.ts
+++ b/src/errors/js.ts
@@ -18,14 +18,19 @@
 import uuid from '../services/uuid';
 import Base from '../services/base';
 import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+import { CustomReportOptions } from '../types';
 class JSErrors extends Base {
-  public handleErrors(options: { service: string; serviceVersion: string; pagePath: string; collector: string }) {
+  private infoOpt: CustomReportOptions = {
+    service: '',
+    pagePath: '',
+    serviceVersion: '',
+  };
+  public handleErrors(options: CustomReportOptions) {
+    this.infoOpt = options;
     window.onerror = (message, url, line, col, error) => {
       this.logInfo = {
+        ...this.infoOpt,
         uniqueId: uuid(),
-        service: options.service,
-        serviceVersion: options.serviceVersion,
-        pagePath: options.pagePath,
         category: ErrorsCategory.JS_ERROR,
         grade: GradeTypeEnum.ERROR,
         errorUrl: url,
@@ -38,5 +43,8 @@ class JSErrors extends Base {
       this.traceInfo();
     };
   }
+  setOptions(opt: CustomReportOptions) {
+    this.infoOpt = opt;
+  }
 }
 export default new JSErrors();
diff --git a/src/errors/promise.ts b/src/errors/promise.ts
index fd46b70..543a9a1 100644
--- a/src/errors/promise.ts
+++ b/src/errors/promise.ts
@@ -18,9 +18,16 @@
 import uuid from '../services/uuid';
 import Base from '../services/base';
 import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+import { CustomReportOptions } from '../types';
 
 class PromiseErrors extends Base {
-  public handleErrors(options: { service: string; serviceVersion: string; pagePath: string; collector: string }) {
+  private infoOpt: CustomReportOptions = {
+    service: '',
+    pagePath: '',
+    serviceVersion: '',
+  };
+  public handleErrors(options: CustomReportOptions) {
+    this.infoOpt = options;
     window.addEventListener('unhandledrejection', (event) => {
       try {
         let url = '';
@@ -31,10 +38,8 @@ class PromiseErrors extends Base {
           url = event.reason.config.url;
         }
         this.logInfo = {
+          ...this.infoOpt,
           uniqueId: uuid(),
-          service: options.service,
-          serviceVersion: options.serviceVersion,
-          pagePath: options.pagePath,
           category: ErrorsCategory.PROMISE_ERROR,
           grade: GradeTypeEnum.ERROR,
           errorUrl: url || location.href,
@@ -48,5 +53,8 @@ class PromiseErrors extends Base {
       }
     });
   }
+  setOptions(opt: CustomReportOptions) {
+    this.infoOpt = opt;
+  }
 }
 export default new PromiseErrors();
diff --git a/src/errors/resource.ts b/src/errors/resource.ts
index 0cfbe50..206c8ef 100644
--- a/src/errors/resource.ts
+++ b/src/errors/resource.ts
@@ -18,15 +18,22 @@
 import uuid from '../services/uuid';
 import Base from '../services/base';
 import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+import { CustomReportOptions } from '../types';
 
 class ResourceErrors extends Base {
-  public handleErrors(options: { service: string; pagePath: string; serviceVersion: string; collector: string }) {
+  private infoOpt: CustomReportOptions = {
+    service: '',
+    pagePath: '',
+    serviceVersion: '',
+  };
+  public handleErrors(options: CustomReportOptions) {
+    this.infoOpt = options;
     window.addEventListener('error', (event) => {
       try {
         if (!event) {
           return;
         }
-        const target: any = event.target || event.srcElement;
+        const target: any = event.target;
         const isElementTarget =
           target instanceof HTMLScriptElement ||
           target instanceof HTMLLinkElement ||
@@ -37,13 +44,11 @@ class ResourceErrors extends Base {
           return;
         }
         this.logInfo = {
+          ...this.infoOpt,
           uniqueId: uuid(),
-          service: options.service,
-          serviceVersion: options.serviceVersion,
-          pagePath: options.pagePath,
           category: ErrorsCategory.RESOURCE_ERROR,
           grade: target.tagName === 'IMG' ? GradeTypeEnum.WARNING : GradeTypeEnum.ERROR,
-          errorUrl: target.src || target.href || location.href,
+          errorUrl: (target as HTMLScriptElement).src || (target as HTMLLinkElement).href || location.href,
           message: `load ${target.tagName} resource error`,
           collector: options.collector,
           stack: `load ${target.tagName} resource error`,
@@ -54,5 +59,8 @@ class ResourceErrors extends Base {
       }
     });
   }
+  setOptions(opt: CustomReportOptions) {
+    this.infoOpt = opt;
+  }
 }
 export default new ResourceErrors();
diff --git a/src/errors/vue.ts b/src/errors/vue.ts
index a1de936..2cf805c 100644
--- a/src/errors/vue.ts
+++ b/src/errors/vue.ts
@@ -18,19 +18,21 @@
 import uuid from '../services/uuid';
 import Base from '../services/base';
 import { GradeTypeEnum, ErrorsCategory } from '../services/constant';
+import { CustomReportOptions } from '../types';
 
 class VueErrors extends Base {
-  public handleErrors(
-    options: { service: string; pagePath: string; serviceVersion: string; collector: string },
-    Vue: any,
-  ) {
+  private infoOpt: CustomReportOptions = {
+    service: '',
+    pagePath: '',
+    serviceVersion: '',
+  };
+  public handleErrors(options: CustomReportOptions, Vue: any) {
+    this.infoOpt = options;
     Vue.config.errorHandler = (error: Error, vm: any, info: string) => {
       try {
         this.logInfo = {
+          ...this.infoOpt,
           uniqueId: uuid(),
-          service: options.service,
-          serviceVersion: options.serviceVersion,
-          pagePath: options.pagePath,
           category: ErrorsCategory.VUE_ERROR,
           grade: GradeTypeEnum.ERROR,
           errorUrl: location.href,
@@ -44,6 +46,9 @@ class VueErrors extends Base {
       }
     };
   }
+  setOptions(opt: CustomReportOptions) {
+    this.infoOpt = opt;
+  }
 }
 
 export default new VueErrors();
diff --git a/src/monitor.ts b/src/monitor.ts
index de8f949..6c12d7d 100644
--- a/src/monitor.ts
+++ b/src/monitor.ts
@@ -18,7 +18,7 @@
 import { CustomOptionsType, CustomReportOptions } from './types';
 import { JSErrors, PromiseErrors, AjaxErrors, ResourceErrors, VueErrors, FrameErrors } from './errors/index';
 import tracePerf from './performance/index';
-import traceSegment from './trace/segment';
+import traceSegment, { setConfig } from './trace/segment';
 
 const ClientMonitor = {
   customOptions: {
@@ -79,13 +79,29 @@ const ClientMonitor = {
       ResourceErrors.handleErrors({ service, pagePath, serviceVersion, collector });
     }
   },
-  setPerformance(configs: CustomOptionsType) {
+  setPerformance(configs: CustomReportOptions) {
     // history router
     this.customOptions = {
       ...this.customOptions,
       ...configs,
+      useFmp: false,
     };
     this.performance(this.customOptions);
+    const { service, pagePath, serviceVersion, collector } = this.customOptions;
+    if (this.customOptions.jsErrors) {
+      JSErrors.setOptions({ service, pagePath, serviceVersion, collector });
+      PromiseErrors.setOptions({ service, pagePath, serviceVersion, collector });
+      if (this.customOptions.vue) {
+        VueErrors.setOptions({ service, pagePath, serviceVersion, collector });
+      }
+    }
+    if (this.customOptions.apiErrors) {
+      AjaxErrors.setOptions({ service, pagePath, serviceVersion, collector });
+    }
+    if (this.customOptions.resourceErrors) {
+      ResourceErrors.setOptions({ service, pagePath, serviceVersion, collector });
+    }
+    setConfig(this.customOptions);
   },
   reportFrameErrors(configs: CustomReportOptions, error: Error) {
     FrameErrors.handleErrors(configs, error);
diff --git a/src/trace/interceptors/fetch.ts b/src/trace/interceptors/fetch.ts
index 90eabe4..bc231e8 100644
--- a/src/trace/interceptors/fetch.ts
+++ b/src/trace/interceptors/fetch.ts
@@ -19,17 +19,11 @@ import uuid from '../../services/uuid';
 import { SegmentFields, SpanFields } from '../type';
 import { CustomOptionsType } from '../../types';
 import Base from '../../services/base';
-import {
-  ComponentId,
-  ReportTypes,
-  SpanLayer,
-  SpanType,
-  ErrorsCategory,
-  GradeTypeEnum,
-} from '../../services/constant';
-
+import { ComponentId, ReportTypes, SpanLayer, SpanType, ErrorsCategory, GradeTypeEnum } from '../../services/constant';
+let customConfig: any = {};
 export default function windowFetch(options: CustomOptionsType, segments: SegmentFields[]) {
   const originFetch: any = window.fetch;
+  setFetchOptions(options);
 
   window.fetch = async (...args: any) => {
     const startTime = new Date().getTime();
@@ -37,9 +31,9 @@ export default function windowFetch(options: CustomOptionsType, segments: Segmen
     const traceSegmentId = uuid();
     let segment = {
       traceId: '',
-      service: options.service,
+      service: customConfig.service,
       spans: [],
-      serviceInstance: options.serviceVersion,
+      serviceInstance: customConfig.serviceVersion,
       traceSegmentId: '',
     } as SegmentFields;
     let url = {} as URL;
@@ -53,7 +47,7 @@ export default function windowFetch(options: CustomOptionsType, segments: Segmen
       url.pathname = args[0];
     }
 
-    const noTraceOrigins = options.noTraceOrigins.some((rule: string | RegExp) => {
+    const noTraceOrigins = customConfig.noTraceOrigins.some((rule: string | RegExp) => {
       if (typeof rule === 'string') {
         if (rule === url.origin) {
           return true;
@@ -64,18 +58,18 @@ export default function windowFetch(options: CustomOptionsType, segments: Segmen
         }
       }
     });
-    const cURL = new URL(options.collector);
+    const cURL = new URL(customConfig.collector);
     const pathname = cURL.pathname === '/' ? url.pathname : url.pathname.replace(new RegExp(`^${cURL.pathname}`), '');
     const internals = [ReportTypes.ERROR, ReportTypes.ERRORS, ReportTypes.PERF, ReportTypes.SEGMENTS] as string[];
     const isSDKInternal = internals.includes(pathname);
-    const hasTrace = !noTraceOrigins || (isSDKInternal && options.traceSDKInternal);
+    const hasTrace = !noTraceOrigins || (isSDKInternal && customConfig.traceSDKInternal);
 
     if (hasTrace) {
       const traceIdStr = String(encode(traceId));
       const segmentId = String(encode(traceSegmentId));
       const service = String(encode(segment.service));
       const instance = String(encode(segment.serviceInstance));
-      const endpoint = String(encode(options.pagePath));
+      const endpoint = String(encode(customConfig.pagePath));
       const peer = String(encode(url.host));
       const index = segment.spans.length;
       const values = `${1}-${traceIdStr}-${segmentId}-${index}-${service}-${instance}-${endpoint}-${peer}`;
@@ -95,14 +89,14 @@ export default function windowFetch(options: CustomOptionsType, segments: Segmen
       if (response && (response.status === 0 || response.status >= 400)) {
         const logInfo = {
           uniqueId: uuid(),
-          service: options.service,
-          serviceVersion: options.serviceVersion,
-          pagePath: options.pagePath,
+          service: customConfig.service,
+          serviceVersion: customConfig.serviceVersion,
+          pagePath: customConfig.pagePath,
           category: ErrorsCategory.AJAX_ERROR,
           grade: GradeTypeEnum.ERROR,
           errorUrl: (response && response.url) || `${url.protocol}//${url.host}${url.pathname}`,
           message: `status: ${response ? response.status : 0}; statusText: ${response && response.statusText};`,
-          collector: options.collector,
+          collector: customConfig.collector,
           stack: 'Fetch: ' + response && response.statusText,
         };
         new Base().traceInfo(logInfo);
@@ -110,7 +104,7 @@ export default function windowFetch(options: CustomOptionsType, segments: Segmen
       if (hasTrace) {
         const endTime = new Date().getTime();
         const exitSpan: SpanFields = {
-          operationName: options.pagePath,
+          operationName: customConfig.pagePath,
           startTime: startTime,
           endTime,
           spanId: segment.spans.length,
@@ -120,7 +114,7 @@ export default function windowFetch(options: CustomOptionsType, segments: Segmen
           parentSpanId: segment.spans.length - 1,
           componentId: ComponentId,
           peer: url.host,
-          tags: options.detailMode
+          tags: customConfig.detailMode
             ? [
                 {
                   key: 'http.method',
@@ -147,3 +141,6 @@ export default function windowFetch(options: CustomOptionsType, segments: Segmen
     return response.clone();
   };
 }
+export function setFetchOptions(opt: CustomOptionsType) {
+  customConfig = { ...customConfig, ...opt };
+}
diff --git a/src/trace/interceptors/xhr.ts b/src/trace/interceptors/xhr.ts
index ec2e627..8074f0b 100644
--- a/src/trace/interceptors/xhr.ts
+++ b/src/trace/interceptors/xhr.ts
@@ -20,11 +20,17 @@ import { encode } from 'js-base64';
 import { CustomOptionsType } from '../../types';
 import { SegmentFields, SpanFields } from '../type';
 
+let customConfig: CustomOptionsType | any = {};
 export default function xhrInterceptor(options: CustomOptionsType, segments: SegmentFields[]) {
+  setOptions(options);
   const originalXHR = window.XMLHttpRequest as any;
   const xhrSend = XMLHttpRequest.prototype.send;
   const xhrOpen = XMLHttpRequest.prototype.open;
 
+  if (!(xhrSend && xhrOpen)) {
+    console.error('Tracing is not supported');
+    return;
+  }
   originalXHR.getRequestConfig = [];
 
   function ajaxEventTrigger(event: string) {
@@ -69,9 +75,9 @@ export default function xhrInterceptor(options: CustomOptionsType, segments: Seg
   window.addEventListener('xhrReadyStateChange', (event: CustomEvent<XMLHttpRequest & { getRequestConfig: any[] }>) => {
     let segment = {
       traceId: '',
-      service: options.service,
+      service: customConfig.service,
       spans: [],
-      serviceInstance: options.serviceVersion,
+      serviceInstance: customConfig.serviceVersion,
       traceSegmentId: '',
     } as SegmentFields;
     const xhrState = event.detail.readyState;
@@ -86,7 +92,7 @@ export default function xhrInterceptor(options: CustomOptionsType, segments: Seg
       url.pathname = config[1];
     }
 
-    const noTraceOrigins = options.noTraceOrigins.some((rule: string | RegExp) => {
+    const noTraceOrigins = customConfig.noTraceOrigins.some((rule: string | RegExp) => {
       if (typeof rule === 'string') {
         if (rule === url.origin) {
           return true;
@@ -101,12 +107,12 @@ export default function xhrInterceptor(options: CustomOptionsType, segments: Seg
       return;
     }
 
-    const cURL = new URL(options.collector);
+    const cURL = new URL(customConfig.collector);
     const pathname = cURL.pathname === '/' ? url.pathname : url.pathname.replace(new RegExp(`^${cURL.pathname}`), '');
     const internals = [ReportTypes.ERROR, ReportTypes.ERRORS, ReportTypes.PERF, ReportTypes.SEGMENTS] as string[];
     const isSDKInternal = internals.includes(pathname);
 
-    if (isSDKInternal && !options.traceSDKInternal) {
+    if (isSDKInternal && !customConfig.traceSDKInternal) {
       return;
     }
 
@@ -126,7 +132,7 @@ export default function xhrInterceptor(options: CustomOptionsType, segments: Seg
       const segmentId = String(encode(traceSegmentId));
       const service = String(encode(segment.service));
       const instance = String(encode(segment.serviceInstance));
-      const endpoint = String(encode(options.pagePath));
+      const endpoint = String(encode(customConfig.pagePath));
       const peer = String(encode(url.host));
       const index = segment.spans.length;
       const values = `${1}-${traceIdStr}-${segmentId}-${index}-${service}-${instance}-${endpoint}-${peer}`;
@@ -144,7 +150,7 @@ export default function xhrInterceptor(options: CustomOptionsType, segments: Seg
           }
 
           const exitSpan: SpanFields = {
-            operationName: options.pagePath,
+            operationName: customConfig.pagePath,
             startTime: segCollector[i].startTime,
             endTime,
             spanId: segment.spans.length,
@@ -154,7 +160,7 @@ export default function xhrInterceptor(options: CustomOptionsType, segments: Seg
             parentSpanId: segment.spans.length - 1,
             componentId: ComponentId,
             peer: responseURL.host,
-            tags: options.detailMode
+            tags: customConfig.detailMode
               ? [
                   {
                     key: 'http.method',
@@ -180,3 +186,6 @@ export default function xhrInterceptor(options: CustomOptionsType, segments: Seg
     }
   });
 }
+export function setOptions(opt: CustomOptionsType) {
+  customConfig = { ...customConfig, ...opt };
+}
diff --git a/src/trace/segment.ts b/src/trace/segment.ts
index 1a3d072..b8ea454 100644
--- a/src/trace/segment.ts
+++ b/src/trace/segment.ts
@@ -15,8 +15,8 @@
  * limitations under the License.
  */
 
-import xhrInterceptor from './interceptors/xhr';
-import windowFetch from './interceptors/fetch';
+import xhrInterceptor, { setOptions } from './interceptors/xhr';
+import windowFetch, { setFetchOptions } from './interceptors/fetch';
 import Report from '../services/report';
 import { SegmentFields } from './type';
 import { CustomOptionsType } from '../types';
@@ -41,3 +41,8 @@ export default function traceSegment(options: CustomOptionsType) {
     segments.splice(0, segments.length);
   }, options.traceTimeInterval);
 }
+
+export function setConfig(opt: CustomOptionsType) {
+  setOptions(opt);
+  setFetchOptions(opt);
+}