Tracking Cloudflare Worker requests using Application Insights

 
 
  • Gérald Barré

This website is hosted on a static website hosting provider and I use Cloudflare CDN to improve the performance. These 2 services allow me to host this website for free even if I got more and more visitors. However, I do not have lots of analytics. For instance, I want to know where the user comes from using the HTTP referer header or if they got a 404. Google Analytics is useful but most users use an adblocker, and it doesn't work well with 404 pages Application Insights, among other features, allows to track requests. In this post, we'll see how to integrate Application Insights into Cloudflare.

Cloudflare Workers allows to handle requests and serve the response to the client. If you are familiar with Azure, Cloudflare Workers are similar to Azure Functions. Using Workers, you can serve the content from your original server and track the request to Application Insights.

To deal with Cloudflare Workers, you need to install wrangler:

Shell
npm install -g @cloudflare/wrangler
wrangler login

Then, you can generate the project:

Shell
wrangler generate application-insights

This will create a folder with a few files. The most important ones are index.js, package.json, and wrangler.toml. You can edit the index.js file with the following content:

TypeScript
const applicationInsightsKey = "<TODO Application Insights Instrumentation Key>";
const requestDataEventName = `Microsoft.ApplicationInsights.${applicationInsightsKey.replace(/-/g, '')}.RequestData`;

addEventListener("fetch", event => {
    // https://developers.cloudflare.com/workers/learning/fetch-event-lifecycle
    event.passThroughOnException();
    event.respondWith(processRequest(event));
});

async function processRequest(event) {
    const request = event.request;
    const response = await fetch(request);

    // Prevent the worker to stop before sending the data to Application Insights
    // https://developers.cloudflare.com/workers/learning/fetch-event-lifecycle#waituntil
    event.waitUntil(trackRequest(request, response));

    return response;
}

function trackRequest(request, response) {
    // Allowed Application Insights payload: https://github.com/microsoft/ApplicationInsights-JS/tree/61b49063eeacda7878a1fda0107bde766e83e59e/legacy/JavaScript/JavaScriptSDK.Interfaces/Contracts/Generated
    const body = {
        iKey: applicationInsightsKey,
        name: requestDataEventName,
        time: new Date(),
        tags: {
            // Allowed tags: https://github.com/microsoft/ApplicationInsights-JS/blob/17ef50442f73fd02a758fbd74134933d92607ecf/legacy/JavaScript/JavaScriptSDK.Interfaces/Contracts/Generated/ContextTagKeys.ts#L208
            // Set the client_ip
            "ai.location.ip": request.headers.get("CF-Connecting-IP"),
        },
        data: {
            baseType: "RequestData",
            baseData: {
                ver: 2,
                id: generateUniqueId(),
                properties: {
                    // You can add more properties if needed
                    HttpReferer: request.headers.get("Referer")
                },
                measurements: {},
                responseCode: response.status,
                success: response.status >= 200 && response.status < 400,
                url: request.url,
                source: request.headers.get("CF-Connecting-IP") || "",
                duration: 1 // Cloudflare doesn't allow to measure duration. performance.now() is not implemented, and new Date() always return the same value
            }
        }
    };

    return fetch('https://dc.services.visualstudio.com/v2/track', {
        method: 'POST',
        body: JSON.stringify([body]),
    });
}

function generateUniqueId() {
    function chr4() { return Math.random().toString(16).slice(-4); }
    return chr4() + chr4() + '-' + chr4() + '-' + chr4() + '-' + chr4() + '-' + chr4() + chr4() + chr4();
}

The code of the worker is complete. Before publishing the project to Cloudflare, you will need to update the following fields in the wrangler.toml file: You can find your account_id in the right sidebar of your account's Workers page, and zone_id in the right sidebar of a zone's overview tab at https://dash.cloudflare.com.

Once you have filled both fields, you can publish the project:

Shell
wrangler publish

Last, you need to associate the worker on your website. Go to the Workers page, and click on the "Add route" button. Enter the route

You can now see the requests in Application Insights:

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub