-
Notifications
You must be signed in to change notification settings - Fork 754
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
Added App Insights instrumentation. #1251
Conversation
@@ -80,8 +81,10 @@ export function* getArmToken( | |||
PersistAzureLoginChanged, | |||
persistLogin | |||
); | |||
CommandServiceImpl.remoteCall(TrackEvent, 'signIn_success'); |
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.
These remote calls should probably be yielded so exceptions can be handled.
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.
What would the caller want to do in the case of an error? I would actually expect this to not throw an error because we wouldn't want the app to crash or become degraded just because we failed to track an event.
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 have put code into the TelemetryService
that will swallow any exception thrown by the Application Insights sdk because like Andy, I don't think the app should crash when we fail to collect data.
I didn't want to synchronously execute TrackEvent
for the same reason. I believe tracking events should be more of a "background process."
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.
However, the command service could still throw, so would adding a catch like this to each of the command calls to TrackEvent
be sufficient?
commandService.remoteCall(TrackEvent, ...).catch(e => void 0);
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.
That seems reasonable to me. I think your reasoning is solid about not needing to wait for the telemetry as well.
packages/app/client/src/ui/editor/emulator/parts/inspector/inspectorContainer.ts
Show resolved
Hide resolved
@@ -80,8 +81,10 @@ export function* getArmToken( | |||
PersistAzureLoginChanged, | |||
persistLogin | |||
); | |||
CommandServiceImpl.remoteCall(TrackEvent, 'signIn_success'); |
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.
What would the caller want to do in the case of an error? I would actually expect this to not throw an error because we wouldn't want the app to crash or become degraded just because we failed to track an event.
private onChangeCollectUsageData = (): void => { | ||
this.setUncommittedState({ | ||
collectUsageData: !this.state.uncommitted.collectUsageData, | ||
}); |
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.
This has the potential of getting out of sync with state. Not sure how to approach given that setUncommittedState
only accepts an object. In any case, probably not a huge problem unless someone spams the checkbox.
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.
Your first comment echoes what I was thinking. I thought it would be best if the app would avoid crashing if something failed while trying to track telemetry. However, I still believe the error should be swallowed inside of the TelemetryService
so that it doesn't bubble up to the Command Service and become uncaught.
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.
Re: second comment
What would be a better pattern?
Pass the event into the handler and read the checked
value of the element?
Currently all the checkboxes in AppSettingsEditor
use this same pattern, but I'm open to changing them to one that is more reliable and wouldn't be at risk of falling out of sync.
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.
This can be:
const state = Object.create({}, {
collectUsageData: {
get: () => !this.state.uncommitted.collectUsageData,
enumerable: true // important since rest spread is used.
}
}):
this.setUncommittedState(state);
Which will read from the state at the moment the getter is invoked.
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.
That suggestion might be a little too complex. I think in general, the better approach would be to refactor the setUncommittedState
method to allow an updater function instead that gets invoked with previous state. But as I said, I don't think it will be an issue in this case unless someone spams the checkbox.
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've gone with a refactor including Justin's suggestion for now. However, I think we could investigate your approach down the road because we need to refactor AppSettingsEditor.tsx
anyway and write a test for it, which ideally would be done at the same time.
@@ -56,6 +56,7 @@ export interface LogEntryProps { | |||
setInspectorObjects?: (...args: any[]) => void; | |||
reconnectNgrok?: () => void; | |||
showAppSettings?: () => void; | |||
trackEvent?: (name: string, properties?: { [key: string]: any }) => void; |
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.
Maybe we should just add a type for trackEvent
?
|
||
import { getSettings } from '../settingsData/store'; | ||
|
||
const INSTRUMENTATION_KEY = '631faf57-1d84-40b4-9a71-fce28a3934a8'; |
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.
Is this secret?
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.
It is the key that allows anybody to post events to our App Insights instance, yes. I've spoken to the Azure CLI team about how they implemented instrumentation and they expose the key to the public in the same manner.
There is an email thread I can forward to you if you're interested, but basically the rationale behind it is this:
- This does not increase exposure to DDoS attacks, because even if we abstracted the key, someone could write a script or use an auto clicker to perform some instrumented action in the Emulator and hammer our App Insights instance if they wanted to.
- Internal data is not exposed in any way through this key. This only gives the ability to push data into the App Insights instance.
- We can just scrub and throw away bad / garbage events
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.
That's fine with me. Just checking.
Is there a common place for config values such as this? If not, we may consider creating one. Even a config package. No need to update if not, but something to keep in mind. (I can think of a few other things that could live in that module as well)
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.
No official config file as far as I know. We do have a .env
file in the root for using Travis, but that's about as close as it gets.
// turn off extra instrmentation | ||
.setAutoCollectConsole(false) | ||
.setAutoCollectDependencies(false) | ||
.setAutoCollectExceptions(false) |
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.
This one could be interesting. Why do we not want to collect exceptions?
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 just read the docs and it looks like this tracks all uncaught exceptions to App Insights. I don't really see a reason why we shouldn't collect these, but it is out of scope for the instrumentation spec. We can always flip the flag down the road.
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.
👍
d49cc6e
to
f31be94
Compare
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.
bc85ff0
to
02294b6
Compare
02294b6
to
43ba5dc
Compare
Addresses #1083
===
This PR adds Instrumentation to the Emulator that will track usage to an App Insights instance. The events being tracked are outlined in the internal document.