Open davallen opened 3 years ago
Yes you can, as long as all of the subscription(s) all end up in the same region (and therefore get sent to the same location -- without the server sending service side redirects).
Then there are 2 simple methods
evt.iKey = "xxx"
)instrumentationKey
provided during initialization. Soooo, you could "replace" the telemetryItem.iKey
value with the value you want (probably based on some other value that you temporarily assign to the telemetry item -- sort of like setting the iKey above)What this doesn't do for you is that all of the automatic events (PageView, Instrumented XHR or fetch) requests etc will still use be assigned the default instrumentationKey and these will only get sent once (which is fine -- most of the time, except for maybe the Page view for different subscriptions). For the ajax (XHR, fetch) dependency calls this is where the telemetryInitializer option would work better as you can switch the iKey based on the URL.
Another option
You can create "multiple" appInsights instances and use them directly, this is easiest when consuming via the NPM so that all teams could use the same code and just create multiple instances, but it can also be done via the snippet loader you would need multiple "snippets" with each one defining it's own configuration and each with their own INSTRUMENTATION_KEY
AND also specifying the name
config value which will assign the global instance (on window) to this name and then each team would have their own instances.
So the following will create 2 global objects window.team1AppInsights and window.team2AppInsights
<script type="text/javascript">
!function(T,l,y){<!-- Removed the Snippet code for brevity -->}(window,document,{
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
crossOrigin: "anonymous",
onInit: function (sdk) {
sdk.addTelemetryInitializer(function (envelope) {
envelope.data.someField = 'This item passed through my telemetry initializer';
});
}, // Once the application insights instance has loaded and initialized this method will be called
name: "team1AppInsights",
cfg: { // Application Insights Configuration
instrumentationKey: "YOUR_INSTRUMENTATION_KEY - TEAM1"
}});
</script>
<script type="text/javascript">
!function(T,l,y){<!-- Removed the Snippet code for brevity -->}(window,document,{
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
crossOrigin: "anonymous",
onInit: function (sdk) {
sdk.addTelemetryInitializer(function (envelope) {
envelope.data.someField = 'This item passed through my telemetry initializer';
});
}, // Once the application insights instance has loaded and initialized this method will be called
name: "team2AppInsights",
cfg: { // Application Insights Configuration
instrumentationKey: "YOUR_INSTRUMENTATION_KEY - TEAM2"
}});
</script>
Note: I've not tried this recently, so if you encounter an issue with this let us know as that would be considered a bug.
Just fixed up the "location" of the name config in the above as it should be at the same level as cfg (doh!) just as is documented in the main readme https://github.com/Microsoft/ApplicationInsights-JS#snippet-setup-ignore-if-using-npm-setup
@MSNev I've been trying to achieve the same thing and took your suggestion and other various approaches but with no success:
My first attempt was having 2 global instances as you mentioned and call them separately but this didn't work as expected and only logged it to one of the instances. Apparently the last one that is defined in the HTML is the only one that works as I switched them around and now the instance that was not getting logged, was getting logged, and the other didn't log anymore.
I've also tried refactoring the 2 global objects as not to need to have to duplicate the whole js snippet by converting it to NOT be IIFE ( Immediately invoked function expression ) and instead assign it to a variable so I could call it multiple times with different config objects:
const aiConfig1 = {
name: 'appInsights',
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js", crossOrigin: "",
cfg: {instrumentationKey: instrumentationKey, disableAjaxTracking: true}
};
const aiConfig2 = {
name: 'appInsightsSecondary',
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js", crossOrigin: "",
cfg: {instrumentationKey: instrumentationKeySec, disableAjaxTracking: true}
};
const appInsightsInit= function(T,l,y){<!-- Removed the Snippet code for brevity -->} ):a()};
appInsightsInit(window, document, aiConfig1);
appInsightsInit(window, document, aiConfig2);
This had no difference from the 2 separate global objects and only the last one was getting logged.
My second attempt was specifing the iKey
or instrumentationKey
on the event itself but that didn't work either:
appInsights.trackEvent({name: 'myEvent', iKey: alternativeKey})
I tried using different names such as iKey
, instrumentationKey
, and specifying them in different places: inside properties: {}, inside cfg{}, inside config{} , etc.. nothing worked.
Then my last idea was to override the appInsights.config.instrumentationKey
after logging an event, and then log that event a second time, hopefully using the new key.
appInsights.trackEvent({name: event, properties: data});
if (secondaryInstrumentationKey) {
// Save primary InstrumentationKey
const originalKey = appInsights.config.instrumentationKey;
// Temporarly override instrumentationKey and log the event again
appInsights.config.instrumentationKey = secondaryInstrumentationKey;
appInsights.trackEvent({name: event, properties: data});
// Restore the original instrumentationKey
appInsights.config.instrumentationKey = originalKey;
}
This worked but it seems very inconsistent. Sometimes the event doesn't get logged to the second instance probably due to how the SDK debounces and aggregates as many events as possible before POSTing them to App Insights. I really have no idea..
I think the simplest thing would be to have the ability to override the iKey when calling appInsights.trackEvent().
Hi @FredUK
You are correct, name
in the config replace the same global appInsightsSDK
and therefore only the core of the last one is initialized!
We are investigating on this and working on a solution.
Hi @FredUK
After discussion with @MSNev ,
currently the best solution should be loading your second appInsights after initialization of the first one.
You can add onInit
callback function in your first appInsights configuration, the onInit
will be called once appInsights initialization is done.
so, your code might look like this:
<script>
const secondScript = () => !function(T,l,y){ var S=T.location,k="script" ...
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
crossOrigin: "anonymous",
name:"appInsights2",
cfg: {
instrumentationKey: "appInsights2"
}});
!function(T,l,y){var S=T.location,k="script" ...
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
crossOrigin: "anonymous",
onInit: secondScript,
name:"appInsights1",
cfg: {
instrumentationKey: "appInsights1"
}});
</script>
please let us know if the solution works!
@FredUK, and just to circle back on your options (sorry I was out last week).
1) @Karlie-777 found a race condition in the way the scripts are loaded and initializing around the use of a "global" instance name (not a simple fix) -- So her response above effectively works around this by serializing the initialization and avoiding the race. And if both are using the same script source, then the browser should re-use the previously (from first script) downloaded code and the 2nd should get initialized almost straight away.
2) This works (but) only for direct usages of the track
method (as this is a supported scenario for track). @Karlie-777 can you please raise another specific issue that trackEvent()
doesn't allow replacing the iKey (we will need to add this as an optional value for the IEventTelemetry```` (the same as it is already for
ITelemetryItem```) and set it if present after creating the envelope -- if present)
> I think the simplest thing would be to have the ability to override the iKey when calling appInsights.trackEvent().
100% Agree as called out above in # 2 response
3) This is not a supported scenario and it's inconsistent because we don't (currently) support "changing" the config after initialization (some components cache the config -- which is why it's inconsistent). There would also be possible race conditions between changing, "track" events and automatic events that could use the wrong iKey (even if you restored directly after the track call -- primarily if sending a synchronous event or during the "unload" cycle (which is all treated as synchronous))
Hi @Karlie-777 and @MSNev , thanks for both detailed replies. That really helps understanding why it wasn't working. I have attemped your suggestion of initiating the second appInsights on the onInit of the first one but it does not get initiated.
I have created a small jsfiddle sample here if you want to take a look.
If you click the "trackEvent" button and look at the console you will see it will log the first placeholder iKey but for the second log, it says appInsights2 is not defined. It seems the second global one is not initialized at all, even when on initiated on onInit.
Just wondering if the suggestion had been tested in the past or if I'm doing something wrong?
Thanks.
Hi @FredUK,
The OnInit, needs to be outside of the cfg: {} as it's a snippet config value and not the AI config.
I changed your jsFiddle for the 1st instance like this
name: 'appInsights1',
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
crossOrigin: "",
onInit: () => {
console.log("On Init called!");
secondScript();
},
cfg: {
instrumentationKey: instrumentationKey,
disableAjaxTracking: true
}});
Thanks @MSNev :medal_sports: , that worked. I guess I spent too much time messing with it that I messed up where I put the onInit. :)
Using this approach I' am sometimes getting a CORB error. I heard of CORS before but not CORB. Unfortunately I cannot figure out why I only get this warning sometimes and not all the time. I just thought I should mention in case it helps:
Ok, a CORB error is a little tricky to diagnose as it's going to depend on what the server returned in the body of the response and the Content-Type header.
As such I think the easiest way to track this down (if you can get a consistent repro) would be a fiddler trace with the offending response(s) to https://dc.services.visualstudio.com/vs/track, so this may contain sensitive data attaching to this thread is not advised. So if you can get a trace with this captured let me know (here) and we can find some other way to share the file.
Hi again, I have managed to capture it in Fiddler just not sure how I will be able to send you the google drive link as Github has no private messaging.
As I mentioned this only seems to happen sometimes. Looking at the server response for a working logged event and one that threw a CORB message the only difference I can see is that in the response body for the CORB one there is no appId property returned from the server.
This response was fine
{
"itemsReceived": 1,
"itemsAccepted": 1,
"errors": [],
"appId": "c9e8cc9d-351d-42b3[...]" // shortened for security reasons
}
This response threw a CORB error
{
"itemsReceived": 1,
"itemsAccepted": 1,
"errors": []
}
Hope this helps. Let me know if you are still interested in the fiddler session file and how I can make the link get to you.
@FredUK - excellent, I suspect it's something else in the response. I'm currently setting up an email alias that will enable you to send the trace (or a link) directly to me. It normally takes a few hours to get approved / processed will ping again once it is complete and active. It will be an @microsoft.com email address.
Thanks @MSNev , email has been sent. You can remove it from comment above if you'd like.
Thanks @FredUK, I'm reviewing the trace and while the response seems fine there are differences in the outbound request specifically the Content-Type which might be causing the issue -- investigating.
I've split out the CORB issue to #1653, as the requests that are returning the CORB issue appear to be originating from the _beaconSender() (using the sendBeacon API). Assuming this is the only case this is a non-blocking issue as the JS code doesn't need the response from a sendBeacon request (because the API doesn't return the response).
Looking at the trace provided by @FredUK the events where still ingested by the service, so it does not appear that this is blocking events from being ingested
Thanks @MSNev , great stuff. Appreciate your support and the detailed information. I will eventually wait for #1642 and the ability to specify the iKey on tracKEvent() instead of having to load 2 application insights instances.
We are leveraging the ApplicationInsights-JS package in a micro UI architecture where many teams are contributing to overall user experience. These teams would like to be able to monitor and instrument with their own instance of App Insights subscription.
Would like to be able to instantiate or maintain a collection of app insights subscriptions on client side and be able to push data to any of them based on configuration.
We have tried to implement all telemetry to a single app insights instance, but storage threshold is becoming an issue.
Is there any way to be able to selectively push telemetry data to multiple subscriptions in the same application.