当前位置: 首页 > news >正文

前端Sentry数据分析与可视化:构建智能化监控仪表板

前端Sentry数据分析与可视化:构建智能化监控仪表板

在现代前端开发中,仅仅收集错误数据是不够的,更重要的是如何有效地分析和可视化这些数据,从中获得有价值的洞察。本文将深入探讨如何基于Sentry构建智能化的监控仪表板,实现数据的深度分析和可视化展示。

一、Sentry数据分析基础架构

1.1 数据收集与预处理系统

// dataCollectionSystem.js
import * as Sentry from '@sentry/browser';
import { BrowserTracing } from '@sentry/tracing';// 数据收集与预处理系统
export class DataCollectionSystem {constructor(options = {}) {this.options = {enableAdvancedMetrics: true,enableUserBehaviorTracking: true,enablePerformanceAnalytics: true,dataRetentionDays: 30,batchSize: 100,flushInterval: 5000, // 5秒...options};this.dataBuffer = [];this.metricsCache = new Map();this.userSessions = new Map();this.performanceMetrics = new Map();this.setupDataCollection();this.startDataProcessing();}setupDataCollection() {// 增强Sentry配置Sentry.init({dsn: process.env.REACT_APP_SENTRY_DSN,environment: process.env.NODE_ENV,integrations: [new BrowserTracing({// 自定义性能监控beforeNavigate: context => {return {...context,// 添加自定义标签tags: {...context.tags,navigationSource: this.getNavigationSource(),userSegment: this.getUserSegment(),deviceType: this.getDeviceType()}};}})],tracesSampleRate: 0.1,// 自定义事件处理器beforeSend: (event) => {return this.preprocessEvent(event);},// 自定义面包屑处理器beforeBreadcrumb: (breadcrumb) => {return this.preprocessBreadcrumb(breadcrumb);}});// 设置全局事件监听器this.setupGlobalEventListeners();}// 预处理事件数据preprocessEvent(event) {// 添加自定义数据event.extra = {...event.extra,sessionId: this.getCurrentSessionId(),userJourney: this.getUserJourney(),performanceContext: this.getPerformanceContext(),businessContext: this.getBusinessContext()};// 添加自定义标签event.tags = {...event.tags,errorCategory: this.categorizeError(event),impactLevel: this.calculateImpactLevel(event),userType: this.getUserType(),featureFlag: this.getActiveFeatureFlags()};// 缓存事件数据用于分析this.cacheEventData(event);return event;}// 预处理面包屑数据preprocessBreadcrumb(breadcrumb) {// 增强面包屑数据breadcrumb.data = {...breadcrumb.data,sessionTime: Date.now() - this.getSessionStartTime(),pageLoadTime: this.getPageLoadTime(),userInteractionCount: this.getUserInteractionCount()};// 缓存用户行为数据this.cacheUserBehavior(breadcrumb);return breadcrumb;}// 设置全局事件监听器setupGlobalEventListeners() {// 监听页面性能if ('PerformanceObserver' in window) {this.setupPerformanceObserver();}// 监听用户交互this.setupUserInteractionTracking();// 监听网络状态this.setupNetworkMonitoring();// 监听内存使用this.setupMemoryMonitoring();}// 设置性能观察器setupPerformanceObserver() {// 监听导航性能const navObserver = new PerformanceObserver((list) => {list.getEntries().forEach(entry => {this.collectNavigationMetrics(entry);});});navObserver.observe({ entryTypes: ['navigation'] });// 监听资源加载性能const resourceObserver = new PerformanceObserver((list) => {list.getEntries().forEach(entry => {this.collectResourceMetrics(entry);});});resourceObserver.observe({ entryTypes: ['resource'] });// 监听长任务const longTaskObserver = new PerformanceObserver((list) => {list.getEntries().forEach(entry => {this.collectLongTaskMetrics(entry);});});longTaskObserver.observe({ entryTypes: ['longtask'] });// 监听布局偏移const clsObserver = new PerformanceObserver((list) => {list.getEntries().forEach(entry => {this.collectLayoutShiftMetrics(entry);});});clsObserver.observe({ entryTypes: ['layout-shift'] });}// 收集导航性能指标collectNavigationMetrics(entry) {const metrics = {type: 'navigation',timestamp: Date.now(),url: entry.name,duration: entry.duration,domContentLoaded: entry.domContentLoadedEventEnd - entry.domContentLoadedEventStart,loadComplete: entry.loadEventEnd - entry.loadEventStart,firstPaint: this.getFirstPaint(),firstContentfulPaint: this.getFirstContentfulPaint(),largestContentfulPaint: this.getLargestContentfulPaint(),firstInputDelay: this.getFirstInputDelay(),cumulativeLayoutShift: this.getCumulativeLayoutShift(),timeToInteractive: this.getTimeToInteractive()};this.addToDataBuffer('performance', metrics);// 发送到SentrySentry.addBreadcrumb({category: 'performance',message: 'Navigation performance collected',level: 'info',data: metrics});}// 收集资源加载指标collectResourceMetrics(entry) {const metrics = {type: 'resource',timestamp: Date.now(),name: entry.name,duration: entry.duration,size: entry.transferSize,resourceType: this.getResourceType(entry.name),initiatorType: entry.initiatorType,responseStart: entry.responseStart,responseEnd: entry.responseEnd};this.addToDataBuffer('resource', metrics);}// 收集长任务指标collectLongTaskMetrics(entry) {const metrics = {type: 'longtask',timestamp: Date.now(),duration: entry.duration,startTime: entry.startTime,attribution: entry.attribution};this.addToDataBuffer('longtask', metrics);// 如果长任务超过阈值,发送警告if (entry.duration > 100) {Sentry.captureMessage(`Long task detected: ${entry.duration}ms`,'warning',{tags: {category: 'performance',type: 'longtask'},extra: metrics});}}// 收集布局偏移指标collectLayoutShiftMetrics(entry) {if (!entry.hadRecentInput) {const metrics = {type: 'layout-shift',timestamp: Date.now(),value: entry.value,sources: entry.sources?.map(source => ({node: source.node?.tagName,currentRect: source.currentRect,previousRect: source.previousRect}))};this.addToDataBuffer('layout-shift', metrics);}}// 设置用户交互追踪setupUserInteractionTracking() {const interactionEvents = ['click', 'scroll', 'keydown', 'touchstart'];interactionEvents.forEach(eventType => {document.addEventListener(eventType, (event) => {this.trackUserInteraction(eventType, event);}, { passive: true });});}// 追踪用户交互trackUserInteraction(type, event) {const interaction = {type: 'user-interaction',timestamp: Date.now(),eventType: type,target: this.getElementSelector(event.target),coordinates: type === 'click' ? { x: event.clientX, y: event.clientY } : null,sessionTime: Date.now() - this.getSessionStartTime()};this.addToDataBuffer('interaction', interaction);// 更新用户会话数据this.updateUserSession(interaction);}// 设置网络监控setupNetworkMonitoring() {// 监听在线/离线状态window.addEventListener('online', () => {this.addToDataBuffer('network', {type: 'network-status',timestamp: Date.now(),status: 'online'});});window.addEventListener('offline', () => {this.addToDataBuffer('network', {type: 'network-status',timestamp: Date.now(),status: 'offline'});});// 监听连接信息if ('connection' in navigator) {const connection = navigator.connection;const collectConnectionInfo = () => {this.addToDataBuffer('network', {type: 'connection-info',timestamp: Date.now(),effectiveType: connection.effectiveType,downlink: connection.downlink,rtt: connection.rtt,saveData: connection.saveData});};connection.addEventListener('change', collectConnectionInfo);collectConnectionInfo(); // 初始收集}}// 设置内存监控setupMemoryMonitoring() {if ('memory' in performance) {setInterval(() => {const memInfo = performance.memory;this.addToDataBuffer('memory', {type: 'memory-usage',timestamp: Date.now(),usedJSHeapSize: memInfo.usedJSHeapSize,totalJSHeapSize: memInfo.totalJSHeapSize,jsHeapSizeLimit: memInfo.jsHeapSizeLimit,usagePercentage: (memInfo.usedJSHeapSize / memInfo.jsHeapSizeLimit) * 100});}, 30000); // 每30秒收集一次}}// 添加数据到缓冲区addToDataBuffer(category, data) {this.dataBuffer.push({category,data,timestamp: Date.now()});// 如果缓冲区满了,立即处理if (this.dataBuffer.length >= this.options.batchSize) {this.processDataBuffer();}}// 开始数据处理startDataProcessing() {// 定期处理数据缓冲区setInterval(() => {this.processDataBuffer();}, this.options.flushInterval);// 定期清理过期数据setInterval(() => {this.cleanupExpiredData();}, 3600000); // 每小时清理一次}// 处理数据缓冲区processDataBuffer() {if (this.dataBuffer.length === 0) return;const batch = this.dataBuffer.splice(0, this.options.batchSize);// 分析数据this.analyzeDataBatch(batch);// 存储到本地缓存this.storeDataBatch(batch);// 发送聚合数据到Sentrythis.sendAggregatedData(batch);}// 分析数据批次analyzeDataBatch(batch) {const analysis = {performance: this.analyzePerformanceData(batch),userBehavior: this.analyzeUserBehaviorData(batch),errors: this.analyzeErrorData(batch),network: this.analyzeNetworkData(batch)};// 检测异常模式this.detectAnomalies(analysis);// 更新实时指标this.updateRealTimeMetrics(analysis);}// 分析性能数据analyzePerformanceData(batch) {const performanceData = batch.filter(item => ['performance', 'resource', 'longtask', 'layout-shift'].includes(item.category));if (performanceData.length === 0) return null;const analysis = {averageLoadTime: 0,slowestResources: [],longTaskCount: 0,layoutShiftScore: 0,performanceScore: 0};// 计算平均加载时间const navigationData = performanceData.filter(item => item.category === 'performance' && item.data.type === 'navigation');if (navigationData.length > 0) {analysis.averageLoadTime = navigationData.reduce((sum, item) => sum + item.data.duration, 0) / navigationData.length;}// 找出最慢的资源const resourceData = performanceData.filter(item => item.category === 'resource');analysis.slowestResources = resourceData.sort((a, b) => b.data.duration - a.data.duration).slice(0, 5).map(item => ({name: item.data.name,duration: item.data.duration,size: item.data.size}));// 计算长任务数量analysis.longTaskCount = performanceData.filter(item => item.category === 'longtask').length;// 计算布局偏移分数const layoutShiftData = performanceData.filter(item => item.category === 'layout-shift');analysis.layoutShiftScore = layoutShiftData.reduce((sum, item) => sum + item.data.value, 0);// 计算综合性能分数analysis.performanceScore = this.calculatePerformanceScore(analysis);return analysis;}// 分析用户行为数据analyzeUserBehaviorData(batch) {const behaviorData = batch.filter(item => item.category === 'interaction');if (behaviorData.length === 0) return null;const analysis = {totalInteractions: behaviorData.length,interactionTypes: {},averageSessionTime: 0,mostInteractedElements: {},userEngagement: 0};// 统计交互类型behaviorData.forEach(item => {const type = item.data.eventType;analysis.interactionTypes[type] = (analysis.interactionTypes[type] || 0) + 1;});// 统计最多交互的元素behaviorData.forEach(item => {const target = item.data.target;analysis.mostInteractedElements[target] = (analysis.mostInteractedElements[target] || 0) + 1;});// 计算平均会话时间const sessionTimes = behaviorData.map(item => item.data.sessionTime);if (sessionTimes.length > 0) {analysis.averageSessionTime = sessionTimes.reduce((sum, time) => sum + time, 0) / sessionTimes.length;}// 计算用户参与度analysis.userEngagement = this.calculateUserEngagement(analysis);return analysis;}// 检测异常模式detectAnomalies(analysis) {const anomalies = [];// 检测性能异常if (analysis.performance) {if (analysis.performance.averageLoadTime > 5000) {anomalies.push({type: 'performance',severity: 'high',message: `Average load time is ${analysis.performance.averageLoadTime}ms`,data: analysis.performance});}if (analysis.performance.longTaskCount > 10) {anomalies.push({type: 'performance',severity: 'medium',message: `High number of long tasks: ${analysis.performance.longTaskCount}`,data: analysis.performance});}if (analysis.performance.layoutShiftScore > 0.25) {anomalies.push({type: 'performance',severity: 'medium',message: `High cumulative layout shift: ${analysis.performance.layoutShiftScore}`,data: analysis.performance});}}// 检测用户行为异常if (analysis.userBehavior) {if (analysis.userBehavior.userEngagement < 0.3) {anomalies.push({type: 'user-behavior',severity: 'medium',message: `Low user engagement: ${analysis.userBehavior.userEngagement}`,data: analysis.userBehavior});}}// 发送异常报告if (anomalies.length > 0) {this.reportAnomalies(anomalies);}}// 报告异常reportAnomalies(anomalies) {anomalies.forEach(anomaly => {Sentry.captureMessage(`Anomaly detected: ${anomaly.message}`,anomaly.severity === 'high' ? 'error' : 'warning',{tags: {category: 'anomaly-detection',type: anomaly.type,severity: anomaly.severity},extra: anomaly.data});});}// 计算性能分数calculatePerformanceScore(analysis) {let score = 100;// 基于加载时间的扣分if (analysis.averageLoadTime > 3000) {score -= Math.min(30, (analysis.averageLoadTime - 3000) / 100);}// 基于长任务的扣分score -= Math.min(20, analysis.longTaskCount * 2);// 基于布局偏移的扣分score -= Math.min(25, analysis.layoutShiftScore * 100);return Math.max(0, Math.round(score));}// 计算用户参与度calculateUserEngagement(analysis) {let engagement = 0;// 基于交互数量engagement += Math.min(0.4, analysis.totalInteractions / 100);// 基于会话时间engagement += Math.min(0.3, analysis.averageSessionTime / 300000); // 5分钟为满分// 基于交互多样性const typeCount = Object.keys(analysis.interactionTypes).length;engagement += Math.min(0.3, typeCount / 4);return Math.round(engagement * 100) / 100;}// 获取元素选择器getElementSelector(element) {if (!element) return 'unknown';let selector = element.tagName.toLowerCase();if (element.id) {selector += `#${element.id}`;} else if (element.className) {selector += `.${element.className.split(' ').join('.')}`;}return selector;}// 获取资源类型getResourceType(url) {const extension = url.split('.').pop()?.toLowerCase();const typeMap = {'js': 'script','css': 'stylesheet','png': 'image','jpg': 'image','jpeg': 'image','gif': 'image','svg': 'image','woff': 'font','woff2': 'font','ttf': 'font','eot': 'font'};return typeMap[extension] || 'other';}// 获取导航来源getNavigationSource() {if (document.referrer) {try {const referrerDomain = new URL(document.referrer).hostname;const currentDomain = window.location.hostname;return referrerDomain === currentDomain ? 'internal' : 'external';} catch {return 'unknown';}}return 'direct';}// 获取用户细分getUserSegment() {// 这里可以根据业务逻辑实现用户细分const userId = localStorage.getItem('userId');if (!userId) return 'anonymous';// 示例:基于用户ID的简单细分const userType = localStorage.getItem('userType') || 'regular';return userType;}// 获取设备类型getDeviceType() {const userAgent = navigator.userAgent;if (/tablet|ipad|playbook|silk/i.test(userAgent)) {return 'tablet';}if (/mobile|iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(userAgent)) {return 'mobile';}return 'desktop';}// 获取当前会话IDgetCurrentSessionId() {let sessionId = sessionStorage.getItem('sentrySessionId');if (!sessionId) {sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);sessionStorage.setItem('sentrySessionId', sessionId);}return sessionId;}// 获取用户旅程getUserJourney() {const journey = JSON.parse(localStorage.getItem('userJourney') || '[]');return journey.slice(-10); // 返回最近10个页面}// 获取性能上下文getPerformanceContext() {return {connectionType: navigator.connection?.effectiveType || 'unknown',deviceMemory: navigator.deviceMemory || 'unknown',hardwareConcurrency: navigator.hardwareConcurrency || 'unknown',cookieEnabled: navigator.cookieEnabled,language: navigator.language};}// 获取业务上下文getBusinessContext() {return {currentPage: window.location.pathname,referrer: document.referrer,timestamp: Date.now(),timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,screenResolution: `${screen.width}x${screen.height}`,viewportSize: `${window.innerWidth}x${window.innerHeight}`};}// 分类错误categorizeError(event) {const errorType = event.exception?.values[0]?.type;const errorMessage = event.message || event.exception?.values[0]?.value || '';// 网络错误if (errorType === 'NetworkError' || errorMessage.includes('fetch')) {return 'network';}// 语法错误if (errorType === 'SyntaxError') {return 'syntax';}// 引用错误if (errorType === 'ReferenceError') {return 'reference';}// 类型错误if (errorType === 'TypeError') {return 'type';}// 权限错误if (errorType === 'SecurityError') {return 'security';}// 资源加载错误if (errorMessage.includes('Loading chunk') || errorMessage.includes('ChunkLoadError')) {return 'chunk-load';}return 'other';}// 计算影响级别calculateImpactLevel(event) {let score = 0;// 基于错误类型const errorCategory = this.categorizeError(event);const categoryScores = {'security': 10,'network': 7,'chunk-load': 6,'syntax': 8,'reference': 7,'type': 5,'other': 3};score += categoryScores[errorCategory] || 3;// 基于环境if (event.environment === 'production') {score += 3;}// 基于用户类型const userType = this.getUserType();if (userType === 'premium') {score += 2;}if (score >= 10) return 'critical';if (score >= 7) return 'high';if (score >= 4) return 'medium';return 'low';}// 获取用户类型getUserType() {return localStorage.getItem('userType') || 'regular';}// 获取活跃的功能标志getActiveFeatureFlags() {const flags = JSON.parse(localStorage.getItem('featureFlags') || '{}');return Object.keys(flags).filter(key => flags[key]).join(',');}// 缓存事件数据cacheEventData(event) {const key = `event_${Date.now()}`;this.metricsCache.set(key, {type: 'error',data: event,timestamp: Date.now()});}// 缓存用户行为cacheUserBehavior(breadcrumb) {const key = `behavior_${Date.now()}`;this.metricsCache.set(key, {type: 'behavior',data: breadcrumb,timestamp: Date.now()});}// 更新用户会话updateUserSession(interaction) {const userId = this.getUserId();const session = this.userSessions.get(userId) || {startTime: Date.now(),interactions: [],pageViews: 0,errors: 0};session.interactions.push(interaction);session.lastActivity = Date.now();this.userSessions.set(userId, session);}// 获取用户IDgetUserId() {return localStorage.getItem('userId') || 'anonymous';}// 获取会话开始时间getSessionStartTime() {const userId = this.getUserId();const session = this.userSessions.get(userId);return session ? session.startTime : Date.now();}// 获取页面加载时间getPageLoadTime() {const navigation = performance.getEntriesByType('navigation')[0];return navigation ? navigation.loadEventEnd - navigation.loadEventStart : 0;}// 获取用户交互次数getUserInteractionCount() {const userId = this.getUserId();const session = this.userSessions.get(userId);return session ? session.interactions.length : 0;}// 获取First PaintgetFirstPaint() {const paintEntries = performance.getEntriesByType('paint');const fpEntry = paintEntries.find(entry => entry.name === 'first-paint');return fpEntry ? fpEntry.startTime : 0;}// 获取First Contentful PaintgetFirstContentfulPaint() {const paintEntries = performance.getEntriesByType('paint');const fcpEntry = paintEntries.find(entry => entry.name === 'first-contentful-paint');return fcpEntry ? fcpEntry.startTime : 0;}// 获取Largest Contentful PaintgetLargestContentfulPaint() {return new Promise((resolve) => {const observer = new PerformanceObserver((list) => {const entries = list.getEntries();const lastEntry = entries[entries.length - 1];resolve(lastEntry ? lastEntry.startTime : 0);observer.disconnect();});observer.observe({ entryTypes: ['largest-contentful-paint'] });// 超时处理setTimeout(() => {observer.disconnect();resolve(0);}, 5000);});}// 获取First Input DelaygetFirstInputDelay() {return new Promise((resolve) => {const observer = new PerformanceObserver((list) => {const entries = list.getEntries();const firstEntry = entries[0];resolve(firstEntry ? firstEntry.processingStart - firstEntry.startTime : 0);observer.disconnect();});observer.observe({ entryTypes: ['first-input'] });// 超时处理setTimeout(() => {observer.disconnect();resolve(0);}, 5000);});}// 获取Cumulative Layout ShiftgetCumulativeLayoutShift() {return new Promise((resolve) => {let clsValue = 0;const observer = new PerformanceObserver((list) => {for (const entry of list.getEntries()) {if (!entry.hadRecentInput) {clsValue += entry.value;}}});observer.observe({ entryTypes: ['layout-shift'] });// 在页面卸载时返回结果window.addEventListener('beforeunload', () => {observer.disconnect();resolve(clsValue);});// 超时处理setTimeout(() => {observer.disconnect();resolve(clsValue);}, 5000);});}// 获取Time to InteractivegetTimeToInteractive() {// 简化的TTI计算const navigation = performance.getEntriesByType('navigation')[0];if (!navigation) return 0;return navigation.domContentLoadedEventEnd - navigation.fetchStart;}// 存储数据批次storeDataBatch(batch) {try {const existingData = JSON.parse(localStorage.getItem('sentryAnalyticsData') || '[]');const newData = [...existingData, ...batch];// 限制存储大小const maxItems = 1000;if (newData.length > maxItems) {newData.splice(0, newData.length - maxItems);}localStorage.setItem('sentryAnalyticsData', JSON.stringify(newData));} catch (error) {console.warn('Failed to store analytics data:', error);}}// 发送聚合数据sendAggregatedData(batch) {const aggregated = this.aggregateData(batch);if (Object.keys(aggregated).length > 0) {Sentry.addBreadcrumb({category: 'analytics',message: 'Aggregated data collected',level: 'info',data: aggregated});}}// 聚合数据aggregateData(batch) {const aggregated = {performance: {},interactions: {},network: {},memory: {}};batch.forEach(item => {switch (item.category) {case 'performance':this.aggregatePerformanceData(aggregated.performance, item.data);break;case 'interaction':this.aggregateInteractionData(aggregated.interactions, item.data);break;case 'network':this.aggregateNetworkData(aggregated.network, item.data);break;case 'memory':this.aggregateMemoryData(aggregated.memory, item.data);break;}});return aggregated;}// 聚合性能数据aggregatePerformanceData(target, data) {if (data.type === 'navigation') {target.navigationCount = (target.navigationCount || 0) + 1;target.totalDuration = (target.totalDuration || 0) + data.duration;target.averageDuration = target.totalDuration / target.navigationCount;}}// 聚合交互数据aggregateInteractionData(target, data) {target.totalInteractions = (target.totalInteractions || 0) + 1;target.byType = target.byType || {};target.byType[data.eventType] = (target.byType[data.eventType] || 0) + 1;}// 聚合网络数据aggregateNetworkData(target, data) {if (data.type === 'connection-info') {target.connectionType = data.effectiveType;target.downlink = data.downlink;target.rtt = data.rtt;}}// 聚合内存数据aggregateMemoryData(target, data) {if (data.type === 'memory-usage') {target.currentUsage = data.usagePercentage;target.maxUsage = Math.max(target.maxUsage || 0, data.usagePercentage);}}// 清理过期数据cleanupExpiredData() {const cutoffTime = Date.now() - (this.options.dataRetentionDays * 24 * 60 * 60 * 1000);// 清理内存缓存this.metricsCache.forEach((value, key) => {if (value.timestamp < cutoffTime) {this.metricsCache.delete(key);}});// 清理本地存储try {const storedData = JSON.parse(localStorage.getItem('sentryAnalyticsData') || '[]');const filteredData = storedData.filter(item => item.timestamp > cutoffTime);localStorage.setItem('sentryAnalyticsData', JSON.stringify(filteredData));} catch (error) {console.warn('Failed to cleanup stored data:', error);}}// 获取分析数据getAnalyticsData(timeRange = '24h') {const timeRanges = {'1h': 3600000,'24h': 86400000,'7d': 604800000,'30d': 2592000000};const cutoffTime = Date.now() - (timeRanges[timeRange] || timeRanges['24h']);try {const storedData = JSON.parse(localStorage.getItem('sentryAnalyticsData') || '[]');return storedData.filter(item => item.timestamp > cutoffTime);} catch (error) {console.warn('Failed to get analytics data:', error);return [];}}// 获取实时指标getRealTimeMetrics() {const userId = this.getUserId();const session = this.userSessions.get(userId);return {sessionDuration: session ? Date.now() - session.startTime : 0,interactionCount: session ? session.interactions.length : 0,pageViews: session ? session.pageViews : 0,errorCount: session ? session.errors : 0,memoryUsage: this.getCurrentMemoryUsage(),connectionType: navigator.connection?.effectiveType || 'unknown'};}// 获取当前内存使用getCurrentMemoryUsage() {if ('memory' in performance) {const memInfo = performance.memory;return {used: memInfo.usedJSHeapSize,total: memInfo.totalJSHeapSize,limit: memInfo.jsHeapSizeLimit,percentage: (memInfo.usedJSHeapSize / memInfo.jsHeapSizeLimit) * 100};}return null;}
}// 创建全局数据收集系统实例
export const dataCollectionSystem = new DataCollectionSystem();// 导出便捷方法
export const getAnalyticsData = (timeRange) => dataCollectionSystem.getAnalyticsData(timeRange);
export const getRealTimeMetrics = () => dataCollectionSystem.getRealTimeMetrics();

1.2 数据分析引擎

// dataAnalysisEngine.js
import * as Sentry from '@sentry/browser';// 数据分析引擎
export class DataAnalysisEngine {constructor(options = {}) {this.options = {enableTrendAnalysis: true,enableAnomalyDetection: true,enablePredictiveAnalysis: false,analysisInterval: 300000, // 5分钟trendWindow: 86400000, // 24小时anomalyThreshold: 2, // 标准差倍数...options};this.analysisCache = new Map();this.trendData = new Map();this.baselineMetrics = new Map();this.startAnalysisEngine();}startAnalysisEngine() {// 定期执行分析setInterval(() => {this.performAnalysis();}, this.options.analysisInterval);// 初始化基线指标this.initializeBaselines();}// 执行分析async performAnalysis() {try {const data = this.getAnalysisData();if (data.length === 0) return;const analysis = {timestamp: Date.now(),errorAnalysis: await this.analyzeErrors(data),performanceAnalysis: await this.analyzePerformance(data),userBehaviorAnalysis: await this.analyzeUserBehavior(data),trendAnalysis: this.options.enableTrendAnalysis ? await this.analyzeTrends(data) : null,anomalyAnalysis: this.options.enableAnomalyDetection ? await this.detectAnomalies(data) : null};// 缓存分析结果this.cacheAnalysisResult(analysis);// 发送分析结果到Sentrythis.sendAnalysisToSentry(analysis);// 触发告警this.checkAlerts(analysis);} catch (error) {console.error('Analysis failed:', error);Sentry.captureException(error, {tags: {category: 'data-analysis',operation: 'perform-analysis'}});}}// 获取分析数据getAnalysisData() {try {const storedData = JSON.parse(localStorage.getItem('sentryAnalyticsData') || '[]');const cutoffTime = Date.now() - this.options.trendWindow;return storedData.filter(item => item.timestamp > cutoffTime);} catch (error) {console.warn('Failed to get analysis data:', error);return [];}}// 分析错误async analyzeErrors(data) {const errorData = data.filter(item => item.category === 'error');if (errorData.length === 0) {return {totalErrors: 0,errorRate: 0,topErrors: [],errorTrends: {},impactAnalysis: {}};}const analysis = {totalErrors: errorData.length,errorRate: this.calculateErrorRate(errorData, data),topErrors: this.getTopErrors(errorData),errorTrends: this.getErrorTrends(errorData),impactAnalysis: this.analyzeErrorImpact(errorData),categoryDistribution: this.getErrorCategoryDistribution(errorData),severityDistribution: this.getErrorSeverityDistribution(errorData),environmentDistribution: this.getErrorEnvironmentDistribution(errorData)};return analysis;}// 计算错误率calculateErrorRate(errorData, allData) {const totalEvents = allData.length;return totalEvents > 0 ? (errorData.length / totalEvents) * 100 : 0;}// 获取顶级错误getTopErrors(errorData) {const errorCounts = new Map();errorData.forEach(item => {const errorKey = this.getErrorKey(item.data);const count = errorCounts.get(errorKey) || 0;errorCounts.set(errorKey, count + 1);});return Array.from(errorCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([error, count]) => ({ error, count }));}// 获取错误键getErrorKey(errorData) {const errorType = errorData.exception?.values[0]?.type || 'Unknown';const errorMessage = errorData.message || errorData.exception?.values[0]?.value || 'Unknown';return `${errorType}: ${errorMessage.substring(0, 100)}`;}// 获取错误趋势getErrorTrends(errorData) {const hourlyTrends = new Map();const now = Date.now();// 初始化24小时的数据for (let i = 23; i >= 0; i--) {const hour = new Date(now - i * 3600000).getHours();hourlyTrends.set(hour, 0);}// 统计每小时的错误数errorData.forEach(item => {const hour = new Date(item.timestamp).getHours();const count = hourlyTrends.get(hour) || 0;hourlyTrends.set(hour, count + 1);});return Object.fromEntries(hourlyTrends);}// 分析错误影响analyzeErrorImpact(errorData) {const impactLevels = {critical: 0,high: 0,medium: 0,low: 0};const affectedUsers = new Set();const affectedPages = new Set();errorData.forEach(item => {const impact = item.data.tags?.impactLevel || 'low';impactLevels[impact] = (impactLevels[impact] || 0) + 1;if (item.data.user?.id) {affectedUsers.add(item.data.user.id);}if (item.data.request?.url) {affectedPages.add(item.data.request.url);}});return {impactLevels,affectedUsers: affectedUsers.size,affectedPages: affectedPages.size,totalImpactScore: this.calculateTotalImpactScore(impactLevels)};}// 计算总影响分数calculateTotalImpactScore(impactLevels) {const weights = { critical: 10, high: 7, medium: 4, low: 1 };return Object.entries(impactLevels).reduce((total, [level, count]) => total + (count * (weights[level] || 1)), 0);}// 获取错误分类分布getErrorCategoryDistribution(errorData) {const distribution = {};errorData.forEach(item => {const category = item.data.tags?.errorCategory || 'other';distribution[category] = (distribution[category] || 0) + 1;});return distribution;}// 获取错误严重性分布getErrorSeverityDistribution(errorData) {const distribution = {};errorData.forEach(item => {const severity = item.data.level || 'error';distribution[severity] = (distribution[severity] || 0) + 1;});return distribution;}// 获取错误环境分布getErrorEnvironmentDistribution(errorData) {const distribution = {};errorData.forEach(item => {const environment = item.data.environment || 'unknown';distribution[environment] = (distribution[environment] || 0) + 1;});return distribution;}// 分析性能async analyzePerformance(data) {const performanceData = data.filter(item => ['performance', 'resource', 'longtask', 'layout-shift', 'memory'].includes(item.category));if (performanceData.length === 0) {return {overallScore: 0,coreWebVitals: {},resourceAnalysis: {},memoryAnalysis: {},performanceTrends: {}};}const analysis = {overallScore: this.calculateOverallPerformanceScore(performanceData),coreWebVitals: this.analyzeCoreWebVitals(performanceData),resourceAnalysis: this.analyzeResources(performanceData),memoryAnalysis: this.analyzeMemoryUsage(performanceData),performanceTrends: this.getPerformanceTrends(performanceData),longTaskAnalysis: this.analyzeLongTasks(performanceData),layoutShiftAnalysis: this.analyzeLayoutShifts(performanceData)};return analysis;}// 计算整体性能分数calculateOverallPerformanceScore(performanceData) {const navigationData = performanceData.filter(item => item.category === 'performance' && item.data.type === 'navigation');if (navigationData.length === 0) return 0;let totalScore = 0;let scoreCount = 0;navigationData.forEach(item => {const data = item.data;let score = 100;// FCP评分 (0-2.5s: 100分, 2.5-4s: 50分, >4s: 0分)if (data.firstContentfulPaint > 4000) {score -= 30;} else if (data.firstContentfulPaint > 2500) {score -= 15;}// LCP评分 (0-2.5s: 100分, 2.5-4s: 50分, >4s: 0分)if (data.largestContentfulPaint > 4000) {score -= 30;} else if (data.largestContentfulPaint > 2500) {score -= 15;}// FID评分 (0-100ms: 100分, 100-300ms: 50分, >300ms: 0分)if (data.firstInputDelay > 300) {score -= 25;} else if (data.firstInputDelay > 100) {score -= 12;}// CLS评分 (0-0.1: 100分, 0.1-0.25: 50分, >0.25: 0分)if (data.cumulativeLayoutShift > 0.25) {score -= 15;} else if (data.cumulativeLayoutShift > 0.1) {score -= 7;}totalScore += Math.max(0, score);scoreCount++;});return scoreCount > 0 ? Math.round(totalScore / scoreCount) : 0;}// 分析Core Web VitalsanalyzeCoreWebVitals(performanceData) {const navigationData = performanceData.filter(item => item.category === 'performance' && item.data.type === 'navigation');if (navigationData.length === 0) {return {lcp: { average: 0, p75: 0, p95: 0, status: 'unknown' },fid: { average: 0, p75: 0, p95: 0, status: 'unknown' },cls: { average: 0, p75: 0, p95: 0, status: 'unknown' },fcp: { average: 0, p75: 0, p95: 0, status: 'unknown' }};}const lcpValues = navigationData.map(item => item.data.largestContentfulPaint).filter(v => v > 0);const fidValues = navigationData.map(item => item.data.firstInputDelay).filter(v => v > 0);const clsValues = navigationData.map(item => item.data.cumulativeLayoutShift).filter(v => v >= 0);const fcpValues = navigationData.map(item => item.data.firstContentfulPaint).filter(v => v > 0);return {lcp: this.calculateMetricStats(lcpValues, [2500, 4000]),fid: this.calculateMetricStats(fidValues, [100, 300]),cls: this.calculateMetricStats(clsValues, [0.1, 0.25]),fcp: this.calculateMetricStats(fcpValues, [1800, 3000])};}// 计算指标统计calculateMetricStats(values, thresholds) {if (values.length === 0) {return { average: 0, p75: 0, p95: 0, status: 'unknown' };}const sorted = values.sort((a, b) => a - b);const average = values.reduce((sum, val) => sum + val, 0) / values.length;const p75 = this.getPercentile(sorted, 75);const p95 = this.getPercentile(sorted, 95);let status = 'good';if (p75 > thresholds[1]) {status = 'poor';} else if (p75 > thresholds[0]) {status = 'needs-improvement';}return {average: Math.round(average),p75: Math.round(p75),p95: Math.round(p95),status};}// 获取百分位数getPercentile(sortedArray, percentile) {const index = (percentile / 100) * (sortedArray.length - 1);const lower = Math.floor(index);const upper = Math.ceil(index);const weight = index % 1;if (upper >= sortedArray.length) return sortedArray[sortedArray.length - 1];return sortedArray[lower] * (1 - weight) + sortedArray[upper] * weight;}// 分析资源analyzeResources(performanceData) {const resourceData = performanceData.filter(item => item.category === 'resource');if (resourceData.length === 0) {return {totalResources: 0,totalSize: 0,averageLoadTime: 0,slowestResources: [],resourceTypes: {}};}const totalSize = resourceData.reduce((sum, item) => sum + (item.data.size || 0), 0);const totalDuration = resourceData.reduce((sum, item) => sum + item.data.duration, 0);const averageLoadTime = totalDuration / resourceData.length;// 按类型分组const resourceTypes = {};resourceData.forEach(item => {const type = item.data.resourceType || 'other';if (!resourceTypes[type]) {resourceTypes[type] = { count: 0, totalSize: 0, totalDuration: 0 };}resourceTypes[type].count++;resourceTypes[type].totalSize += item.data.size || 0;resourceTypes[type].totalDuration += item.data.duration;});// 计算每种类型的平均值Object.keys(resourceTypes).forEach(type => {const typeData = resourceTypes[type];typeData.averageSize = typeData.totalSize / typeData.count;typeData.averageDuration = typeData.totalDuration / typeData.count;});// 找出最慢的资源const slowestResources = resourceData.sort((a, b) => b.data.duration - a.data.duration).slice(0, 5).map(item => ({name: item.data.name,duration: item.data.duration,size: item.data.size,type: item.data.resourceType}));return {totalResources: resourceData.length,totalSize,averageLoadTime,slowestResources,resourceTypes};}// 分析内存使用analyzeMemoryUsage(performanceData) {const memoryData = performanceData.filter(item => item.category === 'memory');if (memoryData.length === 0) {return {currentUsage: 0,maxUsage: 0,averageUsage: 0,trend: 'stable'};}const usageValues = memoryData.map(item => item.data.usagePercentage);const currentUsage = usageValues[usageValues.length - 1];const maxUsage = Math.max(...usageValues);const averageUsage = usageValues.reduce((sum, val) => sum + val, 0) / usageValues.length;// 计算趋势let trend = 'stable';if (usageValues.length > 1) {const recent = usageValues.slice(-5);const older = usageValues.slice(-10, -5);if (recent.length > 0 && older.length > 0) {const recentAvg = recent.reduce((sum, val) => sum + val, 0) / recent.length;const olderAvg = older.reduce((sum, val) => sum + val, 0) / older.length;if (recentAvg > olderAvg + 5) {trend = 'increasing';} else if (recentAvg < olderAvg - 5) {trend = 'decreasing';}}}return {currentUsage: Math.round(currentUsage),maxUsage: Math.round(maxUsage),averageUsage: Math.round(averageUsage),trend};}// 获取性能趋势getPerformanceTrends(performanceData) {const hourlyTrends = new Map();const now = Date.now();// 初始化24小时的数据for (let i = 23; i >= 0; i--) {const hour = new Date(now - i * 3600000).getHours();hourlyTrends.set(hour, {loadTime: [],resourceCount: 0,longTasks: 0,layoutShifts: 0});}// 统计每小时的性能数据performanceData.forEach(item => {const hour = new Date(item.timestamp).getHours();const hourData = hourlyTrends.get(hour);if (!hourData) return;switch (item.category) {case 'performance':if (item.data.type === 'navigation') {hourData.loadTime.push(item.data.duration);}break;case 'resource':hourData.resourceCount++;break;case 'longtask':hourData.longTasks++;break;case 'layout-shift':hourData.layoutShifts++;break;}});// 计算每小时的平均值const trends = {};hourlyTrends.forEach((data, hour) => {trends[hour] = {averageLoadTime: data.loadTime.length > 0 ? data.loadTime.reduce((sum, time) => sum + time, 0) / data.loadTime.length : 0,resourceCount: data.resourceCount,longTasks: data.longTasks,layoutShifts: data.layoutShifts};});return trends;}// 分析长任务analyzeLongTasks(performanceData) {const longTaskData = performanceData.filter(item => item.category === 'longtask');if (longTaskData.length === 0) {return {totalCount: 0,averageDuration: 0,maxDuration: 0,impactScore: 0};}const durations = longTaskData.map(item => item.data.duration);const totalDuration = durations.reduce((sum, duration) => sum + duration, 0);const averageDuration = totalDuration / durations.length;const maxDuration = Math.max(...durations);// 计算影响分数 (基于数量和持续时间)const impactScore = Math.min(100, (longTaskData.length * 5) + (averageDuration / 10));return {totalCount: longTaskData.length,averageDuration: Math.round(averageDuration),maxDuration: Math.round(maxDuration),impactScore: Math.round(impactScore)};}// 分析布局偏移analyzeLayoutShifts(performanceData) {const layoutShiftData = performanceData.filter(item => item.category === 'layout-shift');if (layoutShiftData.length === 0) {return {totalShifts: 0,cumulativeScore: 0,averageShift: 0,impactLevel: 'good'};}const shiftValues = layoutShiftData.map(item => item.data.value);const cumulativeScore = shiftValues.reduce((sum, value) => sum + value, 0);const averageShift = cumulativeScore / shiftValues.length;// 确定影响级别let impactLevel = 'good';if (cumulativeScore > 0.25) {impactLevel = 'poor';} else if (cumulativeScore > 0.1) {impactLevel = 'needs-improvement';}return {totalShifts: layoutShiftData.length,cumulativeScore: Math.round(cumulativeScore * 1000) / 1000,averageShift: Math.round(averageShift * 1000) / 1000,impactLevel};}// 分析用户行为async analyzeUserBehavior(data) {const behaviorData = data.filter(item => item.category === 'interaction');if (behaviorData.length === 0) {return {totalInteractions: 0,engagementScore: 0,sessionAnalysis: {},interactionPatterns: {},userJourney: []};}const analysis = {totalInteractions: behaviorData.length,engagementScore: this.calculateEngagementScore(behaviorData),sessionAnalysis: this.analyzeUserSessions(behaviorData),interactionPatterns: this.analyzeInteractionPatterns(behaviorData),userJourney: this.analyzeUserJourney(behaviorData),deviceAnalysis: this.analyzeDeviceUsage(behaviorData),timeAnalysis: this.analyzeTimePatterns(behaviorData)};return analysis;}// 计算参与度分数calculateEngagementScore(behaviorData) {let score = 0;// 基于交互数量 (最多40分)const interactionScore = Math.min(40, behaviorData.length * 2);score += interactionScore;// 基于交互多样性 (最多30分)const interactionTypes = new Set(behaviorData.map(item => item.data.eventType));const diversityScore = Math.min(30, interactionTypes.size * 7.5);score += diversityScore;// 基于会话时长 (最多30分)const sessionTimes = behaviorData.map(item => item.data.sessionTime);const maxSessionTime = Math.max(...sessionTimes);const timeScore = Math.min(30, maxSessionTime / 10000); // 10秒为1分score += timeScore;return Math.round(score);}// 分析用户会话analyzeUserSessions(behaviorData) {const sessions = new Map();behaviorData.forEach(item => {const sessionId = item.data.sessionId || 'default';if (!sessions.has(sessionId)) {sessions.set(sessionId, {interactions: [],startTime: item.timestamp,endTime: item.timestamp});}const session = sessions.get(sessionId);session.interactions.push(item);session.endTime = Math.max(session.endTime, item.timestamp);});const sessionAnalysis = {totalSessions: sessions.size,averageSessionDuration: 0,averageInteractionsPerSession: 0,longestSession: 0,shortestSession: Infinity};let totalDuration = 0;let totalInteractions = 0;sessions.forEach(session => {const duration = session.endTime - session.startTime;totalDuration += duration;totalInteractions += session.interactions.length;sessionAnalysis.longestSession = Math.max(sessionAnalysis.longestSession, duration);sessionAnalysis.shortestSession = Math.min(sessionAnalysis.shortestSession, duration);});sessionAnalysis.averageSessionDuration = Math.round(totalDuration / sessions.size);sessionAnalysis.averageInteractionsPerSession = Math.round(totalInteractions / sessions.size);if (sessionAnalysis.shortestSession === Infinity) {sessionAnalysis.shortestSession = 0;}return sessionAnalysis;}// 分析交互模式analyzeInteractionPatterns(behaviorData) {const patterns = {byType: {},byTarget: {},byTime: {},sequences: []};// 按类型统计behaviorData.forEach(item => {const type = item.data.eventType;patterns.byType[type] = (patterns.byType[type] || 0) + 1;});// 按目标元素统计behaviorData.forEach(item => {const target = item.data.target;patterns.byTarget[target] = (patterns.byTarget[target] || 0) + 1;});// 按时间段统计behaviorData.forEach(item => {const hour = new Date(item.timestamp).getHours();patterns.byTime[hour] = (patterns.byTime[hour] || 0) + 1;});// 分析交互序列const sortedData = behaviorData.sort((a, b) => a.timestamp - b.timestamp);for (let i = 0; i < sortedData.length - 1; i++) {const current = sortedData[i];const next = sortedData[i + 1];const timeDiff = next.timestamp - current.timestamp;if (timeDiff < 5000) { // 5秒内的连续交互patterns.sequences.push({from: current.data.eventType,to: next.data.eventType,interval: timeDiff});}}return patterns;}// 分析用户旅程analyzeUserJourney(behaviorData) {const journey = [];const sortedData = behaviorData.sort((a, b) => a.timestamp - b.timestamp);let currentPage = null;let pageStartTime = null;sortedData.forEach(item => {const page = this.extractPageFromInteraction(item);if (page !== currentPage) {if (currentPage) {journey.push({page: currentPage,startTime: pageStartTime,endTime: item.timestamp,duration: item.timestamp - pageStartTime,interactions: sortedData.filter(d => d.timestamp >= pageStartTime && d.timestamp < item.timestamp &&this.extractPageFromInteraction(d) === currentPage).length});}currentPage = page;pageStartTime = item.timestamp;}});// 添加最后一个页面if (currentPage && pageStartTime) {const lastTimestamp = sortedData[sortedData.length - 1].timestamp;journey.push({page: currentPage,startTime: pageStartTime,endTime: lastTimestamp,duration: lastTimestamp - pageStartTime,interactions: sortedData.filter(d => d.timestamp >= pageStartTime &&this.extractPageFromInteraction(d) === currentPage).length});}return journey;}// 从交互中提取页面信息extractPageFromInteraction(interaction) {// 这里可以根据实际情况实现页面提取逻辑return interaction.data.page || window.location.pathname;}// 分析设备使用情况analyzeDeviceUsage(behaviorData) {const deviceTypes = {};const browsers = {};const screenSizes = {};behaviorData.forEach(item => {const deviceType = item.data.deviceType || 'unknown';const browser = item.data.browser || 'unknown';const screenSize = item.data.screenSize || 'unknown';deviceTypes[deviceType] = (deviceTypes[deviceType] || 0) + 1;browsers[browser] = (browsers[browser] || 0) + 1;screenSizes[screenSize] = (screenSizes[screenSize] || 0) + 1;});return {deviceTypes,browsers,screenSizes};}// 分析时间模式analyzeTimePatterns(behaviorData) {const hourlyActivity = new Array(24).fill(0);const dailyActivity = {};behaviorData.forEach(item => {const date = new Date(item.timestamp);const hour = date.getHours();const day = date.toDateString();hourlyActivity[hour]++;dailyActivity[day] = (dailyActivity[day] || 0) + 1;});// 找出最活跃的时间段const peakHour = hourlyActivity.indexOf(Math.max(...hourlyActivity));const peakDay = Object.keys(dailyActivity).reduce((a, b) => dailyActivity[a] > dailyActivity[b] ? a : b);return {hourlyActivity,dailyActivity,peakHour,peakDay,totalActiveDays: Object.keys(dailyActivity).length};}
}// 使用示例
const dataAnalyzer = new SentryDataAnalyzer();// 启动数据收集
dataAnalyzer.startDataCollection();// 定期执行分析
setInterval(async () => {const analysis = await dataAnalyzer.performAnalysis();console.log('分析结果:', analysis);
}, 60000); // 每分钟分析一次

3. 智能化监控仪表板实现

3.1 实时监控仪表板组件

// 智能监控仪表板
class IntelligentMonitoringDashboard {constructor(containerId, options = {}) {this.container = document.getElementById(containerId);this.options = {refreshInterval: 30000, // 30秒刷新间隔theme: 'light',autoResize: true,...options};this.charts = new Map();this.widgets = new Map();this.dataAnalyzer = new SentryDataAnalyzer();this.alertManager = new AlertManager();this.init();}// 初始化仪表板async init() {this.createLayout();this.setupEventListeners();await this.loadInitialData();this.startRealTimeUpdates();// 启用自动调整大小if (this.options.autoResize) {window.addEventListener('resize', this.handleResize.bind(this));}}// 创建布局createLayout() {this.container.innerHTML = `<div class="dashboard-header"><h1>智能监控仪表板</h1><div class="dashboard-controls"><select id="timeRange"><option value="1h">最近1小时</option><option value="6h">最近6小时</option><option value="24h" selected>最近24小时</option><option value="7d">最近7天</option></select><button id="refreshBtn">刷新</button><button id="exportBtn">导出</button></div></div><div class="dashboard-grid"><!-- 关键指标卡片 --><div class="metrics-row"><div class="metric-card" id="errorRate"><h3>错误率</h3><div class="metric-value">-</div><div class="metric-trend">-</div></div><div class="metric-card" id="performanceScore"><h3>性能评分</h3><div class="metric-value">-</div><div class="metric-trend">-</div></div><div class="metric-card" id="userSatisfaction"><h3>用户满意度</h3><div class="metric-value">-</div><div class="metric-trend">-</div></div><div class="metric-card" id="activeUsers"><h3>活跃用户</h3><div class="metric-value">-</div><div class="metric-trend">-</div></div></div><!-- 图表区域 --><div class="charts-row"><div class="chart-container"><h3>错误趋势</h3><canvas id="errorTrendChart"></canvas></div><div class="chart-container"><h3>性能指标</h3><canvas id="performanceChart"></canvas></div></div><div class="charts-row"><div class="chart-container"><h3>用户行为热图</h3><div id="userHeatmap"></div></div><div class="chart-container"><h3>实时告警</h3><div id="alertsList"></div></div></div><!-- 详细分析区域 --><div class="analysis-row"><div class="analysis-panel"><h3>智能分析建议</h3><div id="intelligentInsights"></div></div><div class="analysis-panel"><h3>性能瓶颈识别</h3><div id="bottleneckAnalysis"></div></div></div></div>`;this.addStyles();}// 添加样式addStyles() {const styles = `<style>.dashboard-header {display: flex;justify-content: space-between;align-items: center;padding: 20px;background: #f8f9fa;border-bottom: 1px solid #e9ecef;}.dashboard-controls {display: flex;gap: 10px;}.dashboard-controls select,.dashboard-controls button {padding: 8px 16px;border: 1px solid #ddd;border-radius: 4px;background: white;cursor: pointer;}.dashboard-grid {padding: 20px;}.metrics-row {display: grid;grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));gap: 20px;margin-bottom: 30px;}.metric-card {background: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 4px rgba(0,0,0,0.1);text-align: center;}.metric-card h3 {margin: 0 0 10px 0;color: #666;font-size: 14px;text-transform: uppercase;}.metric-value {font-size: 32px;font-weight: bold;color: #333;margin-bottom: 5px;}.metric-trend {font-size: 12px;color: #666;}.metric-trend.positive {color: #28a745;}.metric-trend.negative {color: #dc3545;}.charts-row {display: grid;grid-template-columns: 1fr 1fr;gap: 20px;margin-bottom: 30px;}.chart-container {background: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 4px rgba(0,0,0,0.1);}.chart-container h3 {margin: 0 0 20px 0;color: #333;}.analysis-row {display: grid;grid-template-columns: 1fr 1fr;gap: 20px;}.analysis-panel {background: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 4px rgba(0,0,0,0.1);}.analysis-panel h3 {margin: 0 0 15px 0;color: #333;}.insight-item {padding: 10px;margin-bottom: 10px;border-left: 4px solid #007bff;background: #f8f9fa;border-radius: 4px;}.insight-item.warning {border-left-color: #ffc107;}.insight-item.error {border-left-color: #dc3545;}.alert-item {padding: 12px;margin-bottom: 8px;border-radius: 4px;border-left: 4px solid #dc3545;background: #f8d7da;}.alert-item.warning {border-left-color: #ffc107;background: #fff3cd;}.alert-item.info {border-left-color: #17a2b8;background: #d1ecf1;}@media (max-width: 768px) {.charts-row,.analysis-row {grid-template-columns: 1fr;}.metrics-row {grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));}}</style>`;document.head.insertAdjacentHTML('beforeend', styles);}// 设置事件监听器setupEventListeners() {// 时间范围选择document.getElementById('timeRange').addEventListener('change', (e) => {this.updateTimeRange(e.target.value);});// 刷新按钮document.getElementById('refreshBtn').addEventListener('click', () => {this.refreshData();});// 导出按钮document.getElementById('exportBtn').addEventListener('click', () => {this.exportData();});}// 加载初始数据async loadInitialData() {try {const analysis = await this.dataAnalyzer.performAnalysis();this.updateDashboard(analysis);} catch (error) {console.error('加载初始数据失败:', error);this.showError('数据加载失败,请稍后重试');}}// 启动实时更新startRealTimeUpdates() {this.updateInterval = setInterval(async () => {try {const analysis = await this.dataAnalyzer.performAnalysis();this.updateDashboard(analysis);} catch (error) {console.error('实时更新失败:', error);}}, this.options.refreshInterval);}// 更新仪表板updateDashboard(analysis) {this.updateMetricCards(analysis);this.updateCharts(analysis);this.updateInsights(analysis);this.updateAlerts(analysis);}// 更新指标卡片updateMetricCards(analysis) {const { errorAnalysis, performanceAnalysis, userBehaviorAnalysis } = analysis;// 错误率const errorRate = errorAnalysis.errorRate;this.updateMetricCard('errorRate', {value: `${errorRate.toFixed(2)}%`,trend: this.calculateTrend(errorRate, 'error'),status: errorRate > 5 ? 'error' : errorRate > 2 ? 'warning' : 'good'});// 性能评分const performanceScore = this.calculatePerformanceScore(performanceAnalysis);this.updateMetricCard('performanceScore', {value: performanceScore,trend: this.calculateTrend(performanceScore, 'performance'),status: performanceScore < 60 ? 'error' : performanceScore < 80 ? 'warning' : 'good'});// 用户满意度const userSatisfaction = userBehaviorAnalysis.engagementScore;this.updateMetricCard('userSatisfaction', {value: `${userSatisfaction}/100`,trend: this.calculateTrend(userSatisfaction, 'satisfaction'),status: userSatisfaction < 60 ? 'error' : userSatisfaction < 80 ? 'warning' : 'good'});// 活跃用户const activeUsers = userBehaviorAnalysis.sessionAnalysis.totalSessions || 0;this.updateMetricCard('activeUsers', {value: activeUsers.toLocaleString(),trend: this.calculateTrend(activeUsers, 'users'),status: 'info'});}// 更新单个指标卡片updateMetricCard(cardId, data) {const card = document.getElementById(cardId);const valueElement = card.querySelector('.metric-value');const trendElement = card.querySelector('.metric-trend');valueElement.textContent = data.value;trendElement.textContent = data.trend.text;trendElement.className = `metric-trend ${data.trend.direction}`;// 更新卡片状态颜色card.className = `metric-card ${data.status}`;}// 计算趋势calculateTrend(currentValue, type) {// 这里应该与历史数据比较,简化实现const change = Math.random() * 20 - 10; // 模拟变化const direction = change > 0 ? 'positive' : change < 0 ? 'negative' : 'neutral';let text = '';if (Math.abs(change) < 1) {text = '保持稳定';} else {text = `${change > 0 ? '↑' : '↓'} ${Math.abs(change).toFixed(1)}%`;}return { direction, text };}// 计算性能评分calculatePerformanceScore(performanceAnalysis) {const { coreWebVitals, resourceAnalysis, longTaskAnalysis } = performanceAnalysis;let score = 100;// LCP评分 (最大内容绘制)if (coreWebVitals.lcp > 4000) {score -= 30;} else if (coreWebVitals.lcp > 2500) {score -= 15;}// FID评分 (首次输入延迟)if (coreWebVitals.fid > 300) {score -= 25;} else if (coreWebVitals.fid > 100) {score -= 10;}// CLS评分 (累积布局偏移)if (coreWebVitals.cls > 0.25) {score -= 20;} else if (coreWebVitals.cls > 0.1) {score -= 10;}// 长任务影响score -= Math.min(15, longTaskAnalysis.impactScore / 10);return Math.max(0, Math.round(score));}// 更新图表updateCharts(analysis) {this.updateErrorTrendChart(analysis.errorAnalysis);this.updatePerformanceChart(analysis.performanceAnalysis);this.updateUserHeatmap(analysis.userBehaviorAnalysis);}// 更新错误趋势图表updateErrorTrendChart(errorAnalysis) {const canvas = document.getElementById('errorTrendChart');const ctx = canvas.getContext('2d');// 简化的图表实现const data = errorAnalysis.trends || [];this.renderLineChart(ctx, data, {title: '错误趋势',color: '#dc3545',yAxisLabel: '错误数量'});}// 更新性能图表updatePerformanceChart(performanceAnalysis) {const canvas = document.getElementById('performanceChart');const ctx = canvas.getContext('2d');const data = [{ label: 'LCP', value: performanceAnalysis.coreWebVitals.lcp },{ label: 'FID', value: performanceAnalysis.coreWebVitals.fid },{ label: 'CLS', value: performanceAnalysis.coreWebVitals.cls * 1000 }];this.renderBarChart(ctx, data, {title: '核心性能指标',colors: ['#007bff', '#28a745', '#ffc107']});}// 更新用户行为热图updateUserHeatmap(userBehaviorAnalysis) {const container = document.getElementById('userHeatmap');const timeAnalysis = userBehaviorAnalysis.timeAnalysis;if (!timeAnalysis) {container.innerHTML = '<p>暂无用户行为数据</p>';return;}const hourlyData = timeAnalysis.hourlyActivity;const maxActivity = Math.max(...hourlyData);let heatmapHTML = '<div class="heatmap-grid">';for (let hour = 0; hour < 24; hour++) {const activity = hourlyData[hour] || 0;const intensity = maxActivity > 0 ? activity / maxActivity : 0;const opacity = Math.max(0.1, intensity);heatmapHTML += `<div class="heatmap-cell" style="background-color: rgba(0, 123, 255, ${opacity})"title="${hour}:00 - ${activity} 次交互">${hour}</div>`;}heatmapHTML += '</div>';// 添加热图样式const heatmapStyles = `<style>.heatmap-grid {display: grid;grid-template-columns: repeat(12, 1fr);gap: 2px;margin-top: 10px;}.heatmap-cell {aspect-ratio: 1;display: flex;align-items: center;justify-content: center;border-radius: 4px;font-size: 12px;color: white;font-weight: bold;cursor: pointer;transition: transform 0.2s;}.heatmap-cell:hover {transform: scale(1.1);}</style>`;if (!document.querySelector('.heatmap-styles')) {document.head.insertAdjacentHTML('beforeend', heatmapStyles.replace('<style>', '<style class="heatmap-styles">'));}container.innerHTML = heatmapHTML;}// 渲染折线图renderLineChart(ctx, data, options) {const canvas = ctx.canvas;const width = canvas.width;const height = canvas.height;ctx.clearRect(0, 0, width, height);if (!data || data.length === 0) {ctx.fillStyle = '#666';ctx.font = '14px Arial';ctx.textAlign = 'center';ctx.fillText('暂无数据', width / 2, height / 2);return;}// 简化的折线图实现const padding = 40;const chartWidth = width - padding * 2;const chartHeight = height - padding * 2;const maxValue = Math.max(...data.map(d => d.value));const minValue = Math.min(...data.map(d => d.value));const valueRange = maxValue - minValue || 1;ctx.strokeStyle = options.color;ctx.lineWidth = 2;ctx.beginPath();data.forEach((point, index) => {const x = padding + (index / (data.length - 1)) * chartWidth;const y = padding + chartHeight - ((point.value - minValue) / valueRange) * chartHeight;if (index === 0) {ctx.moveTo(x, y);} else {ctx.lineTo(x, y);}});ctx.stroke();}// 渲染柱状图renderBarChart(ctx, data, options) {const canvas = ctx.canvas;const width = canvas.width;const height = canvas.height;ctx.clearRect(0, 0, width, height);if (!data || data.length === 0) {ctx.fillStyle = '#666';ctx.font = '14px Arial';ctx.textAlign = 'center';ctx.fillText('暂无数据', width / 2, height / 2);return;}const padding = 40;const chartWidth = width - padding * 2;const chartHeight = height - padding * 2;const barWidth = chartWidth / data.length * 0.8;const barSpacing = chartWidth / data.length * 0.2;const maxValue = Math.max(...data.map(d => d.value));data.forEach((item, index) => {const barHeight = (item.value / maxValue) * chartHeight;const x = padding + index * (barWidth + barSpacing);const y = padding + chartHeight - barHeight;ctx.fillStyle = options.colors[index % options.colors.length];ctx.fillRect(x, y, barWidth, barHeight);// 绘制标签ctx.fillStyle = '#333';ctx.font = '12px Arial';ctx.textAlign = 'center';ctx.fillText(item.label, x + barWidth / 2, height - 10);ctx.fillText(item.value.toFixed(0), x + barWidth / 2, y - 5);});}// 更新智能分析建议updateInsights(analysis) {const container = document.getElementById('intelligentInsights');const insights = this.generateInsights(analysis);let insightsHTML = '';insights.forEach(insight => {insightsHTML += `<div class="insight-item ${insight.type}"><strong>${insight.title}</strong><p>${insight.description}</p>${insight.action ? `<small>建议: ${insight.action}</small>` : ''}</div>`;});container.innerHTML = insightsHTML || '<p>暂无分析建议</p>';}// 生成智能分析建议generateInsights(analysis) {const insights = [];const { errorAnalysis, performanceAnalysis, userBehaviorAnalysis } = analysis;// 错误率分析if (errorAnalysis.errorRate > 5) {insights.push({type: 'error',title: '错误率过高',description: `当前错误率为 ${errorAnalysis.errorRate.toFixed(2)}%,超过了5%的警戒线`,action: '建议立即检查最近的代码部署,排查高频错误原因'});} else if (errorAnalysis.errorRate > 2) {insights.push({type: 'warning',title: '错误率偏高',description: `当前错误率为 ${errorAnalysis.errorRate.toFixed(2)}%,需要关注`,action: '建议分析错误类型分布,优化容错处理'});}// 性能分析const performanceScore = this.calculatePerformanceScore(performanceAnalysis);if (performanceScore < 60) {insights.push({type: 'error',title: '性能严重不足',description: `性能评分仅为 ${performanceScore},用户体验较差`,action: '建议进行性能优化:代码分割、资源压缩、CDN加速等'});} else if (performanceScore < 80) {insights.push({type: 'warning',title: '性能有待提升',description: `性能评分为 ${performanceScore},还有优化空间`,action: '建议优化Core Web Vitals指标,特别关注LCP和FID'});}// 长任务分析if (performanceAnalysis.longTaskAnalysis.totalCount > 10) {insights.push({type: 'warning',title: '长任务过多',description: `检测到 ${performanceAnalysis.longTaskAnalysis.totalCount} 个长任务`,action: '建议使用Web Workers或时间切片技术优化长任务'});}// 布局偏移分析if (performanceAnalysis.layoutShiftAnalysis.impactLevel === 'poor') {insights.push({type: 'error',title: '布局偏移严重',description: `CLS评分为 ${performanceAnalysis.layoutShiftAnalysis.cumulativeScore}`,action: '建议为图片和广告设置固定尺寸,避免动态内容插入'});}// 用户参与度分析if (userBehaviorAnalysis.engagementScore < 60) {insights.push({type: 'warning',title: '用户参与度较低',description: `用户参与度评分为 ${userBehaviorAnalysis.engagementScore}`,action: '建议优化用户界面和交互体验,增加用户粘性'});}// 会话分析const sessionAnalysis = userBehaviorAnalysis.sessionAnalysis;if (sessionAnalysis.averageSessionDuration < 30000) { // 30秒insights.push({type: 'info',title: '会话时长较短',description: `平均会话时长为 ${Math.round(sessionAnalysis.averageSessionDuration / 1000)}`,action: '建议分析用户流失点,优化页面内容和导航'});}return insights;}// 更新告警列表updateAlerts(analysis) {const container = document.getElementById('alertsList');const alerts = this.generateAlerts(analysis);let alertsHTML = '';alerts.forEach(alert => {alertsHTML += `<div class="alert-item ${alert.severity}"><div class="alert-header"><strong>${alert.title}</strong><span class="alert-time">${alert.time}</span></div><p>${alert.message}</p></div>`;});container.innerHTML = alertsHTML || '<p>暂无告警信息</p>';}// 生成告警信息generateAlerts(analysis) {const alerts = [];const now = new Date();// 基于分析结果生成告警const { errorAnalysis, performanceAnalysis } = analysis;if (errorAnalysis.errorRate > 10) {alerts.push({severity: 'error',title: '严重错误告警',message: `错误率达到 ${errorAnalysis.errorRate.toFixed(2)}%,需要立即处理`,time: now.toLocaleTimeString()});}if (performanceAnalysis.coreWebVitals.lcp > 4000) {alerts.push({severity: 'warning',title: 'LCP性能告警',message: `最大内容绘制时间为 ${performanceAnalysis.coreWebVitals.lcp}ms,超过4秒阈值`,time: now.toLocaleTimeString()});}if (performanceAnalysis.longTaskAnalysis.totalCount > 20) {alerts.push({severity: 'warning',title: '长任务告警',message: `检测到 ${performanceAnalysis.longTaskAnalysis.totalCount} 个长任务,可能影响用户体验`,time: now.toLocaleTimeString()});}return alerts.slice(0, 5); // 只显示最近5条告警}// 更新时间范围updateTimeRange(range) {this.currentTimeRange = range;this.refreshData();}// 刷新数据async refreshData() {try {const analysis = await this.dataAnalyzer.performAnalysis();this.updateDashboard(analysis);this.showSuccess('数据已刷新');} catch (error) {console.error('刷新数据失败:', error);this.showError('数据刷新失败');}}// 导出数据exportData() {try {const data = {timestamp: new Date().toISOString(),timeRange: this.currentTimeRange,analysis: this.lastAnalysis};const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'});const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = `sentry-analysis-${Date.now()}.json`;document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(url);this.showSuccess('数据已导出');} catch (error) {console.error('导出数据失败:', error);this.showError('数据导出失败');}}// 处理窗口大小调整handleResize() {// 重新渲染图表if (this.lastAnalysis) {this.updateCharts(this.lastAnalysis);}}// 显示成功消息showSuccess(message) {this.showNotification(message, 'success');}// 显示错误消息showError(message) {this.showNotification(message, 'error');}// 显示通知showNotification(message, type) {const notification = document.createElement('div');notification.className = `notification ${type}`;notification.textContent = message;notification.style.cssText = `position: fixed;top: 20px;right: 20px;padding: 12px 20px;border-radius: 4px;color: white;font-weight: bold;z-index: 1000;animation: slideIn 0.3s ease-out;background: ${type === 'success' ? '#28a745' : '#dc3545'};`;document.body.appendChild(notification);setTimeout(() => {notification.style.animation = 'slideOut 0.3s ease-in';setTimeout(() => {document.body.removeChild(notification);}, 300);}, 3000);}// 销毁仪表板destroy() {if (this.updateInterval) {clearInterval(this.updateInterval);}if (this.options.autoResize) {window.removeEventListener('resize', this.handleResize.bind(this));}this.container.innerHTML = '';}}// 告警管理器class AlertManager {constructor(options = {}) {this.options = {maxAlerts: 100,retentionTime: 24 * 60 * 60 * 1000, // 24小时...options};this.alerts = [];this.subscribers = [];}// 添加告警addAlert(alert) {const alertWithId = {id: Date.now() + Math.random(),timestamp: Date.now(),...alert};this.alerts.unshift(alertWithId);// 限制告警数量if (this.alerts.length > this.options.maxAlerts) {this.alerts = this.alerts.slice(0, this.options.maxAlerts);}// 通知订阅者this.notifySubscribers(alertWithId);// 清理过期告警this.cleanupExpiredAlerts();}// 获取告警列表getAlerts(filter = {}) {let filteredAlerts = [...this.alerts];if (filter.severity) {filteredAlerts = filteredAlerts.filter(alert => alert.severity === filter.severity);}if (filter.since) {filteredAlerts = filteredAlerts.filter(alert => alert.timestamp >= filter.since);}if (filter.limit) {filteredAlerts = filteredAlerts.slice(0, filter.limit);}return filteredAlerts;}// 订阅告警subscribe(callback) {this.subscribers.push(callback);// 返回取消订阅函数return () => {const index = this.subscribers.indexOf(callback);if (index > -1) {this.subscribers.splice(index, 1);}};}// 通知订阅者notifySubscribers(alert) {this.subscribers.forEach(callback => {try {callback(alert);} catch (error) {console.error('告警通知失败:', error);}});}// 清理过期告警cleanupExpiredAlerts() {const now = Date.now();this.alerts = this.alerts.filter(alert => now - alert.timestamp < this.options.retentionTime);}// 清除所有告警clearAlerts() {this.alerts = [];}}// 使用示例const dashboard = new IntelligentMonitoringDashboard('dashboard-container', {refreshInterval: 30000,theme: 'light',autoResize: true});// 监听告警const alertManager = new AlertManager();alertManager.subscribe(alert => {console.log('新告警:', alert);// 可以在这里添加更多的告警处理逻辑// 比如发送邮件、推送通知等});

4. 核心价值与实施建议

4.1 核心价值

数据驱动决策

  • 基于真实用户数据进行产品优化
  • 量化用户体验指标
  • 识别性能瓶颈和改进机会

智能化监控

  • 自动异常检测和告警
  • 智能分析建议生成
  • 实时性能监控和优化

可视化洞察

  • 直观的数据展示和趋势分析
  • 多维度数据关联分析
  • 自定义仪表板和报告

4.2 实施建议

分阶段实施

  1. 基础阶段: 实现数据收集和基本分析
  2. 进阶阶段: 添加智能分析和可视化
  3. 高级阶段: 构建完整的监控体系

团队协作

  • 开发团队负责数据收集和技术实现
  • 产品团队参与指标定义和分析
  • 运维团队负责监控和告警处理

持续改进

  • 定期评估和优化监控策略
  • 根据业务需求调整分析维度
  • 持续完善告警规则和阈值

5. 未来发展趋势

5.1 AI驱动的智能分析

机器学习预测

  • 基于历史数据预测性能趋势
  • 智能异常检测和根因分析
  • 自动化性能优化建议

自然语言处理

  • 智能错误分类和聚合
  • 自动生成分析报告
  • 语音交互式数据查询

5.2 边缘计算集成

边缘数据处理

  • 就近处理用户数据,减少延迟
  • 实时性能监控和优化
  • 分布式数据分析架构

智能缓存策略

  • 基于用户行为的智能缓存
  • 动态资源优化和分发
  • 边缘计算性能提升

5.3 隐私保护增强

数据脱敏技术

  • 自动识别和保护敏感信息
  • 差分隐私数据分析
  • 联邦学习模型训练

合规性自动化

  • 自动化GDPR合规检查
  • 数据生命周期管理
  • 隐私影响评估工具

总结

前端Sentry数据分析与可视化是构建现代Web应用监控体系的重要组成部分。通过系统化的数据收集、智能化的分析处理和直观的可视化展示,我们可以:

  1. 全面了解应用状态: 从错误监控到性能分析,从用户行为到业务指标
  2. 快速识别问题: 通过智能告警和异常检测,及时发现和解决问题
  3. 数据驱动优化: 基于真实数据进行产品决策和性能优化
  4. 提升用户体验: 通过持续监控和改进,不断提升用户满意度

随着技术的不断发展,前端监控将更加智能化、自动化和个性化。掌握这些技术和方法,将帮助我们构建更加稳定、高效和用户友好的Web应用。

http://www.dtcms.com/a/354868.html

相关文章:

  • 大数据毕业设计选题推荐-基于大数据的痴呆症预测数据可视化分析系统-Spark-Hadoop-Bigdata
  • 重置 Windows Server 2019 管理员账户密码
  • 基于SamOut的音频Token序列生成模型训练指南
  • 【Rust】 3. 语句与表达式笔记
  • Flask测试平台开发实战-第一篇
  • 安科瑞三相智能安全配电装置在养老院配电系统中的应用
  • Flask测试平台开发,登陆重构
  • F010 Vue+Flask豆瓣图书推荐大数据可视化平台系统源码
  • 新型Zip Slip漏洞允许攻击者在解压过程中操纵ZIP文件
  • 大模型训练推理优化(5): FlexLink —— NVLink 带宽无损提升27%
  • Android Glide插件化开发实战:模块化加载与自定义扩展
  • 使用MySQL计算斐波那契数列
  • 三轴云台之闭环反馈技术篇
  • Vue + ECharts 中 Prop 数据被修改导致图表合并的问题及解决方案
  • Vibe Coding到底是什么:什么是 Vibe Coding?AI编程?
  • SpringCloud OpenFeign 远程调用(RPC)
  • Web网络开发 -- 常见CSS属性
  • 前端RSA加密遇到Java后端解密失败的问题解决
  • 创建uniApp小程序项目vue3+ts+uniapp
  • 文档格式转换软件 一键Word转PDF
  • PDF转长图工具,一键多页转图片
  • 【Deepseek】Windows MFC/Win32 常用核心 API 汇总
  • Spring Boot对访问密钥加解密——HMAC-SHA256
  • Docker Swarm 与 Kubernetes (K8s) 全面对比教程
  • SMU算法与人工智能创新实践班SMU2025 Summer 7th 参考题解
  • 虚幻基础:角色变换角色视角蒙太奇运动
  • Python篇---返回类型
  • 安卓/ios按键精灵脚本开发工具:OpenCV.FindImgAll命令介绍
  • 工业电子看板赋能线缆工厂生产高效运转
  • 可扩展系统设计的黄金法则与Go语言实践|得物技术