Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I utilise ApplicationInsights-JS in a service worker?

I am currently using ApplicationInsights-JS in my progressive web app. It works in my react components as I can import what I need from the relevant npm packages.

In my service worker however, I can only import logic using importScripts.

I did manage to find a CDN for ApplicationInsights-JS on their Github page however it seems that in order to initialise app insights using this library you need to have access to window in order to store the appinsights, which you cannot do from a service worker.

I tried to use the web snippet approach since the CDN seemed to be related to that particular library, but I can't use window and am not sure how else to implement this solution.

This is a copy paste of the suggested snippet to init the app insights object from: https://github.com/Microsoft/ApplicationInsights-JS

importScripts('https://az416426.vo.msecnd.net/beta/ai.2.min.js');

const sdkInstance = 'appInsightsSDK';
window[sdkInstance] = 'appInsights';
const aiName = window[sdkInstance];

const aisdk =
  window[aiName] ||
  (function(e) {
    function n(e) {
      i[e] = function() {
        const n = arguments;
        i.queue.push(function() {
          i[e](...n);
        });
      };
    }
    let i = { config: e };
    i.initialize = !0;
    const a = document;

    const t = window;
    setTimeout(function() {
      const n = a.createElement('script');
      (n.src = e.url || 'https://az416426.vo.msecnd.net/next/ai.2.min.js'),
        a.getElementsByTagName('script')[0].parentNode.appendChild(n);
    });
    try {
      i.cookie = a.cookie;
    } catch (e) {}
    (i.queue = []), (i.version = 2);
    for (
      const r = [
        'Event',
        'PageView',
        'Exception',
        'Trace',
        'DependencyData',
        'Metric',
        'PageViewPerformance'
      ];
      r.length;

    )
      n(`track${r.pop()}`);
    n('startTrackPage'), n('stopTrackPage');
    const o = `Track${r[0]}`;
    if (
      (n(`start${o}`),
      n(`stop${o}`),
      !(
        !0 === e.disableExceptionTracking ||
        (e.extensionConfig &&
          e.extensionConfig.ApplicationInsightsAnalytics &&
          !0 ===
            e.extensionConfig.ApplicationInsightsAnalytics
              .disableExceptionTracking)
      ))
    ) {
      n(`_${(r = 'onerror')}`);
      const s = t[r];
      (t[r] = function(e, n, a, t, o) {
        const c = s && s(e, n, a, t, o);
        return (
          !0 !== c &&
            i[`_${r}`]({
              message: e,
              url: n,
              lineNumber: a,
              columnNumber: t,
              error: o
            }),
          c
        );
      }),
        (e.autoExceptionInstrumented = !0);
    }
    return i;
  })({ instrumentationKey: 'xxx-xxx-xxx-xxx-xxx' });
(window[aiName] = aisdk),
  aisdk.queue && aisdk.queue.length === 0 && aisdk.trackPageView({});

I get window is not defined which is expected, but I'm not sure how else I can make use of this library from the service worker.

Has anyone else had a similar implementation in which they successfully logged telemetry using ApplicationInsights from a service worker?

like image 576
B.L.Coskey Avatar asked May 02 '19 15:05

B.L.Coskey


3 Answers

I realised that I was over complicating this.

Since I only needed to track a custom event, and didn't need all the automated page tracking etc that appInsights does, I ended up doing a fetch from my service worker.

I just copied the header and body format from the requests that I made using my react pages.

The below successfully logged telemetry to my app insights dashboard:

fetch(url, {
  method: 'post',
  headers: {
    'Content-type': 'application/json'
  },
  body: JSON.stringify([
    {
      time: '2019-05-02T15:56:37.589Z',
      iKey: 'INSTRUMENTATION_KEY',
      name:
        'Microsoft.ApplicationInsights.INSTRUMENTATION_KEY.Event',
      tags: {
        'ai.user.id': 'l6Tey',
        'ai.session.id': 'TL+Ry',
        'ai.device.id': 'browser',
        'ai.device.type': 'Browser',
        'ai.operation.id': 'HUfNE',
        SampleRate: '100',
        // eslint-disable-next-line no-script-url
        'ai.internal.sdkVersion': 'javascript:2.0.0-rc4'
      },
      data: {
        baseType: 'EventData',
        baseData: {
          ver: 2,
          name: 'Testing manual event',
          properties: {},
          measurements: {}
        }
      }
    }
  ])
})
  .then(json)
  .then(function(data) {
  })
  .catch(function(error) {
  });
like image 85
B.L.Coskey Avatar answered Oct 01 '22 21:10

B.L.Coskey


I've almost managed to use Microsoft Application Insights in our app's service worker.

The key parts are:

  • Using the lightweight version of appInsights (see this small remark at 4th step) with importScripts('https://az416426.vo.msecnd.net/next/aib.2.min.js').
  • Initialize an appInsights object:
appInsights = new Microsoft.AppInsights.AppInsights({ instrumentationKey: "[replace with your own key]" });
  • when track needed (during onpush event or onnotificationclick), go for appInsight.track({ eventItemFields }) then appInsights.flush().

I've said "almost" because the flush part seems to not working, I've got: "Sender was not initialized" internal error after enabling debugging. I will publish here a working sample code if I successfully manage this issue.

References:

  • https://github.com/Azure-Samples/applicationinsights-web-sample1/blob/master/testlightsku.html
  • This response to the question: How to add analytics for Push notifications.
like image 33
Rajar Avatar answered Oct 01 '22 20:10

Rajar


Using the Web SDK in a service worker is troublesome. The full version depends on a window object, while the basic SDK depends on Beacon or XmlHttpRequest for sending the messages (in file https://github.com/microsoft/ApplicationInsights-JS/blob/master/channels/applicationinsights-channel-js/src/Sender.ts):

                if (!_self._senderConfig.isBeaconApiDisabled() && Util.IsBeaconApiSupported()) {
                    _self._sender = _beaconSender;
                } else {
                    if (typeof XMLHttpRequest !== undefined) {
                        const xhr:any = getGlobalInst("XMLHttpRequest");
                        if(xhr) {
                            const testXhr = new xhr();
                            if ("withCredentials" in testXhr) {
                                _self._sender = _xhrSender;
                                _self._XMLHttpRequestSupported = true;
                            } else if (typeof XDomainRequest !== undefined) {
                                _self._sender = _xdrSender; // IE 8 and 9
                            }
                        }
                    }
                }

At the moment Application Insights SDK does not seem to support service workers. Rajars solution seems to be the best option for now.

Update: There is an issue in the Github Repo about this: https://github.com/microsoft/ApplicationInsights-JS/issues/1436

A suggestion that works is by using the basic/lightweight version of Application Insights (as mentioned by Rajar) and adding a XMLHttpRequest polyfill (that uses the fetch api) before inititializing Application Insights. After that you can use the lightweight version.

An example can be found here: https://github.com/Pkiri/pwa-ai

like image 28
Pkiri Avatar answered Oct 01 '22 22:10

Pkiri