Extracting HOC tracked component class base for re-use (#1829)
* Extracting HOC tracked component class for re-use * addressing review comments Co-authored-by: Ladislav Bitto <labitto@microsoft.com> Co-authored-by: Nev <54870357+MSNev@users.noreply.github.com>
This commit is contained in:
Родитель
9d4e266421
Коммит
4391b212f8
|
@ -3,7 +3,7 @@
|
|||
|
||||
import { IReactExtensionConfig } from "./Interfaces/IReactExtensionConfig";
|
||||
import ReactPlugin from "./ReactPlugin";
|
||||
import withAITracking from "./withAITracking";
|
||||
import withAITracking, { AITrackedComponentBase } from "./withAITracking";
|
||||
import AppInsightsErrorBoundary from "./AppInsightsErrorBoundary"
|
||||
import {
|
||||
AppInsightsContext,
|
||||
|
@ -20,5 +20,6 @@ export {
|
|||
AppInsightsContext,
|
||||
useAppInsightsContext,
|
||||
useTrackEvent,
|
||||
useTrackMetric
|
||||
useTrackMetric,
|
||||
AITrackedComponentBase
|
||||
};
|
||||
|
|
|
@ -2,10 +2,92 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
import { IMetricTelemetry } from '@microsoft/applicationinsights-common';
|
||||
import { CoreUtils } from '@microsoft/applicationinsights-core-js';
|
||||
import { dateNow } from '@microsoft/applicationinsights-core-js';
|
||||
import * as React from 'react';
|
||||
import ReactPlugin from './ReactPlugin';
|
||||
|
||||
/**
|
||||
* Higher-order component base class to hook Application Insights tracking
|
||||
* in a React component's lifecycle.
|
||||
*/
|
||||
export abstract class AITrackedComponentBase<P> extends React.Component<P> {
|
||||
protected _mountTimestamp: number = 0;
|
||||
protected _firstActiveTimestamp: number = 0;
|
||||
protected _idleStartTimestamp: number = 0;
|
||||
protected _lastActiveTimestamp: number = 0;
|
||||
protected _totalIdleTime: number = 0;
|
||||
protected _idleCount: number = 0;
|
||||
protected _idleTimeout: number = 5000;
|
||||
protected _intervalId?: any;
|
||||
protected _componentName: string;
|
||||
protected _reactPlugin: ReactPlugin;
|
||||
|
||||
public constructor(props: P, reactPlugin: ReactPlugin, componentName: string) {
|
||||
super(props);
|
||||
|
||||
this._reactPlugin = reactPlugin;
|
||||
this._componentName = componentName;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this._mountTimestamp = dateNow();
|
||||
this._firstActiveTimestamp = 0;
|
||||
this._totalIdleTime = 0;
|
||||
this._lastActiveTimestamp = 0;
|
||||
this._idleStartTimestamp = 0;
|
||||
this._idleCount = 0;
|
||||
|
||||
this._intervalId = setInterval(() => {
|
||||
if (this._lastActiveTimestamp > 0 && this._idleStartTimestamp === 0 && dateNow() - this._lastActiveTimestamp >= this._idleTimeout) {
|
||||
this._idleStartTimestamp = dateNow();
|
||||
this._idleCount++;
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (this._mountTimestamp === 0) {
|
||||
throw new Error('withAITracking:componentWillUnmount: mountTimestamp is not initialized.');
|
||||
}
|
||||
if (this._intervalId) {
|
||||
clearInterval(this._intervalId);
|
||||
}
|
||||
|
||||
if (this._firstActiveTimestamp === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const engagementTime = this.getEngagementTimeSeconds();
|
||||
const metricData: IMetricTelemetry = {
|
||||
average: engagementTime,
|
||||
name: 'React Component Engaged Time (seconds)',
|
||||
sampleCount: 1
|
||||
};
|
||||
|
||||
const additionalProperties: { [key: string]: any } = { 'Component Name': this._componentName };
|
||||
this._reactPlugin.trackMetric(metricData, additionalProperties);
|
||||
}
|
||||
|
||||
protected trackActivity = (e: React.SyntheticEvent<any>): void => {
|
||||
if (this._firstActiveTimestamp === 0) {
|
||||
this._firstActiveTimestamp = dateNow();
|
||||
this._lastActiveTimestamp = this._firstActiveTimestamp;
|
||||
} else {
|
||||
this._lastActiveTimestamp = dateNow();
|
||||
}
|
||||
|
||||
if (this._idleStartTimestamp > 0) {
|
||||
const lastIdleTime = this._lastActiveTimestamp - this._idleStartTimestamp;
|
||||
this._totalIdleTime += lastIdleTime;
|
||||
this._idleStartTimestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private getEngagementTimeSeconds(): number {
|
||||
return (dateNow() - this._firstActiveTimestamp - this._totalIdleTime - this._idleCount * this._idleTimeout) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Higher-order component function to hook Application Insights tracking
|
||||
* in a React component's lifecycle.
|
||||
|
@ -18,63 +100,20 @@ import ReactPlugin from './ReactPlugin';
|
|||
export default function withAITracking<P>(reactPlugin: ReactPlugin, Component: React.ComponentType<P>, componentName?: string, className?: string): React.ComponentClass<P> {
|
||||
|
||||
if (componentName === undefined || componentName === null || typeof componentName !== 'string') {
|
||||
componentName = Component.prototype &&
|
||||
Component.prototype.constructor &&
|
||||
Component.prototype.constructor.name ||
|
||||
'Unknown';
|
||||
componentName = Component.prototype &&
|
||||
Component.prototype.constructor &&
|
||||
Component.prototype.constructor.name ||
|
||||
'Unknown';
|
||||
}
|
||||
|
||||
if (className === undefined || className === null || typeof className !== 'string') {
|
||||
className = '';
|
||||
}
|
||||
|
||||
return class extends React.Component<P> {
|
||||
private _mountTimestamp: number = 0;
|
||||
private _firstActiveTimestamp: number = 0;
|
||||
private _idleStartTimestamp: number = 0;
|
||||
private _lastActiveTimestamp: number = 0;
|
||||
private _totalIdleTime: number = 0;
|
||||
private _idleCount: number = 0;
|
||||
private _idleTimeout: number = 5000;
|
||||
private _intervalId?: any;
|
||||
return class extends AITrackedComponentBase<P> {
|
||||
|
||||
public componentDidMount() {
|
||||
this._mountTimestamp = CoreUtils.dateNow();
|
||||
this._firstActiveTimestamp = 0;
|
||||
this._totalIdleTime = 0;
|
||||
this._lastActiveTimestamp = 0;
|
||||
this._idleStartTimestamp = 0;
|
||||
this._idleCount = 0;
|
||||
|
||||
this._intervalId = setInterval(() => {
|
||||
if (this._lastActiveTimestamp > 0 && this._idleStartTimestamp === 0 && CoreUtils.dateNow() - this._lastActiveTimestamp >= this._idleTimeout) {
|
||||
this._idleStartTimestamp = CoreUtils.dateNow();
|
||||
this._idleCount++;
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (this._mountTimestamp === 0) {
|
||||
throw new Error('withAITracking:componentWillUnmount: mountTimestamp is not initialized.');
|
||||
}
|
||||
if (this._intervalId) {
|
||||
clearInterval(this._intervalId);
|
||||
}
|
||||
|
||||
if (this._firstActiveTimestamp === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const engagementTime = this.getEngagementTimeSeconds();
|
||||
const metricData: IMetricTelemetry = {
|
||||
average: engagementTime,
|
||||
name: 'React Component Engaged Time (seconds)',
|
||||
sampleCount: 1
|
||||
};
|
||||
|
||||
const additionalProperties: { [key: string]: any } = { 'Component Name': componentName };
|
||||
reactPlugin.trackMetric(metricData, additionalProperties);
|
||||
public constructor(props: P) {
|
||||
super(props, reactPlugin, componentName);
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
@ -92,24 +131,5 @@ export default function withAITracking<P>(reactPlugin: ReactPlugin, Component: R
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private trackActivity = (e: React.SyntheticEvent<any>): void => {
|
||||
if (this._firstActiveTimestamp === 0) {
|
||||
this._firstActiveTimestamp = CoreUtils.dateNow();
|
||||
this._lastActiveTimestamp = this._firstActiveTimestamp;
|
||||
} else {
|
||||
this._lastActiveTimestamp = CoreUtils.dateNow();
|
||||
}
|
||||
|
||||
if (this._idleStartTimestamp > 0) {
|
||||
const lastIdleTime = this._lastActiveTimestamp - this._idleStartTimestamp;
|
||||
this._totalIdleTime += lastIdleTime;
|
||||
this._idleStartTimestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private getEngagementTimeSeconds(): number {
|
||||
return (CoreUtils.dateNow() - this._firstActiveTimestamp - this._totalIdleTime - this._idleCount * this._idleTimeout) / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче