Skip to content

Monitoring and Analytics

Comprehensive monitoring and analytics strategies for mini programs, including performance monitoring, user analytics, error tracking, and business intelligence.

Monitoring Fundamentals

Key Metrics Overview

  • Performance Metrics: Response time, throughput, resource utilization
  • User Experience Metrics: Page load time, interaction responsiveness
  • Business Metrics: User engagement, conversion rates, revenue
  • Technical Metrics: Error rates, API performance, system health

Monitoring Strategy

  • Real-Time Monitoring: Live system health and performance tracking
  • Historical Analysis: Trend analysis and pattern recognition
  • Predictive Analytics: Forecasting and capacity planning
  • Alerting Systems: Proactive issue detection and notification

Performance Monitoring

Application Performance Monitoring (APM)

javascript
// Performance monitoring implementation
class PerformanceMonitor {
  constructor() {
    this.metrics = new MetricsCollector();
    this.tracer = new DistributedTracer();
    this.profiler = new ApplicationProfiler();
  }
  
  startTransaction(name, context = {}) {
    const transaction = {
      id: this.generateTransactionId(),
      name: name,
      startTime: performance.now(),
      context: context,
      spans: [],
      metadata: {
        userId: context.userId,
        sessionId: context.sessionId,
        userAgent: navigator.userAgent,
        url: window.location.href
      }
    };
    
    this.activeTransactions.set(transaction.id, transaction);
    return transaction;
  }
  
  endTransaction(transactionId, result = {}) {
    const transaction = this.activeTransactions.get(transactionId);
    
    if (!transaction) {
      console.warn('Transaction not found:', transactionId);
      return;
    }
    
    transaction.endTime = performance.now();
    transaction.duration = transaction.endTime - transaction.startTime;
    transaction.result = result;
    
    // Calculate performance metrics
    const metrics = this.calculateMetrics(transaction);
    
    // Send to analytics
    this.sendMetrics({
      type: 'transaction',
      transaction: transaction,
      metrics: metrics,
      timestamp: Date.now()
    });
    
    // Check for performance issues
    this.checkPerformanceThresholds(transaction, metrics);
    
    this.activeTransactions.delete(transactionId);
  }
  
  measurePageLoad() {
    if (typeof window !== 'undefined' && window.performance) {
      const navigation = performance.getEntriesByType('navigation')[0];
      const paint = performance.getEntriesByType('paint');
      
      const metrics = {
        // Core Web Vitals
        firstContentfulPaint: this.getFCP(paint),
        largestContentfulPaint: this.getLCP(),
        cumulativeLayoutShift: this.getCLS(),
        firstInputDelay: this.getFID(),
        
        // Navigation timing
        domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
        loadComplete: navigation.loadEventEnd - navigation.loadEventStart,
        
        // Resource timing
        resourceLoadTime: this.calculateResourceLoadTime(),
        
        // Custom metrics
        timeToInteractive: this.calculateTTI(),
        totalBlockingTime: this.calculateTBT()
      };
      
      this.sendMetrics({
        type: 'page_load',
        metrics: metrics,
        url: window.location.href,
        timestamp: Date.now()
      });
    }
  }
}

Real User Monitoring (RUM)

javascript
// Real user monitoring implementation
class RealUserMonitor {
  constructor() {
    this.sessionTracker = new SessionTracker();
    this.interactionTracker = new InteractionTracker();
    this.errorTracker = new ErrorTracker();
  }
  
  initializeRUM() {
    // Track page views
    this.trackPageView();
    
    // Track user interactions
    this.setupInteractionTracking();
    
    // Track errors
    this.setupErrorTracking();
    
    // Track performance
    this.setupPerformanceTracking();
    
    // Track custom events
    this.setupCustomEventTracking();
  }
  
  trackPageView() {
    const pageView = {
      id: this.generatePageViewId(),
      url: window.location.href,
      title: document.title,
      referrer: document.referrer,
      timestamp: Date.now(),
      sessionId: this.sessionTracker.getSessionId(),
      userId: this.getUserId(),
      deviceInfo: this.getDeviceInfo(),
      performanceMetrics: this.getPagePerformanceMetrics()
    };
    
    this.sendEvent('page_view', pageView);
  }
  
  setupInteractionTracking() {
    // Track clicks
    document.addEventListener('click', (event) => {
      this.trackInteraction('click', {
        element: this.getElementInfo(event.target),
        coordinates: { x: event.clientX, y: event.clientY },
        timestamp: Date.now()
      });
    });
    
    // Track form submissions
    document.addEventListener('submit', (event) => {
      this.trackInteraction('form_submit', {
        form: this.getFormInfo(event.target),
        timestamp: Date.now()
      });
    });
    
    // Track scroll behavior
    let scrollTimeout;
    window.addEventListener('scroll', () => {
      clearTimeout(scrollTimeout);
      scrollTimeout = setTimeout(() => {
        this.trackInteraction('scroll', {
          scrollPosition: window.scrollY,
          scrollPercentage: this.calculateScrollPercentage(),
          timestamp: Date.now()
        });
      }, 100);
    });
  }
  
  trackCustomEvent(eventName, properties = {}) {
    const customEvent = {
      name: eventName,
      properties: properties,
      timestamp: Date.now(),
      sessionId: this.sessionTracker.getSessionId(),
      userId: this.getUserId(),
      context: {
        url: window.location.href,
        userAgent: navigator.userAgent,
        viewport: {
          width: window.innerWidth,
          height: window.innerHeight
        }
      }
    };
    
    this.sendEvent('custom_event', customEvent);
  }
}

Error Tracking and Logging

Error Monitoring System

javascript
// Comprehensive error tracking
class ErrorTracker {
  constructor() {
    this.errorQueue = [];
    this.errorFilters = new Set();
    this.contextCollector = new ContextCollector();
  }
  
  initialize() {
    // Global error handler
    window.addEventListener('error', (event) => {
      this.captureError({
        type: 'javascript_error',
        message: event.message,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        error: event.error,
        stack: event.error?.stack
      });
    });
    
    // Unhandled promise rejection handler
    window.addEventListener('unhandledrejection', (event) => {
      this.captureError({
        type: 'unhandled_promise_rejection',
        reason: event.reason,
        promise: event.promise,
        stack: event.reason?.stack
      });
    });
    
    // Network error handler
    this.setupNetworkErrorTracking();
  }
  
  captureError(errorData) {
    try {
      // Filter out known non-critical errors
      if (this.shouldFilterError(errorData)) {
        return;
      }
      
      const enrichedError = {
        ...errorData,
        id: this.generateErrorId(),
        timestamp: Date.now(),
        sessionId: this.getSessionId(),
        userId: this.getUserId(),
        context: this.contextCollector.collect(),
        breadcrumbs: this.getBreadcrumbs(),
        fingerprint: this.generateErrorFingerprint(errorData),
        severity: this.calculateSeverity(errorData)
      };
      
      // Add to queue
      this.errorQueue.push(enrichedError);
      
      // Send immediately for critical errors
      if (enrichedError.severity === 'critical') {
        this.sendErrorsImmediately([enrichedError]);
      } else {
        this.scheduleErrorBatch();
      }
      
      // Log locally for debugging
      this.logErrorLocally(enrichedError);
    } catch (error) {
      console.error('Error in error tracking:', error);
    }
  }
  
  setupNetworkErrorTracking() {
    // Intercept fetch requests
    const originalFetch = window.fetch;
    window.fetch = async (...args) => {
      const startTime = performance.now();
      
      try {
        const response = await originalFetch(...args);
        
        // Track successful requests
        this.trackNetworkRequest({
          url: args[0],
          method: args[1]?.method || 'GET',
          status: response.status,
          duration: performance.now() - startTime,
          success: true
        });
        
        return response;
      } catch (error) {
        // Track failed requests
        this.captureError({
          type: 'network_error',
          url: args[0],
          method: args[1]?.method || 'GET',
          error: error.message,
          duration: performance.now() - startTime
        });
        
        throw error;
      }
    };
  }
}

Logging System

javascript
// Structured logging implementation
class Logger {
  constructor() {
    this.logLevel = this.getLogLevel();
    this.logBuffer = [];
    this.contextEnrichers = [];
  }
  
  log(level, message, context = {}) {
    if (!this.shouldLog(level)) {
      return;
    }
    
    const logEntry = {
      timestamp: new Date().toISOString(),
      level: level,
      message: message,
      context: this.enrichContext(context),
      sessionId: this.getSessionId(),
      userId: this.getUserId(),
      source: this.getSource(),
      environment: this.getEnvironment()
    };
    
    // Add to buffer
    this.logBuffer.push(logEntry);
    
    // Console output for development
    if (this.isDevelopment()) {
      this.outputToConsole(logEntry);
    }
    
    // Send to logging service
    this.scheduleLogTransmission();
  }
  
  info(message, context) {
    this.log('info', message, context);
  }
  
  warn(message, context) {
    this.log('warn', message, context);
  }
  
  error(message, context) {
    this.log('error', message, context);
  }
  
  debug(message, context) {
    this.log('debug', message, context);
  }
  
  enrichContext(context) {
    let enrichedContext = { ...context };
    
    // Apply context enrichers
    this.contextEnrichers.forEach(enricher => {
      enrichedContext = enricher(enrichedContext);
    });
    
    return enrichedContext;
  }
}

User Analytics

User Behavior Analytics

javascript
// User behavior tracking and analysis
class UserAnalytics {
  constructor() {
    this.eventQueue = [];
    this.userProperties = new Map();
    this.sessionProperties = new Map();
  }
  
  trackEvent(eventName, properties = {}) {
    const event = {
      name: eventName,
      properties: {
        ...properties,
        ...this.getDefaultProperties()
      },
      timestamp: Date.now(),
      sessionId: this.getSessionId(),
      userId: this.getUserId(),
      eventId: this.generateEventId()
    };
    
    this.eventQueue.push(event);
    this.scheduleEventTransmission();
    
    // Update user journey
    this.updateUserJourney(event);
  }
  
  identifyUser(userId, properties = {}) {
    this.userId = userId;
    this.userProperties.set(userId, {
      ...this.userProperties.get(userId),
      ...properties,
      lastSeen: Date.now()
    });
    
    this.trackEvent('user_identified', {
      userId: userId,
      properties: properties
    });
  }
  
  trackPageView(page, properties = {}) {
    this.trackEvent('page_view', {
      page: page,
      url: window.location.href,
      title: document.title,
      referrer: document.referrer,
      ...properties
    });
  }
  
  trackConversion(conversionType, value = 0, properties = {}) {
    this.trackEvent('conversion', {
      type: conversionType,
      value: value,
      currency: properties.currency || 'USD',
      ...properties
    });
  }
  
  createFunnel(funnelName, steps) {
    return {
      name: funnelName,
      steps: steps,
      trackStep: (stepName, properties = {}) => {
        this.trackEvent('funnel_step', {
          funnel: funnelName,
          step: stepName,
          stepIndex: steps.indexOf(stepName),
          ...properties
        });
      }
    };
  }
}

A/B Testing Analytics

javascript
// A/B testing and experimentation
class ExperimentAnalytics {
  constructor() {
    this.activeExperiments = new Map();
    this.userAssignments = new Map();
  }
  
  assignUserToExperiment(experimentId, userId) {
    const experiment = this.activeExperiments.get(experimentId);
    
    if (!experiment) {
      throw new Error(`Experiment ${experimentId} not found`);
    }
    
    // Check if user is already assigned
    let assignment = this.userAssignments.get(`${userId}:${experimentId}`);
    
    if (!assignment) {
      // Assign user to variant
      const variant = this.selectVariant(experiment, userId);
      
      assignment = {
        userId: userId,
        experimentId: experimentId,
        variant: variant,
        assignedAt: Date.now()
      };
      
      this.userAssignments.set(`${userId}:${experimentId}`, assignment);
      
      // Track assignment
      this.trackEvent('experiment_assignment', {
        experimentId: experimentId,
        variant: variant,
        userId: userId
      });
    }
    
    return assignment.variant;
  }
  
  trackExperimentGoal(experimentId, goalName, value = 1) {
    const userId = this.getUserId();
    const assignment = this.userAssignments.get(`${userId}:${experimentId}`);
    
    if (assignment) {
      this.trackEvent('experiment_goal', {
        experimentId: experimentId,
        variant: assignment.variant,
        goal: goalName,
        value: value,
        userId: userId
      });
    }
  }
  
  selectVariant(experiment, userId) {
    // Use consistent hashing for stable assignment
    const hash = this.hashUserId(userId + experiment.id);
    const bucket = hash % 100;
    
    let cumulativeWeight = 0;
    for (const variant of experiment.variants) {
      cumulativeWeight += variant.weight;
      if (bucket < cumulativeWeight) {
        return variant.name;
      }
    }
    
    return experiment.variants[0].name; // fallback
  }
}

Business Intelligence

KPI Dashboard

javascript
// Key Performance Indicators tracking
class KPIDashboard {
  constructor() {
    this.kpis = new Map();
    this.targets = new Map();
    this.alerts = new Map();
  }
  
  defineKPI(name, config) {
    this.kpis.set(name, {
      name: name,
      description: config.description,
      calculation: config.calculation,
      unit: config.unit,
      target: config.target,
      thresholds: config.thresholds,
      updateFrequency: config.updateFrequency || 'daily'
    });
  }
  
  calculateKPI(name, timeRange) {
    const kpi = this.kpis.get(name);
    
    if (!kpi) {
      throw new Error(`KPI ${name} not found`);
    }
    
    const data = this.getDataForTimeRange(timeRange);
    const value = kpi.calculation(data);
    
    const result = {
      name: name,
      value: value,
      unit: kpi.unit,
      target: kpi.target,
      performance: this.calculatePerformance(value, kpi.target),
      trend: this.calculateTrend(name, value, timeRange),
      timestamp: Date.now()
    };
    
    // Check thresholds and send alerts
    this.checkThresholds(name, result);
    
    return result;
  }
  
  generateReport(timeRange, kpiNames = []) {
    const kpisToCalculate = kpiNames.length > 0 ? kpiNames : Array.from(this.kpis.keys());
    
    const report = {
      timeRange: timeRange,
      generatedAt: Date.now(),
      kpis: {},
      summary: {
        totalKPIs: kpisToCalculate.length,
        onTarget: 0,
        belowTarget: 0,
        aboveTarget: 0
      }
    };
    
    kpisToCalculate.forEach(kpiName => {
      const kpiResult = this.calculateKPI(kpiName, timeRange);
      report.kpis[kpiName] = kpiResult;
      
      // Update summary
      if (kpiResult.performance === 'on_target') {
        report.summary.onTarget++;
      } else if (kpiResult.performance === 'below_target') {
        report.summary.belowTarget++;
      } else {
        report.summary.aboveTarget++;
      }
    });
    
    return report;
  }
}

Alerting and Notifications

Alert Management

javascript
// Intelligent alerting system
class AlertManager {
  constructor() {
    this.alertRules = new Map();
    this.alertHistory = [];
    this.notificationChannels = new Map();
  }
  
  createAlertRule(name, config) {
    const rule = {
      name: name,
      condition: config.condition,
      threshold: config.threshold,
      severity: config.severity,
      channels: config.channels,
      cooldown: config.cooldown || 300000, // 5 minutes
      enabled: true,
      lastTriggered: null
    };
    
    this.alertRules.set(name, rule);
  }
  
  evaluateAlerts(metrics) {
    this.alertRules.forEach((rule, name) => {
      if (!rule.enabled) return;
      
      // Check cooldown
      if (rule.lastTriggered && 
          Date.now() - rule.lastTriggered < rule.cooldown) {
        return;
      }
      
      // Evaluate condition
      if (rule.condition(metrics)) {
        this.triggerAlert(name, rule, metrics);
      }
    });
  }
  
  triggerAlert(ruleName, rule, metrics) {
    const alert = {
      id: this.generateAlertId(),
      rule: ruleName,
      severity: rule.severity,
      message: this.generateAlertMessage(rule, metrics),
      metrics: metrics,
      timestamp: Date.now(),
      acknowledged: false,
      resolved: false
    };
    
    // Store alert
    this.alertHistory.push(alert);
    
    // Send notifications
    rule.channels.forEach(channel => {
      this.sendNotification(channel, alert);
    });
    
    // Update rule
    rule.lastTriggered = Date.now();
    
    return alert;
  }
  
  sendNotification(channel, alert) {
    const notificationChannel = this.notificationChannels.get(channel);
    
    if (notificationChannel) {
      notificationChannel.send({
        subject: `Alert: ${alert.rule}`,
        message: alert.message,
        severity: alert.severity,
        timestamp: alert.timestamp
      });
    }
  }
}

Data Visualization

Dashboard Components

javascript
// Interactive dashboard components
class DashboardBuilder {
  constructor() {
    this.widgets = new Map();
    this.layouts = new Map();
    this.dataProviders = new Map();
  }
  
  createWidget(type, config) {
    const widget = {
      id: this.generateWidgetId(),
      type: type,
      title: config.title,
      dataSource: config.dataSource,
      refreshInterval: config.refreshInterval || 60000,
      visualization: config.visualization,
      filters: config.filters || {},
      lastUpdated: null
    };
    
    this.widgets.set(widget.id, widget);
    return widget;
  }
  
  createTimeSeriesChart(config) {
    return this.createWidget('timeseries', {
      ...config,
      visualization: {
        type: 'line',
        xAxis: 'timestamp',
        yAxis: config.metrics,
        aggregation: config.aggregation || 'avg',
        timeRange: config.timeRange || '24h'
      }
    });
  }
  
  createMetricCard(config) {
    return this.createWidget('metric', {
      ...config,
      visualization: {
        type: 'card',
        metric: config.metric,
        format: config.format || 'number',
        comparison: config.comparison,
        trend: config.showTrend !== false
      }
    });
  }
  
  updateWidget(widgetId) {
    const widget = this.widgets.get(widgetId);
    
    if (!widget) return;
    
    const dataProvider = this.dataProviders.get(widget.dataSource);
    
    if (dataProvider) {
      const data = dataProvider.getData(widget.filters);
      widget.data = data;
      widget.lastUpdated = Date.now();
      
      // Emit update event
      this.emit('widget_updated', { widgetId, data });
    }
  }
}

This comprehensive monitoring and analytics guide provides the foundation for implementing robust monitoring systems that ensure optimal performance, user experience, and business success for mini programs.

Connecting Multiple Platforms, Empowering Innovation