Skip to content
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

[BUG] Correlation headers are not always set in vue.js SPA #1668

Closed
JnsSo opened this issue Sep 13, 2021 · 10 comments
Closed

[BUG] Correlation headers are not always set in vue.js SPA #1668

JnsSo opened this issue Sep 13, 2021 · 10 comments
Assignees

Comments

@JnsSo
Copy link

JnsSo commented Sep 13, 2021

Hi,
we have noticed that in our vue.js SPA the correlation headers are not always set. It seems to be quite similar to microsoft/applicationinsights-react-native#9 but not identical. In our case the page changes are tracked correctly but single GraphQL requests are not linked with the corresponding GraphQL API endpoint in our backend services. By analysing the requests we discovered that sometimes the headers Request-Id, Traceparent or Request-Context are missing.
We have ensured that all requests are build and getting executed the same way. Of course the graphql requests normally are executed to different times during the vue component lifecycle hooks but even if change this to a consistent approach e.g. mounted or beforeRouteEnter the headers are missing for some requests.

Could this issue nevertheless be related to the SPA structure?

Due this issue our end-to-end-transactions are not working correctly because now the transactions are starting inside our backend services without any relation to our frontend.

Steps to Reproduce

OS/Browser: -
SDK Version [e.g. 22]:
"@microsoft/applicationinsights-web": "^2.6.5",

How you initialized the SDK:

import { ApplicationInsights, DistributedTracingModes } from "@microsoft/applicationinsights-web";
import { PluginObject } from "vue";
import { ApplicationInsights as AppInsights } from "@microsoft/applicationinsights-analytics-js";

export interface IApplicationInsightsOptions {
  serviceName: string;
}

let appInsights: AppInsights;
let applicationInsights: ApplicationInsights;
const plugin: PluginObject<IApplicationInsightsOptions> = {
  install(vue, options) {
    const ai = new ApplicationInsights({
      config: {
        disableFetchTracking: false,
        enableCorsCorrelation: true,
        enableRequestHeaderTracking: true,
        enableResponseHeaderTracking: true,
        disableCorrelationHeaders: false,
        distributedTracingMode: DistributedTracingModes.AI_AND_W3C,
        enableAutoRouteTracking: true,
        connectionString: ""
      }
    });
    
    ai.loadAppInsights();
    
    ai.addTelemetryInitializer((envelope) => {
      if (envelope.tags) {
        envelope.tags["ai.cloud.role"] = options?.serviceName;
      }
    });

    applicationInsights = ai;
    appInsights = applicationInsights.appInsights;
    vue.prototype.$ai = applicationInsights.appInsights;
  }
}

export {appInsights as AppInsights};
export {applicationInsights as ApplicationInsights };
export default plugin;

Expected behavior

  • All requests contain the necessary headers to ensure that end-to-end transactions are working in combination with the frontend and backend services.
  • The correlation between the frontend and backend services is shown correctly in the application map view.

Additional context
Frontend: vue 2.6.12
Backend services: ASP.NET Core 5.0

So far we could not find any workaround for this problem.

@Karlie-777
Copy link
Contributor

Hi @JnsSo ,
as I replied in the microsoft/applicationinsights-react-native#9
some environments don't give information on currentHost and if this is the case, domains must be manually supplied in correlationHeaderDomains to include correlation headers otherwise no headers will be added. Please let us know if this can solve the issue!

@Karlie-777 Karlie-777 self-assigned this Sep 14, 2021
@JnsSo
Copy link
Author

JnsSo commented Sep 16, 2021

@Karlie-777 thank you for your response. Unfortunately manually supplying the domains in correlationHeaderDomains did not solve the issue. We also tried different apporaches like 'domain', 'domain:port' or 'domain:port/path' - these are all variants we found on GitHub.
Currently the application is running locally. Our frontend uses a proxy (https://cli.vuejs.org/config/#devserver-proxy) for the requests to our backend services. The configuration looks like this:

devServer: {
    compress: true,
    disableHostCheck: true,
    proxy: {
      "^/api/serviceA": {
        ws: true,
        target: "http://localhost:23006",
        pathRewrite: {"^/api/serviceA": ""},
      },
      ....
}

Meanwhile we tried the approach (mentioned here: microsoft/applicationinsights-react-native#9) to manually call trackPageView on every route change but the result is still the same.

@Karlie-777 Karlie-777 added the investigating Investigating the issue label Sep 21, 2021
@Karlie-777
Copy link
Contributor

Karlie-777 commented Sep 23, 2021

Hi @JnsSo
I tested it locally, it seems working

and I used sdk 2.7.0

image

here is my services/UserService.js

export async function getAllUsers() {
    const xhr = new XMLHttpRequest();
    xhr.open('GET','/api/users');
    xhr.send()
    return xhr.responseText;
}
import {
    ApplicationInsights, DistributedTracingModes
  } from '@microsoft/applicationinsights-web'
  
  const appInsights = new ApplicationInsights({
    config: {
      instrumentationKey: "",
      autoTrackPageVisitTime: true,
      enableAutoRouteTracking: true,
      enableRequestHeaderTracking: true,
      enableResponseHeaderTracking: true,
      disableAjaxTracking: false,
      enableCorsCorrelation: true,
      distributedTracingMode: DistributedTracingModes.AI_AND_W3C
    }
  })

and here is my vue.config

module.exports = {
    devServer: {
      proxy: {
        '/api': {
          target: 'http://localhost:3080/',
        },
        "/userapi": {
          target: 'http://localhost:3080/',
          pathRewrite: {'^/userapi' : '/api'}
        }
      }
    }
  }

@Karlie-777 Karlie-777 removed the investigating Investigating the issue label Sep 23, 2021
@JnsSo
Copy link
Author

JnsSo commented Sep 24, 2021

@Karlie-777 Thank you for your efforts. I updated the sdk to 2.7.0 but in our case it still does not work. Based on your answer the issue seems to be related to Apollo, because we are facing this problem only with some GraphQL requests (as mentioned in the initial description).

This is how we create our apollo client reduced to the essential:

...
const httpLink = createHttpLink({
  uri: ...,
  credentials: "include",
  fetchOptions: {
    credentials: "include"
  }
});
...
const link = new ApolloLink((operation, forward) => {
  // already tried to set headers manually as described here:
  // https://www.apollographql.com/docs/react/networking/advanced-http-networking/
  return forward(operation);
});
const apolloLink = split(
  ({query}: any) => {
      const {kind, operation}: IDefinintion = getMainDefinition(query);
      return kind === "OperationDefinition" && operation === "subscription";
    },
    from([link, wsLink]),
    from([link, httpLink])
);
const apolloClient = new ApolloClient({
  link: apolloLink,
  cache: new InMemoryCache({fragmentMatcher}),
  ...options
});
...

I do not really understand why some graphql requests are getting tracked correctly while others are missing. By our implementation there is no difference between correctly tracked requests and not-tracked requests.

@Karlie-777
Copy link
Contributor

Karlie-777 commented Sep 24, 2021

@JnsSo
so I notice Apollo uses cache, is it possible that some of the requests are directly get from the cache and therefore they are not tracked? (correct me if I am wrong)
We currently do not have Vue plugins (like those for react) and some features may not be well supported with Vue, but based on my previous tests, the track should work unless our sdk can not access the information. Have you tried changing the appollo client config?

Or do you mind providing us with a fiddler trace/network screenshots so that we can better target problems? thanks!

@JnsSo
Copy link
Author

JnsSo commented Sep 30, 2021

Sorry for the delay. I will provide the requested information within the next days.

@JnsSo
Copy link
Author

JnsSo commented Oct 4, 2021

@Karlie-777 Thank you for pointing that out. The issue is related to our own apollo client cache. If we create a new apollo client instance for every single request then all headers are set and the correlation is working.
Of course it would be better if we could reuse an existing apollo client, therefore I have one additional question: Is it possible to manually set the request-id header? I managed to get the current traceID but I could not access the spanID since it is not part of the ITelemetryContext:

const spanID = generateW3CId().substr(0, 16);

@Karlie-777
Copy link
Contributor

@JnsSo
We will keep the autogenerated spanID to keep trace id unique.
If you want to set/access traceId, use appInsights.context.telemetryTrace.traceId= Microsoft.ApplicationInsights.Telemetry.Util.generateW3CId() to reset/access.

Please let us know if this works!

@JnsSo
Copy link
Author

JnsSo commented Oct 8, 2021

@Karlie-777 Hi, thank you. That solved our issue.

@JnsSo JnsSo closed this as completed Oct 8, 2021
@github-actions
Copy link

github-actions bot commented Aug 3, 2023

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants