New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introducing React Hooks for AppInsights #1120
Changes from 4 commits
b21b0df
9865f6e
0c68d6e
966526b
076a77f
c2144e5
123c0df
062160d
5d5eb14
9b9283a
9bcd6b2
de34258
e4dd2be
da47bbc
a2a59ee
617ed40
cbac445
54b5829
3a3599d
b34b66c
b6ebf91
dce63b7
3729221
7f3952d
23cfaa2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,53 @@ | ||
{ | ||
"name": "@microsoft/applicationinsights-react-js", | ||
"version": "2.3.1", | ||
"description": "Microsoft Application Insights React plugin", | ||
"main": "dist/applicationinsights-react-js.js", | ||
"module": "dist-esm/applicationinsights-react-js.js", | ||
"types": "types/applicationinsights-react-js.d.ts", | ||
"sideEffects": false, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/microsoft/ApplicationInsights-JS/tree/master/extensions/applicationinsights-react-js" | ||
}, | ||
"scripts": { | ||
"build": "npm run build:esm && npm run build:browser", | ||
"build:esm": "grunt react", | ||
"build:browser": "rollup -c", | ||
"test": "jest --config test/jestconfig.json", | ||
"test-watch": "jest --config test/jestconfig.json --watch", | ||
"lint": "tslint -p tsconfig.json" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "11.13.2", | ||
"@types/enzyme": "3.1.8", | ||
"@types/history": "4.7.2", | ||
"@types/react": "16.0.36", | ||
"@types/react-dom": "16.0.3", | ||
"@types/jest": "^24.0.11", | ||
"enzyme": "^3.9.0", | ||
"enzyme-adapter-react-16": "^1.12.1", | ||
"jest": "^24.7.1", | ||
"grunt": "1.0.1", | ||
"ts-jest": "^24.0.2", | ||
"react-dom": "^16.8.6", | ||
"rollup": "^0.66.0", | ||
"rollup-plugin-node-resolve": "^3.4.0", | ||
"rollup-plugin-replace": "^2.1.0", | ||
"rollup-plugin-uglify": "^6.0.0", | ||
"rollup-plugin-commonjs": "^9.3.4", | ||
"typescript": "2.5.3", | ||
"tslint": "^5.19.0", | ||
"tslint-config-prettier": "^1.18.0" | ||
}, | ||
"dependencies": { | ||
"@microsoft/applicationinsights-core-js": "2.3.1", | ||
"@microsoft/applicationinsights-common": "2.3.1", | ||
"tslib": "^1.9.3", | ||
"react": "^16.8.6", | ||
"history": "^4.9.0" | ||
}, | ||
"license": "MIT" | ||
"name": "@microsoft/applicationinsights-react-js", | ||
"version": "2.3.1", | ||
"description": "Microsoft Application Insights React plugin", | ||
"main": "dist/applicationinsights-react-js.js", | ||
"module": "dist-esm/applicationinsights-react-js.js", | ||
"types": "types/applicationinsights-react-js.d.ts", | ||
"sideEffects": false, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/microsoft/ApplicationInsights-JS/tree/master/extensions/applicationinsights-react-js" | ||
}, | ||
"scripts": { | ||
"build": "npm run build:esm && npm run build:browser", | ||
"build:esm": "grunt react", | ||
"build:browser": "rollup -c", | ||
"test": "jest --config test/jestconfig.json", | ||
"test-watch": "jest --config test/jestconfig.json --watch", | ||
"lint": "tslint -p tsconfig.json" | ||
}, | ||
"license": "MIT", | ||
"dependencies": { | ||
"@microsoft/applicationinsights-common": "2.3.1", | ||
"@microsoft/applicationinsights-core-js": "2.3.1", | ||
"history": "^4.9.0", | ||
"react": "^16.8.6", | ||
"tslib": "^1.9.3" | ||
}, | ||
"devDependencies": { | ||
"@types/enzyme": "3.1.8", | ||
"@types/history": "4.7.2", | ||
"@types/jest": "^24.0.11", | ||
"@types/node": "11.13.2", | ||
"@types/prop-types": "~15.7.3", | ||
"@types/react": "~16.9.11", | ||
"@types/react-dom": "~16.9.4", | ||
"csstype": "~2.6.7", | ||
"enzyme": "^3.9.0", | ||
"enzyme-adapter-react-16": "^1.12.1", | ||
"grunt": "1.0.1", | ||
"jest": "^24.7.1", | ||
"react-dom": "^16.8.6", | ||
"rollup": "^0.66.0", | ||
"rollup-plugin-commonjs": "^9.3.4", | ||
"rollup-plugin-node-resolve": "^3.4.0", | ||
"rollup-plugin-replace": "^2.1.0", | ||
"rollup-plugin-uglify": "^6.0.0", | ||
"ts-jest": "^24.0.2", | ||
"tslint": "^5.19.0", | ||
"tslint-config-prettier": "^1.18.0", | ||
"typescript": "2.5.3" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { createContext, useContext } from "react"; | ||
import ReactPlugin from "./ReactPlugin"; | ||
|
||
const AppInsightsContext = createContext<ReactPlugin>(undefined); | ||
|
||
const useAppInsightsContext = () => useContext(AppInsightsContext); | ||
|
||
export { AppInsightsContext, useAppInsightsContext }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/** | ||
* ReactPlugin.ts | ||
* @copyright Microsoft 2019 | ||
*/ | ||
import { useState, useEffect, useRef } from "react"; | ||
import ReactPlugin from "./ReactPlugin"; | ||
|
||
export default function useCustomEvent<T>( | ||
reactPlugin: ReactPlugin, | ||
eventName: string, | ||
eventData: T, | ||
skipFirstRun = true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aaronpowell do you mind explaining why this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @xiao-lix The reason is to mimic more closely the way the non-hook version works. With |
||
) { | ||
const [data, setData] = useState(eventData); | ||
const firstRun = useRef(skipFirstRun); | ||
|
||
useEffect(() => { | ||
if (firstRun.current) { | ||
firstRun.current = false; | ||
return; | ||
} | ||
reactPlugin.trackEvent({ name: eventName }, data); | ||
}, [reactPlugin, data, eventName]); | ||
|
||
return setData; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { useEffect, useRef } from "react"; | ||
import ReactPlugin from "./ReactPlugin"; | ||
|
||
interface ITrackedData { | ||
hookTimestamp: number; | ||
firstActiveTimestamp: number; | ||
totalIdleTime: number; | ||
lastActiveTimestamp: number; | ||
idleStartTimestamp: number; | ||
idleCount: number; | ||
idleTimeout: number; | ||
} | ||
|
||
function getEngagementTimeSeconds(trackedData: ITrackedData) { | ||
return ( | ||
(Date.now() - | ||
trackedData.firstActiveTimestamp - | ||
trackedData.totalIdleTime - | ||
trackedData.idleCount * trackedData.idleTimeout) / | ||
1000 | ||
); | ||
} | ||
|
||
const useComponentTracking = ( | ||
reactPlugin: ReactPlugin, | ||
componentName: string | ||
) => { | ||
const tracking = useRef<ITrackedData>({ | ||
hookTimestamp: Date.now(), | ||
firstActiveTimestamp: 0, | ||
totalIdleTime: 0, | ||
lastActiveTimestamp: 0, | ||
idleStartTimestamp: 0, | ||
idleCount: 0, | ||
idleTimeout: 5000 | ||
}); | ||
const savedCallback = useRef<() => void>(); | ||
|
||
const callback = () => { | ||
let trackedData = tracking.current; | ||
if ( | ||
trackedData.lastActiveTimestamp > 0 && | ||
trackedData.idleStartTimestamp === 0 && | ||
Date.now() - trackedData.lastActiveTimestamp >= trackedData.idleTimeout | ||
) { | ||
trackedData.idleStartTimestamp = Date.now(); | ||
trackedData.idleCount++; | ||
} | ||
}; | ||
const delay = 100; | ||
|
||
savedCallback.current = callback; | ||
|
||
// Set up the interval. | ||
useEffect(() => { | ||
let id = setInterval(savedCallback.current, delay); | ||
return () => { | ||
clearInterval(id); | ||
|
||
let trackedData = tracking.current; | ||
if (trackedData.hookTimestamp === 0) { | ||
throw new Error( | ||
"useAppInsights:unload hook: hookTimestamp is not initialized." | ||
); | ||
} | ||
|
||
if (trackedData.firstActiveTimestamp === 0) { | ||
return; | ||
} | ||
|
||
const engagementTime = getEngagementTimeSeconds(trackedData); | ||
const metricData = { | ||
average: engagementTime, | ||
name: "React Component Engaged Time (seconds)", | ||
sampleCount: 1 | ||
}; | ||
|
||
const additionalProperties = { "Component Name": componentName }; | ||
reactPlugin.trackMetric(metricData, additionalProperties); | ||
}; | ||
}, []); | ||
|
||
const trackActivity = () => { | ||
let trackedData = tracking.current; | ||
if (trackedData.firstActiveTimestamp === 0) { | ||
trackedData.firstActiveTimestamp = Date.now(); | ||
trackedData.lastActiveTimestamp = trackedData.firstActiveTimestamp; | ||
} else { | ||
trackedData.lastActiveTimestamp = Date.now(); | ||
} | ||
|
||
if (trackedData.idleStartTimestamp > 0) { | ||
const lastIdleTime = | ||
trackedData.lastActiveTimestamp - trackedData.idleStartTimestamp; | ||
trackedData.totalIdleTime += lastIdleTime; | ||
trackedData.idleStartTimestamp = 0; | ||
} | ||
}; | ||
|
||
return trackActivity; | ||
}; | ||
|
||
export default useComponentTracking; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this then becomes
this.diagLog().throwInternal(...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not seeing any other blocking issues apart from the intro of the _logger.
For references the diaLog() takes care of the this getting called before initialization() as well.