OBSERVABILITY MICRO-FRONTENDS WEB-COMPONENTS FRONTEND MONITORING PERFORMANCE ERROR-HANDLING USER-EXPERIENCE DISTRIBUTED-SYSTEMS LOGGING METRICS TRACING CLIENT-SIDE WEB-ARCHITECTURE DEVOPS SRE

Observabilitas untuk Micro-Frontends dan Web Components: Mengintip Kinerja UI Terdistribusi Anda

⏱️ 10 menit baca
👨‍💻

Observabilitas untuk Micro-Frontends dan Web Components: Mengintip Kinerja UI Terdistribusi Anda

1. Pendahuluan

Dunia pengembangan web terus berevolusi, dan saat ini, kita melihat pergeseran signifikan menuju arsitektur yang lebih modular dan terdistribusi. Konsep seperti Micro-Frontends dan Web Components menjadi semakin populer. Mereka menjanjikan skalabilitas, fleksibilitas, dan kemampuan tim yang lebih mandiri dalam mengembangkan fitur. Namun, dengan segala kelebihan ini, muncul pula tantangan baru, terutama dalam hal observabilitas.

Bayangkan Anda memiliki aplikasi e-commerce besar yang dibangun dengan beberapa Micro-Frontends: satu untuk halaman produk, satu untuk keranjang belanja, dan satu lagi untuk proses checkout. Masing-masing Micro-Frontend dikembangkan oleh tim yang berbeda dan mungkin menggunakan framework atau library yang berbeda. Di dalam Micro-Frontends tersebut, banyak komponen UI dibangun menggunakan Web Components untuk reusabilitas dan isolasi.

Dalam skenario kompleks ini, bagaimana Anda bisa tahu jika ada masalah?

Tanpa strategi observabilitas yang kuat, kita akan buta terhadap apa yang sebenarnya terjadi di sisi klien. Kita sulit mendiagnosis performa, tidak bisa mengukur dampak dari setiap perubahan, dan akhirnya, pengalaman pengguna akan terganggu.

Artikel ini akan membahas strategi dan praktik terbaik untuk mengimplementasikan logging, metrics, dan tracing khusus untuk arsitektur Micro-Frontends dan Web Components, membantu Anda mendapatkan visibilitas penuh terhadap kinerja UI terdistribusi Anda.

2. Tantangan Observabilitas di UI Terdistribusi

Sebelum kita menyelami solusinya, mari kita pahami dulu mengapa observabilitas di arsitektur Micro-Frontends dan Web Components menjadi lebih menantang dibandingkan aplikasi monolithic tradisional:

3. Strategi Logging yang Efektif

Logging adalah fondasi observabilitas. Dengan log yang tepat, Anda bisa merekonstruksi apa yang terjadi saat event tertentu atau error muncul.

📌 Centralized & Structured Logging

Praktik Terbaik: Kirim log dari setiap Micro-Frontend/Web Component ke satu sistem log terpusat. Gunakan format log terstruktur (misalnya JSON) agar mudah di-parse dan dianalisis oleh alat monitoring Anda.

// Contoh logging terstruktur di dalam Web Component atau Micro-Frontend
class ProductCard extends HTMLElement {
  connectedCallback() {
    try {
      this.loadProductDetails();
      console.log(JSON.stringify({
        timestamp: new Date().toISOString(),
        level: 'info',
        component: 'ProductCard',
        message: 'Product data loaded successfully',
        productId: this.dataset.productId,
        userId: window.appContext.userId // Contoh konteks global
      }));
    } catch (error) {
      console.error(JSON.stringify({
        timestamp: new Date().toISOString(),
        level: 'error',
        component: 'ProductCard',
        message: 'Failed to load product data',
        productId: this.dataset.productId,
        errorName: error.name,
        errorMessage: error.message,
        stack: error.stack
      }));
    }
  }

  loadProductDetails() {
    // Logika untuk mengambil detail produk
    // ...
  }
}

customElements.define('product-card', ProductCard);

Dengan log JSON, Anda bisa dengan mudah mencari, memfilter, dan menganalisis event berdasarkan component, productId, userId, atau properti lainnya di sistem log Anda (misalnya ELK Stack, Grafana Loki, Sentry, LogRocket).

💡 Contextual Logging dengan Correlation ID

Untuk menghubungkan event yang berbeda di sepanjang perjalanan pengguna atau request, gunakan Correlation ID. Ini adalah pengenal unik yang dilewatkan dari satu Micro-Frontend/Web Component ke yang lain, dan bahkan ke backend.

Praktik Terbaik:

// Di Micro-Frontend shell
const correlationId = crypto.randomUUID(); // Buat ID unik
window.appContext = { ...window.appContext, correlationId };

// Di Web Component/Micro-Frontend yang lebih dalam
console.log(JSON.stringify({
  timestamp: new Date().toISOString(),
  level: 'debug',
  component: 'AddToCartButton',
  message: 'Add to cart clicked',
  productId: '456',
  correlationId: window.appContext.correlationId // Ambil dari konteks
}));

⚠️ Error Boundaries untuk Penanganan Error UI

Untuk aplikasi React, Error Boundaries adalah cara yang elegan untuk menangkap error JavaScript di pohon komponen tanpa merusak seluruh aplikasi. Untuk Web Components atau framework lain, Anda bisa menggunakan try-catch yang lebih spesifik atau event listener global.

Praktik Terbaik:

4. Metrik Kinerja untuk UI Terdistribusi

Logging memberi tahu kita apa yang terjadi, sementara metrik memberi tahu kita seberapa sering dan seberapa baik hal itu terjadi.

🎯 Custom Performance Metrics

Core Web Vitals (LCP, FID/INP, CLS) memang penting untuk seluruh halaman. Namun, dalam arsitektur terdistribusi, Anda juga perlu metrik yang lebih granular untuk setiap bagian UI.

Praktik Terbaik:

// Contoh pengumpulan metrik kustom di Web Component
class DashboardWidget extends HTMLElement {
  connectedCallback() {
    const startTime = performance.now();
    // Logika rendering widget
    this.renderWidgetContent();

    // Gunakan requestAnimationFrame untuk memastikan rendering telah selesai
    requestAnimationFrame(() => {
      const renderTime = performance.now() - startTime;
      // Kirim metrik ke sistem monitoring global
      window.monitor.trackMetric('dashboard-widget-render-time', renderTime, {
        component: 'DashboardWidget',
        widgetType: this.dataset.widgetType,
        correlationId: window.appContext.correlationId
      });
    });
  }

  renderWidgetContent() {
    // ...
  }
}
customElements.define('dashboard-widget', DashboardWidget);

📊 Menggunakan OpenTelemetry untuk Metrik

OpenTelemetry (OTel) adalah standar vendor-agnostic untuk observability yang mencakup metrics, logs, dan traces. Menggunakan OTel JavaScript SDK adalah cara yang bagus untuk mengumpulkan metrik dari frontend Anda dan mengirimnya ke backend observabilitas pilihan Anda.

Praktik Terbaik:

// Konseptual: Inisialisasi OpenTelemetry di Micro-Frontend shell
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getWebAutoInstrumentations } from '@opentelemetry/instrumentation-web';
import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';

diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);

const provider = new WebTracerProvider();
const exporter = new OTLPTraceExporter({
  url: 'http://localhost:4318/v1/traces', // Ganti dengan endpoint OTLP Anda
});
provider.addSpanProcessor(new BatchSpanProcessor(exporter));
provider.register();

registerInstrumentations({
  instrumentations: [
    getWebAutoInstrumentations({
      // Konfigurasi instrumentasi otomatis
      'document-load': { enabled: true },
      'user-interaction': { enabled: true },
      'fetch': { enabled: true },
      'xml-http-request': { enabled: true },
    }),
  ],
});

// Contoh metrik kustom menggunakan OpenTelemetry Metrics API (jika diaktifkan)
// import { metrics } from '@opentelemetry/api';
// const meter = metrics.getMeter('my-frontend-app-metrics');
// const componentRenderCounter = meter.createCounter('component_render_count', {
//   description: 'Counts the number of times a component is rendered',
// });
// componentRenderCounter.add(1, { componentName: 'ProductCard' });

5. Distributed Tracing di Frontend

Distributed tracing memungkinkan Anda melihat seluruh alur request, dari frontend melalui berbagai microservice backend, dan kembali lagi. Ini sangat penting untuk mendiagnosis latensi atau error di sistem terdistribusi.

🔗 Correlation ID sebagai Fondasi Tracing

Seperti pada logging, correlationId adalah kunci untuk tracing. Setiap event dan request harus membawa correlationId yang sama agar bisa dihubungkan dalam satu trace.

🌉 Menghubungkan Frontend dan Backend Tracing

Praktik Terbaik:

// Contoh konseptual: Menggunakan Fetch API dengan OpenTelemetry
import { trace, context, propagation } from '@opentelemetry/api';
const tracer = trace.getTracer('my-frontend-app');

async function fetchProductData(productId, correlationId) {
  const currentContext = context.active();
  const parentSpan = tracer.startSpan('fetchProductData', {
    attributes: { productId, correlationId },
  }, currentContext);

  const newContext = trace.setSpan(currentContext, parentSpan);
  const headers = {};
  propagation.inject(newContext, headers); // Inject traceparent header

  try {
    const response = await fetch(`/api/products/${productId}`, {
      headers: headers,
    });
    const data = await response.json();
    parentSpan.setStatus({ code: SpanStatusCode.OK });
    return data;
  } catch (error) {
    parentSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
    throw error;
  } finally {
    parentSpan.end();
  }
}

Dengan ini, Anda bisa melihat seluruh trace yang membentang dari klik pengguna di Micro-Frontend, melalui API Gateway, microservice produk, database, dan kembali ke rendering UI.

6. Praktik Terbaik dan Pertimbangan

Untuk memastikan implementasi observabilitas Anda efektif dan berkelanjutan: