Skip to content

Latest commit

 

History

History
778 lines (565 loc) · 29.8 KB

javascript-framework-extensions.md

File metadata and controls

778 lines (565 loc) · 29.8 KB
title description services ms.tgt_pltfrm ms.topic ms.date ms.devlang ms.custom ms.reviewer
Enable a framework extension for Application Insights JavaScript SDK
Learn how to install and use JavaScript framework extensions for the Application Insights JavaScript SDK.
azure-monitor
ibiza
conceptual
11/15/2023
javascript
devx-track-js
mmcc

Enable a framework extension for Application Insights JavaScript SDK

In addition to the core SDK, there are also plugins available for specific frameworks, such as the React plugin, the React Native plugin, and the Angular plugin.

These plugins provide extra functionality and integration with the specific framework.

Prerequisites

  • You must be using a version >= 2.0.0 of @microsoft/applicationinsights-web. This plugin only works in react-native apps. It doesn't work with apps using the Expo framework or Create React Native App, which is based on the Expo framework.
  • The Angular plugin is NOT ECMAScript 3 (ES3) compatible.
  • When we add support for a new Angular version, our npm package becomes incompatible with down-level Angular versions. Continue to use older npm packages until you're ready to upgrade your Angular version.

What does the plug-in enable?

The React plug-in for the Application Insights JavaScript SDK enables:

  • Track router history
  • Track exceptions
  • Track components usage
  • Use Application Insights with React Context

The React Native plugin for Application Insights JavaScript SDK enables:

  • Track exceptions

  • Collect device information

    By default, this plugin automatically collects:

    • Unique Device ID (Also known as Installation ID.)
    • Device Model Name (Such as iPhone XS, Samsung Galaxy Fold, Huawei P30 Pro etc.)
    • Device Type (For example, handset, tablet, etc.)
  • Disable automatic device info collection

  • Use your own device info collection class

  • Override the device information

The Angular plugin for the Application Insights JavaScript SDK enables:

  • Track router history
  • Track exceptions
  • Chain more custom exception handlers

Add a plug-in

To add a plug-in, follow the steps in this section.

Install the package

npm install @microsoft/applicationinsights-react-js
  • React Native Plugin

    By default, the React Native Plugin relies on the react-native-device-info package. You must install and link to this package. Keep the react-native-device-info package up to date to collect the latest device names using your app.

    Since v3, support for accessing the DeviceInfo has been abstracted into an interface IDeviceInfoModule to enable you to use / set your own device info module. This interface uses the same function names and result react-native-device-info.

    npm install --save @microsoft/applicationinsights-react-native @microsoft/applicationinsights-web
    npm install --save react-native-device-info
    react-native link react-native-device-info
    
  • React Native Manual Device Plugin

    If you're using React Native Expo, add the React Native Manual Device Plugin instead of the React Native Plugin. The React Native Plugin uses the react-native-device-info package package, which React Native Expo doesn't support.

    npm install --save @microsoft/applicationinsights-react-native @microsoft/applicationinsights-web
    
npm install @microsoft/applicationinsights-angularplugin-js

Add the extension to your code

[!INCLUDE azure-monitor-log-analytics-rebrand]

Initialize a connection to Application Insights:

import React from 'react';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';
import { ReactPlugin } from '@microsoft/applicationinsights-react-js';
import { createBrowserHistory } from "history";
const browserHistory = createBrowserHistory({ basename: '' });
var reactPlugin = new ReactPlugin();
// *** Add the Click Analytics plug-in. ***
/* var clickPluginInstance = new ClickAnalyticsPlugin();
   var clickPluginConfig = {
     autoCapture: true
}; */
var appInsights = new ApplicationInsights({
    config: {
        connectionString: 'YOUR_CONNECTION_STRING_GOES_HERE',
        // *** If you're adding the Click Analytics plug-in, delete the next line. ***
        extensions: [reactPlugin],
     // *** Add the Click Analytics plug-in. ***
     // extensions: [reactPlugin, clickPluginInstance],
        extensionConfig: {
          [reactPlugin.identifier]: { history: browserHistory }
       // *** Add the Click Analytics plug-in. ***
       // [clickPluginInstance.identifier]: clickPluginConfig
        }
    }
});
appInsights.loadAppInsights();
  • React Native Plug-in

    To use this plugin, you need to construct the plugin and add it as an extension to your existing Application Insights instance.

    import { ApplicationInsights } from '@microsoft/applicationinsights-web';
    import { ReactNativePlugin } from '@microsoft/applicationinsights-react-native';
    // *** Add the Click Analytics plug-in. ***
    // import { ClickAnalyticsPlugin } from '@microsoft/applicationinsights-clickanalytics-js';
    var RNPlugin = new ReactNativePlugin();
    // *** Add the Click Analytics plug-in. ***
    /* var clickPluginInstance = new ClickAnalyticsPlugin();
    var clickPluginConfig = {
    autoCapture: true
    }; */
    var appInsights = new ApplicationInsights({
        config: {
            connectionString: 'YOUR_CONNECTION_STRING_GOES_HERE',
            // *** If you're adding the Click Analytics plug-in, delete the next line. ***
            extensions: [RNPlugin]
         // *** Add the Click Analytics plug-in. ***
         /* extensions: [RNPlugin, clickPluginInstance],
                 extensionConfig: {
                     [clickPluginInstance.identifier]: clickPluginConfig
              } */
        }
    });
    appInsights.loadAppInsights();
  • React Native Manual Device Plugin

    To use this plugin, you must either disable automatic device info collection or use your own device info collection class after you add the extension to your code.

    1. Construct the plugin and add it as an extension to your existing Application Insights instance.

      import { ApplicationInsights } from '@microsoft/applicationinsights-web';
      import { ReactNativePlugin } from '@microsoft/applicationinsights-react-native';
      
      var RNMPlugin = new ReactNativePlugin();
      var appInsights = new ApplicationInsights({
          config: {
              instrumentationKey: 'YOUR_INSTRUMENTATION_KEY_GOES_HERE',
              extensions: [RNMPlugin]
          }
      });
      appInsights.loadAppInsights();
    2. Do one of the following:

      • Disable automatic device info collection.

        import { ApplicationInsights } from '@microsoft/applicationinsights-web';
        
        var RNMPlugin = new ReactNativeManualDevicePlugin();
        var appInsights = new ApplicationInsights({
            config: {
                instrumentationKey: 'YOUR_INSTRUMENTATION_KEY_GOES_HERE',
                disableDeviceCollection: true,
                extensions: [RNMPlugin]
            }
        });
        appInsights.loadAppInsights();
      • Use your own device info collection class.

        import { ApplicationInsights } from '@microsoft/applicationinsights-web';
        
        // Simple inline constant implementation
        const myDeviceInfoModule = {
            getModel: () => "deviceModel",
            getDeviceType: () => "deviceType",
            // v5 returns a string while latest returns a promise
            getUniqueId: () => "deviceId",         // This "may" also return a Promise<string>
        };
        
        var RNMPlugin = new ReactNativeManualDevicePlugin();
        RNMPlugin.setDeviceInfoModule(myDeviceInfoModule);
        
        var appInsights = new ApplicationInsights({
            config: {
                instrumentationKey: 'YOUR_INSTRUMENTATION_KEY_GOES_HERE',
                extensions: [RNMPlugin]
            }
        });
        
        appInsights.loadAppInsights();

Set up an instance of Application Insights in the entry component in your app:

Important

When using the ErrorService, there is an implicit dependency on the @microsoft/applicationinsights-analytics-js extension. you MUST include either the '@microsoft/applicationinsights-web' or include the @microsoft/applicationinsights-analytics-js extension. Otherwise, unhandled exceptions caught by the error service will not be sent.

import { Component } from '@angular/core';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';
import { AngularPlugin } from '@microsoft/applicationinsights-angularplugin-js';
// *** Add the Click Analytics plug-in. ***
// import { ClickAnalyticsPlugin } from '@microsoft/applicationinsights-clickanalytics-js';
import { Router } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    constructor(
        private router: Router
    ){
        var angularPlugin = new AngularPlugin();
     // *** Add the Click Analytics plug-in. ***
     /* var clickPluginInstance = new ClickAnalyticsPlugin();
        var clickPluginConfig = {
          autoCapture: true
        }; */
        const appInsights = new ApplicationInsights({
            config: {
                connectionString: 'YOUR_CONNECTION_STRING_GOES_HERE',
                // *** If you're adding the Click Analytics plug-in, delete the next line. ***  
                extensions: [angularPlugin],
             // *** Add the Click Analytics plug-in. ***
             // extensions: [angularPlugin, clickPluginInstance],
                extensionConfig: {
                    [angularPlugin.identifier]: { router: this.router }
                 // *** Add the Click Analytics plug-in. ***
                 // [clickPluginInstance.identifier]: clickPluginConfig
                }
            } 
         });
        appInsights.loadAppInsights();
    }
}

(Optional) Add the Click Analytics plug-in

If you want to add the Click Analytics plug-in:

  1. Uncomment the lines for Click Analytics.

  2. Do one of the following, depending on which plug-in you're adding:

    • For React, delete extensions: [reactPlugin],.
    • For React Native, delete extensions: [RNPlugin].
    • For Angular, delete extensions: [angularPlugin],.
  3. See Use the Click Analytics plug-in to continue with the setup process.

Configuration

This section covers configuration settings for the framework extensions for Application Insights JavaScript SDK.

Track router history

Name Type Required? Default Description
history object Optional null Track router history. For more information, see the React router package documentation.

To track router history, most users can use the enableAutoRouteTracking field in the JavaScript SDK configuration. This field collects the same data for page views as the history object.

Use the history object when you're using a router implementation that doesn't update the browser URL, which is what the configuration listens to. You shouldn't enable both the enableAutoRouteTracking field and history object, because you'll get multiple page view events.

The following code example shows how to enable the enableAutoRouteTracking field.

var reactPlugin = new ReactPlugin();
var appInsights = new ApplicationInsights({
    config: {
        connectionString: 'YOUR_CONNECTION_STRING_GOES_HERE',
        enableAutoRouteTracking: true,
        extensions: [reactPlugin]
    }
});
appInsights.loadAppInsights();

React Native doesn't track router changes but does track page views.

Name Type Required? Default Description
router object Optional null Angular router for enabling Application Insights PageView tracking.

The following code example shows how to enable tracking of router history.

import { Component } from '@angular/core';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';
import { AngularPlugin } from '@microsoft/applicationinsights-angularplugin-js';
import { Router } from '@angular/router';



@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    constructor(
        private router: Router
    ){
        var angularPlugin = new AngularPlugin();
        const appInsights = new ApplicationInsights({ config: {
        connectionString: 'YOUR_CONNECTION_STRING',
        extensions: [angularPlugin],
        extensionConfig: {
            [angularPlugin.identifier]: { router: this.router }
        }
        } });
        appInsights.loadAppInsights();
    }
}

Track exceptions

React error boundaries provide a way to gracefully handle an uncaught exception when it occurs within a React application. When such an exception occurs, it's likely that the exception needs to be logged. The React plug-in for Application Insights provides an error boundary component that automatically logs the exception when it occurs.

import React from "react";
import { reactPlugin } from "./AppInsights";
import { AppInsightsErrorBoundary } from "@microsoft/applicationinsights-react-js";

const App = () => {
    return (
        <AppInsightsErrorBoundary onError={() => <h1>I believe something went wrong</h1>} appInsights={reactPlugin}>
            /* app here */
        </AppInsightsErrorBoundary>
    );
};

The AppInsightsErrorBoundary requires two props to be passed to it. They're the ReactPlugin instance created for the application and a component to be rendered when an exception occurs. When an unhandled exception occurs, trackException is called with the information provided to the error boundary, and the onError component appears.

The tracking of uncaught exceptions is enabled by default. If you want to disable the tracking of uncaught exceptions, set disableExceptionCollection to true.

import { ApplicationInsights } from '@microsoft/applicationinsights-web';

var RNPlugin = new ReactNativePlugin();
var appInsights = new ApplicationInsights({
    config: {
        connectionString: 'YOUR_CONNECTION_STRING_GOES_HERE',
        disableExceptionCollection: true,
        extensions: [RNPlugin]
    }
});
appInsights.loadAppInsights();

To track uncaught exceptions, set up ApplicationinsightsAngularpluginErrorService in app.module.ts:

Important

When using the ErrorService, there is an implicit dependency on the @microsoft/applicationinsights-analytics-js extension. you MUST include either the '@microsoft/applicationinsights-web' or include the @microsoft/applicationinsights-analytics-js extension. Otherwise, unhandled exceptions caught by the error service will not be sent.

import { ApplicationinsightsAngularpluginErrorService } from '@microsoft/applicationinsights-angularplugin-js';

@NgModule({
  ...
  providers: [
    {
      provide: ErrorHandler,
      useClass: ApplicationinsightsAngularpluginErrorService
    }
  ]
  ...
})
export class AppModule { }

Chain more custom exception handlers

Chain more custom exception handlers when you want to want the application to gracefully handle what would previously have been an unhandled exception, but you still want to report this exception as an application failure.

To chain more custom exception handlers:

  1. Create custom exception handlers that implement IErrorService.

    import { IErrorService } from '@microsoft/applicationinsights-angularplugin-js';
    
    export class CustomErrorHandler implements IErrorService {
        handleError(error: any) {
            ...
        }
    }
  2. Pass errorServices array through extensionConfig.

    extensionConfig: {
            [angularPlugin.identifier]: {
              router: this.router,
              errorServices: [new CustomErrorHandler()]
            }
          }

Collect device information

The device information, which includes Browser, OS, version, and language, is already being collected by the Application Insights web package.

  • React Native Plugin: In addition to user agent info from the browser, which is collected by Application Insights web package, React Native also collects device information. Device information is automatically collected when you add the plug-in.
  • React Native Manual Device Plugin: Depending on how you configured the plugin when you added the extension to your code, this plugin either:
    • Doesn't collect device information
    • Uses your own device info collection class

The device information, which includes Browser, OS, version, and language, is already being collected by the Application Insights web package.


Configuration (other)

Track components usage

A feature that's unique to the React plug-in is that you're able to instrument specific components and track them individually.

To instrument React components with usage tracking, apply the withAITracking higher-order component function. To enable Application Insights for a component, wrap withAITracking around the component:

import React from 'react';
import { withAITracking } from '@microsoft/applicationinsights-react-js';
import { reactPlugin, appInsights } from './AppInsights';

// To instrument various React components usage tracking, apply the `withAITracking` higher-order
// component function.

class MyComponent extends React.Component {
    ...
}

// withAITracking takes 4 parameters (reactPlugin, Component, ComponentName, className). 
// The first two are required and the other two are optional.

export default withAITracking(reactPlugin, MyComponent);

It measures time from the ComponentDidMount event through the ComponentWillUnmount event. To make the result more accurate, it subtracts the time in which the user was idle by using React Component Engaged Time = ComponentWillUnmount timestamp - ComponentDidMount timestamp - idle time.

Explore your data

Use Azure Monitor metrics explorer to plot a chart for the custom metric name React Component Engaged Time (seconds) and split this custom metric by Component Name.

:::image type="content" source="./media/javascript-react-plugin/chart.png" lightbox="./media/javascript-react-plugin/chart.png" alt-text="Screenshot that shows a chart that displays the custom metric React Component Engaged Time (seconds) split by Component Name":::

You can also run custom queries to divide Application Insights data to generate reports and visualizations as per your requirements. Here’s an example of a custom query. Go ahead and paste it directly into the query editor to test it out.

customMetrics
| where name contains "React Component Engaged Time (seconds)"
| summarize avg(value), count() by tostring(customDimensions["Component Name"])

It can take up to 10 minutes for new custom metrics to appear in the Azure portal.

Use Application Insights with React Context

We provide general hooks to allow you to customize the change tracking for individual components. Alternatively, you can use useTrackMetric or useTrackEvent, which are pre-defined contacts we provide for tracking the changes to components.

The React Hooks for Application Insights are designed to use React Context as a containing aspect for it. To use Context, initialize Application Insights, and then import the Context object:

import React from "react";
import { AppInsightsContext } from "@microsoft/applicationinsights-react-js";
import { reactPlugin } from "./AppInsights";

const App = () => {
    return (
        <AppInsightsContext.Provider value={reactPlugin}>
            /* your application here */
        </AppInsightsContext.Provider>
    );
};

This Context Provider makes Application Insights available as a useContext Hook within all children components of it:

import React from "react";
import { useAppInsightsContext } from "@microsoft/applicationinsights-react-js";

const MyComponent = () => {
    const appInsights = useAppInsightsContext();
    const metricData = {
        average: engagementTime,
        name: "React Component Engaged Time (seconds)",
        sampleCount: 1
      };
    const additionalProperties = { "Component Name": 'MyComponent' };
    appInsights.trackMetric(metricData, additionalProperties);
    
    return (
        <h1>My Component</h1>
    );
}
export default MyComponent;
useTrackMetric

The useTrackMetric Hook replicates the functionality of the withAITracking higher-order component, without adding another component to the component structure. The Hook takes two arguments:

  • The Application Insights instance, which can be obtained from the useAppInsightsContext Hook.
  • An identifier for the component for tracking, such as its name.
import React from "react";
import { useAppInsightsContext, useTrackMetric } from "@microsoft/applicationinsights-react-js";

const MyComponent = () => {
    const appInsights = useAppInsightsContext();
    const trackComponent = useTrackMetric(appInsights, "MyComponent");
    
    return (
        <h1 onHover={trackComponent} onClick={trackComponent}>My Component</h1>
    );
}
export default MyComponent;

It operates like the higher-order component, but it responds to Hooks lifecycle events rather than a component lifecycle. If there's a need to run on particular interactions, the Hook needs to be explicitly provided to user events.

useTrackEvent

Use the useTrackEvent Hook to track any custom event that an application might need to track, such as a button click or other API call. It takes four arguments:

  • Application Insights instance, which can be obtained from the useAppInsightsContext Hook.
  • Name for the event.
  • Event data object that encapsulates the changes that have to be tracked.
  • skipFirstRun (optional) flag to skip calling the trackEvent call on initialization. The default value is set to true to mimic more closely the way the non-Hook version works. With useEffect Hooks, the effect is triggered on each value update including the initial setting of the value. As a result, tracking starts too early, which causes potentially unwanted events to be tracked.
import React, { useState, useEffect } from "react";
import { useAppInsightsContext, useTrackEvent } from "@microsoft/applicationinsights-react-js";

const MyComponent = () => {
    const appInsights = useAppInsightsContext();
    const [cart, setCart] = useState([]);
    const trackCheckout = useTrackEvent(appInsights, "Checkout", cart);
    const trackCartUpdate = useTrackEvent(appInsights, "Cart Updated", cart);
    useEffect(() => {
        trackCartUpdate({ cartCount: cart.length });
    }, [cart]);
    
    const performCheckout = () => {
        trackCheckout();
        // submit data
    };
    
    return (
        <div>
            <ul>
                <li>Product 1 <button onClick={() => setCart([...cart, "Product 1"])}>Add to Cart</button></li>
                <li>Product 2 <button onClick={() => setCart([...cart, "Product 2"])}>Add to Cart</button></li>
                <li>Product 3 <button onClick={() => setCart([...cart, "Product 3"])}>Add to Cart</button></li>
                <li>Product 4 <button onClick={() => setCart([...cart, "Product 4"])}>Add to Cart</button></li>
            </ul>
            <button onClick={performCheckout}>Checkout</button>
        </div>
    );
}

export default MyComponent;

When the Hook is used, a data payload can be provided to it to add more data to the event when it's stored in Application Insights.

Disable automatic device info collection

If you don’t want to collect the device information, you can set disableDeviceCollection to true.

import { ApplicationInsights } from '@microsoft/applicationinsights-web';

var RNPlugin = new ReactNativePlugin();
var appInsights = new ApplicationInsights({
    config: {
        connectionString: 'YOUR_CONNECTION_STRING_GOES_HERE',
        disableDeviceCollection: true,
        extensions: [RNPlugin]
    }
});
appInsights.loadAppInsights();

Use your own device info collection class

If you want to override your own device’s information, you can use myDeviceInfoModule to collect your own device information.

import { ApplicationInsights } from '@microsoft/applicationinsights-web';

// Simple inline constant implementation
const myDeviceInfoModule = {
    getModel: () => "deviceModel",
    getDeviceType: () => "deviceType",
    // v5 returns a string while latest returns a promise
    getUniqueId: () => "deviceId",         // This "may" also return a Promise<string>
};

var RNPlugin = new ReactNativePlugin();
RNPlugin.setDeviceInfoModule(myDeviceInfoModule);

var appInsights = new ApplicationInsights({
    config: {
        connectionString: 'YOUR_CONNECTION_STRING_GOES_HERE',
        extensions: [RNPlugin]
    }
});

appInsights.loadAppInsights();

Override the device information

Use the IDeviceInfoModule interface to abstract how the plug-in can access the Device Info. This interface is a stripped down version of the react-native-device-info interface and is mostly supplied for testing.

export interface IDeviceInfoModule {
    /**
     * Returns the Device Model
     */
    getModel: () => string;

    /**
     * Returns the device type
     */
    getDeviceType: () => string;

    /**
     * Returns the unique Id for the device. To support both the current version and previous
     * versions react-native-device-info, this may return either a `string` or `Promise<string>`.
     * When a promise is returned, the plugin will "wait" for the promise to `resolve` or `reject`
     * before processing any events. This WILL cause telemetry to be BLOCKED until either of these
     * states, so when returning a Promise, it MUST `resolve` or `reject`. Tt can't just never resolve.
     * There is a default timeout configured via `uniqueIdPromiseTimeout` to automatically unblock
     * event processing when this issue occurs.
     */
    getUniqueId: () => Promise<string> | string;
}

If events are getting "blocked" because the Promise returned via getUniqueId is never resolved / rejected, you can call setDeviceId() on the plugin to "unblock" this waiting state. There is also an automatic timeout configured via uniqueIdPromiseTimeout (defaults to 5 seconds), which will internally call setDeviceId() with any previously configured value.

N/A


Sample app

Check out the Application Insights React demo.

Currently unavailable.

Check out the Application Insights Angular demo.


Frequently asked questions

This section provides answers to common questions.

How does Application Insights generate device information like browser, OS, language, and model?

The browser passes the User Agent string in the HTTP header of the request. The Application Insights ingestion service uses UA Parser to generate the fields you see in the data tables and experiences. As a result, Application Insights users are unable to change these fields.

Occasionally, this data might be missing or inaccurate if the user or enterprise disables sending User Agent in browser settings. The UA Parser regexes might not include all device information. Or Application Insights might not have adopted the latest updates.

Next steps