Production Issue Monitoring: Complete Sentry Integration Guide

Background: When sporadic production issues occur, testers often cannot reproduce the error scenario based on API information alone. Production monitoring is critical for improving system reliability. Among the many monitoring tools available, why choose Sentry? Because it offers session replay capabilities, automatic error collection, multi-user support, free tier, and low integration overhead. Why write this article? Most existing resources are either outdated or too brief. All the content below has been deployed to production—fresh from implementation.

Environment: node version is 14.16.1 "vue": "^2.5.2" "@sentry/vue": "^7.98.0" "@sentry/webpack-plugin": "^2.10.3"


Integration Steps

1. Update Configuration Files

Configure DSN, AUTH_TOKEN, RELEASE, and CURRENTENV.

DSN is the key for client-server communication and specifies the event destination. AUTH_TOKEN is the user token for access control. RELEASE is the version number for tracking changes. CURRENTENV represents the current environment.

Example (in the .env.test environment file):

VUE_APP_SENTRY_AUTH_TOKEN = 25a7bcf607c19c72af0f30fae9...

VUE_APP_SENTRY_DSN = DSN...

VUE_APP_CURRENTENV = TEST

VUE_APP_RELEASE=staging@1.0.1

2. Install Dependencies

Install @sentry/vue and @sentry/webpack-plugin.

npm install --save @sentry/vue @sentry/webpack-plugin

3. Initialize Sentry

Create a sentry.js file alongside main.js to configure Sentry with required options.

import * as Sentry from "@sentry/vue";

export default {
  install(Vue, options) {
    this.init(Vue, options);
    Vue.prototype.$monitor = Sentry;
    Vue.prototype.$reportHttpError = this.reportHttpError;
    Vue.prototype.$logMessage = this.logMessage;
  },

  init(Vue, { router }) {
    Sentry.init({
      Vue,
      dsn: process.env.VUE_APP_SENTRY_DSN,
      release: process.env.VUE_APP_RELEASE,
      environment: process.env.VUE_APP_CURRENTENV,
      debug: true,
      integrations: [
        Sentry.browserTracingIntegration({ router }),
        Sentry.replayIntegration({
          maskAllText: true,
          blockAllMedia: true,
          networkDetailAllowUrls: [window.location.origin],
        }),
      ],
      beforeSend(event) {
        event.tags.location = window.location.href;
        return event;
      },
      tracePropagationTargets: [],
      tracesSampleRate: 1.0,
      replaysSessionSampleRate: 0.1,
      replaysOnErrorSampleRate: 1.0,
    });
  },

  async logMessage(title, params, stack = {}) {
    try {
      const isError = typeof stack === 'object' && !!stack.stack;
      const errorName = (isError ? stack.message : stack.errMsg) || 'unknown';
      const extra = {
        params,
        errMsg: isError ? stack : stack.errMsg || '',
        href: location.href,
      };

      Sentry.withScope((scope) => {
        scope.setFingerprint([title, errorName]);
        const errMessage = new Error(errorName);
        errMessage.name = `Frontend Error Report:${title}`;
        console.log('Frontend error:', title);
        Sentry.captureException(errMessage, {
          extra,
          level: 'error',
        });
      });
    } catch (error) {
      console.log('monitor:', error);
    }
  },

  async reportHttpError(stack) {
    try {
      const errorMsg = stack.message;
      const errorCode = (stack.response && stack.response.status) || 0;
      if ([401, 403, 40301].includes(errorCode)) {
        return;
      }

      let errorName;
      if (/timeout/i.test(errorMsg) || errorCode === 504) {
        errorName = 'Request Timeout';
      } else if (/^4\d{2}$/.test(errorCode) || /^5\d{2}$/.test(errorCode)) {
        errorName = `Server ${errorCode} Error`;
      } else {
        errorName = 'Call Exception';
      }

      const extra = {
        ...(stack.config || {}),
        errMsg: stack,
        href: location.href,
      };

      errorName === 'Request Timeout' && (extra.networkInfo = await this.fetchResourceData('xmlhttprequest', extra.url));

      Sentry.withScope((scope) => {
        scope.setFingerprint([extra.method, extra.url, errorName]);
        const errMessage = new Error(`Exception URL: ${extra.url}`);
        errMessage.name = errorName;
        Sentry.captureException(errMessage, {
          extra,
          level: 'error',
        });
      });
    } catch (error) {
      console.log('monitor:', error);
    }
  },

  fetchResourceData(type = 'xmlhttprequest', name = '') {
    return new Promise((resolve) => {
      if (!window.performance) {
        resolve({});
        return;
      }
      setTimeout(() => {
        const list = window.performance.getEntries().filter((item) => item.initiatorType === type) || [];

        if (!name) {
          resolve(list);
          return;
        }

        let result = {};
        for (let i = list.length - 1; i >= 0; i -= 1) {
          if (list[i].name && list[i].name.indexOf(name) >= 0) {
            result = list[i];
            break;
          }
        }
        resolve(result);
      }, 50);
    });
  }
};

4. Register as a Vue Plugin

Importt in main.js:

import SentryReport from './sentry.js';

if (process.env.VUE_APP_CURRENTENV !== 'DEV') {
  Vue.use(SentryReport, { router });
}

5. Configure Webpack for SourceMap Upload

Add configureWebpack settings in vue.config.js to map production errors to source code:

configureWebpack: (config) => {
  config.devtool = 'source-map';
  if (process.env.VUE_APP_CURRENTENV !== 'DEV') {
    Object.assign(config, {
      plugins: [
        ...config.plugins,
        sentryWebpackPlugin({
          url: "https://test-sentry.scxljs.cn/",
          release: process.env.VUE_APP_RELEASE,
          include: path.join(process.cwd(), "/dist"),
          ignore: ["node_modules", "vue.config.js"],
          authToken: process.env.VUE_APP_SENTRY_AUTH_TOKEN,
          org: 'sentry',
          project: 'environment-assistant',
          urlPrefix: "./",
          cleanArtifacts: true,
          debug: true,
          sourcemaps: {
            filesToDeleteAfterUpload: ['./dist/js/**/*.map'],
          },
          errorHandler: (error) => {
            console.log('upload SourceMap error', error);
          },
        }),
      ],
    });
  }
};

6. Set User Context

Configure user information after retrieving user data:

const userProfile = {
  username: res.data.userName || '-1',
  id: res.data.userId || '-1',
  email: res.data.userName,
};

this.$monitor.setUser(userProfile);

7. Manual Error Reporting

In axios interceptors: Vue.prototype.$reportHttpError(err)

In business logic: this.$monitor.reportHttpError(err);


Automatic Alert Notifications

Configure Alert rules in the Sentry dashboard to notify relevant team members. Alternatively, use webhooks with tools like Feishu (Lark) to route notifications to appropriate stakeholders. When setting up alerts, ensure the delivery channel includes webhook.


Self-Hosted Deployment

Before deploying, check the hardware requirements at https://develop.sentry.dev/self-hosted/. Ensure network connectivity to download the official image. Relying on proxy connections may introduce unexpected complications.


Common Issues

  1. During initial research, without self-hosted deployment, using the official platform caused "API request failed" errrors when uploading sourcemaps due to network restrictions. Self-hosted deployment resolved this issue.
  2. Avoid using Sentry.close as it may cause mismatch between issues and replay sessions.
  3. sentry-cli has Node.js version requirements—versions 14.16 and below are not supported.

References: Using Sentry for Error Monitoring - Integration with Feishu Workflow

Tags: vue sentry frontend-monitoring error-tracking webpack

Posted on Mon, 20 Jul 2026 17:22:01 +0000 by papa