Layanan sub Pemantauan Pengguna Nyata (Real User Monitoring/RUM) dari Application Real-Time Monitoring Service (ARMS) merekam ulang sesi pengguna untuk melacak error, penundaan, dan exception selama interaksi pengguna. Selain itu, RUM mengintegrasikan pelacakan end-to-end dengan Pemantauan Aplikasi atau Managed Service for OpenTelemetry, menghubungkan setiap permintaan dari browser atau program mini ke rentang (span) backend yang dipicunya. Hal ini memberikan tampilan jejak tunggal mulai dari klik pengguna hingga respons server, sehingga Anda dapat mengidentifikasi secara tepat lokasi terjadinya latensi, error, atau exception.
Prasyarat
Sebelum memulai, pastikan Anda telah:
Mengintegrasikan aplikasi antarmuka depan ke dalam RUM. Lihat Integrasikan aplikasi web atau aplikasi HTML5 atau Integrasikan program mini.
Mengintegrasikan aplikasi backend ke dalam Pemantauan Aplikasi atau Managed Service for OpenTelemetry. Lihat Integrasikan layanan atau komponen.
Memiliki layanan backend berbasis HTTP yang mendukung penguraian header dan propagasi konteks jejak.
Cara kerja
RUM menyisipkan header konteks jejak ke dalam permintaan HTTP keluar dari browser atau program mini. Backend mengurai header tersebut untuk melanjutkan jejak, sehingga membentuk rantai rentang yang terhubung dari browser pengguna hingga layanan backend.
Protokol pelacakan yang didukung
RUM mendukung protokol propagasi berikut:
| Protokol | Berlaku untuk |
|---|---|
W3C (tracecontext) | Klien OpenTelemetry, agen ARMS |
| B3 single dan multi | Zipkin |
| Jaeger | Jaeger |
| sw8 | SkyWalking |
Langkah 1: Aktifkan pelacakan di antarmuka depan
Aktifkan pelacakan saat mengintegrasikan antarmuka depan dengan RUM. Pilih metode integrasi yang sesuai dengan konfigurasi Anda: CDN (synchronous atau asynchronous) atau npm.
Pelacakan dikenai biaya, yang termasuk dalam tagihan untuk Pemantauan Aplikasi atau Managed Service for OpenTelemetry.
Mode sederhana (hanya untuk permintaan same-origin)
Jika aplikasi Anda hanya melakukan permintaan same-origin dan backend menggunakan protokol OpenTelemetry, atur tracing: true. Ini setara dengan { enable: true, sample: 100, tracestate: true, allowedUrls: [], baggage: false }.
Mode sederhana direkomendasikan hanya untuk aplikasi web. Untuk program mini, gunakan mode lengkap dan konfigurasikan parameter allowedUrls, karena permintaan program mini tidak membedakan domain.
CDN synchronous loading
<script>
window.__rum = {
pid: "<your-pid>",
endpoint: "<your-endpoint>",
tracing: true
};
</script>
<script type="text/javascript" src="https://sdk.rum.aliyuncs.com/v2/browser-sdk.js" crossorigin></script>CDN asynchronous loading
<script>
!(function(c,b,d,a){c[a]||(c[a]={});c[a].config=
{
pid: "<your-pid>",
endpoint: "<your-endpoint>",
tracing: true
}
with(b)with(body)with(insertBefore(createElement("script"),firstChild))setAttribute("crossorigin","",src=d)
})(window,document,"https://sdk.rum.aliyuncs.com/v1/bl.js","__bl");
</script>npm
import ArmsRum from '@arms/rum-browser';
ArmsRum.init({
pid: "<your-pid>",
endpoint: "<your-endpoint>",
tracing: true
});Mode lengkap (cross-origin atau multi-protokol)
Gunakan mode lengkap untuk:
Mengirim permintaan yang dilacak ke backend cross-origin.
Menggunakan beberapa protokol propagasi untuk layanan backend yang berbeda.
Menyesuaikan laju pengambilan sampel.
Atur tracing menjadi objek konfigurasi dengan array allowedUrls untuk menentukan URL mana yang akan dilacak dan protokol apa yang digunakan untuk masing-masing.
CDN synchronous loading
<script>
window.__rum = {
pid: "<your-pid>",
endpoint: "<your-endpoint>",
tracing: {
enable: true,
sample: 60, // Laju pengambilan sampel: 0-100. Default: 100.
tracestate: true, // Sertakan header tracestate (hanya W3C). Default: true.
baggage: false, // Sertakan header baggage. Default: false.
allowedUrls: [
{ match: 'https://api.example.com', propagatorTypes: ['tracecontext', 'b3'] },
{ match: /api\.backend\.com/i, propagatorTypes: ['b3multi'] },
{ match: (url) => url.includes('.api'), propagatorTypes: ['jaeger'] }
]
}
};
</script>
<script type="text/javascript" src="https://sdk.rum.aliyuncs.com/v2/browser-sdk.js" crossorigin></script>CDN asynchronous loading
<script>
!(function(c,b,d,a){c[a]||(c[a]={});c[a].config=
{
pid: "<your-pid>",
endpoint: "<your-endpoint>",
tracing: {
enable: true,
sample: 100,
tracestate: true,
baggage: true,
allowedUrls: [
{ match: 'https://api.example.com', propagatorTypes: ['tracecontext', 'b3'] },
{ match: /api\.backend\.com/i, propagatorTypes: ['b3multi'] },
{ match: (url) => url.includes('.api'), propagatorTypes: ['jaeger'] }
]
}
}
with(b)with(body)with(insertBefore(createElement("script"),firstChild))setAttribute("crossorigin","",src=d)
})(window,document,"https://sdk.rum.aliyuncs.com/v1/bl.js","__bl");
</script>npm
import ArmsRum from '@arms/rum-browser';
ArmsRum.init({
pid: "<your-pid>",
endpoint: "<your-endpoint>",
tracing: {
enable: true,
sample: 100,
tracestate: true,
baggage: true,
allowedUrls: [
{ match: 'https://api.example.com', propagatorTypes: ['tracecontext', 'b3'] },
{ match: /api\.backend\.com/i, propagatorTypes: ['b3multi'] },
{ match: (url) => url.includes('.api'), propagatorTypes: ['jaeger'] }
]
}
});Parameter pelacakan
| Parameter | Tipe | Default | Deskripsi |
|---|---|---|---|
tracing.enable | Boolean | true | Mengaktifkan atau menonaktifkan pelacakan. Kembali ke true jika nilai tidak valid. |
tracing.sample | Number | 100 | Laju pengambilan sampel (0–100). Mengontrol persentase permintaan yang menghasilkan jejak. Kembali ke 100 jika nilai tidak valid. |
tracing.tracestate | Boolean | true | Sertakan header tracestate. Hanya berlaku untuk W3C. Jika diatur ke false, permintaan W3C tidak menyertakan header tracestate. |
tracing.baggage | Boolean | false | Sertakan header baggage. Jika diatur ke true, RUM menambahkan header baggage ke permintaan terlepas dari protokolnya. |
tracing.propagatorTypes | PropagatorType | PropagatorType[] | null | Protokol propagasi. Ditimpa oleh tracing.allowedUrls[].propagatorTypes jika ditentukan. Saat beberapa protokol diatur, sw8 memiliki prioritas tertinggi. |
tracing.allowedUrls | Array<MatchOption | TraceOption> | undefined | undefined | URL yang akan dilacak. Untuk aplikasi web, permintaan same-origin dilacak secara default; permintaan cross-origin memerlukan entri eksplisit. Untuk program mini, parameter ini wajib diisi. |
Pencocokan URL (MatchOption)
type MatchOption = string | RegExp | ((value: string) => boolean);Parameter allowedUrls mencocokkan URL lengkap menggunakan salah satu dari tiga metode:
String: cocok dengan URL apa pun yang dimulai dengan nilai yang ditentukan. Misalnya,
'https://api.example.com'cocok denganhttps://api.example.com/v1/resource.RegExp: mencocokkan URL dengan ekspresi reguler.
Fungsi: mengembalikan
truejika URL cocok.
Untuk aplikasi web, aturan default berikut secara otomatis ditambahkan ke tracing.allowedUrls:
{
match: (url) => (/^https?:\/\/*/.test(url) || startsWith(url, location.origin)),
propagatorTypes: ['tracecontext']
}Jenis protokol propagasi (PropagatorType)
type PropagatorType = 'tracecontext' | 'b3' | 'b3multi' | 'jaeger' | 'sw8';Setiap protokol menggunakan format header tertentu:
| Protokol | Format header |
|---|---|
| W3C | traceparent: {version}-{trace-id}-{parent-id}-{trace-flags} |
tracestate: rum={version}&{appType}&{pid}&{sessionId} | |
| B3 single | b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId} |
| B3 multi | X-B3-TraceId: {TraceId} |
X-B3-SpanId: {SpanId} | |
X-B3-ParentSpanId: {ParentSpanId} | |
X-B3-Sampled: {SamplingState} | |
| Jaeger | uber-trace-id: {trace-id}:{span-id}:{parent-span-id}:{flags} |
| sw8 | sw8: {sample}-{trace-id}-{segment-id}-{0}-{service}-{instance}-{endpoint}-{peer} |
Penanganan permintaan cross-origin (CORS)
Header jejak yang disebutkan di atas bukan header HTTP standar atau header yang termasuk dalam daftar aman CORS (CORS-safelisted headers). Jika aplikasi Anda melakukan permintaan cross-origin, konfigurasikan server backend untuk menerima header tersebut dengan menentukan parameter Access-Control-Allow-Headers di server. Program mini selalu memerlukan konfigurasi ini karena permintaannya tidak membedakan domain.
Tambahkan header yang sesuai ke Access-Control-Allow-Headers di server berdasarkan protokol propagasi yang Anda gunakan:
| Protokol | Nilai Access-Control-Allow-Headers yang diperlukan |
|---|---|
| W3C | traceparent, tracestate |
| B3 single | b3 |
| B3 multi | X-B3-TraceId, X-B3-SpanId, X-B3-ParentSpanId, X-B3-Sampled |
| Jaeger | uber-trace-id |
| sw8 | sw8 |
Langkah 2: Verifikasi konfigurasi antarmuka depan
Aplikasi web dan HTML5
Buka aplikasi web Anda di browser.
Buka developer tools dan buka tab Network.
Cari permintaan XHR atau Fetch dari aplikasi Anda. Verifikasi bahwa header permintaan menyertakan header konteks jejak untuk protokol yang Anda pilih.
Untuk W3C, Anda seharusnya melihat header seperti berikut:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: rum=2&web&your-pid&session-idProgram mini (Alipay, WeChat, atau DingTalk)
Jalankan program mini di simulator.
Buka debugger simulator dan buka tab Network.
Verifikasi bahwa permintaan keluar menyertakan header konteks jejak untuk protokol yang Anda pilih.
Langkah 3: Aktifkan pelacakan di backend
Untuk menyelesaikan jejak end-to-end, backend harus mengurai header konteks jejak dari permintaan masuk dan melanjutkan jejak tersebut. Pendekatan ini bergantung pada metode instrumentasi Anda.
Auto-instrumentation (tanpa perubahan kode)
Jika backend Anda menggunakan salah satu metode berikut, pelacakan berjalan otomatis tanpa konfigurasi tambahan:
| Metode instrumentasi | Persyaratan |
|---|---|
| Agen ARMS untuk Java | Versi agen V2.x, V3.x, atau V4.x (V4.x direkomendasikan). Kontainer yang didukung: Apache Tomcat, Jetty, WebLogic, Undertow. Framework yang didukung: Spring Boot, Spring Web MVC. Lihat Komponen dan framework Java yang didukung oleh ARMS. Untuk instalasi, lihat Pantau aplikasi Java. |
| Auto-instrumentation OpenTelemetry (Java) | Mendukung sebagian besar framework utama. Lihat Gunakan OpenTelemetry untuk melaporkan data jejak aplikasi Java. |
| Komponen Jaeger Spring Cloud (Java) | Lihat Gunakan Jaeger untuk melaporkan data aplikasi Java. |
| Agen SkyWalking untuk Java | Diperlukan agen V8.x (menggunakan protokol sw8). Lihat Gunakan SkyWalking untuk melaporkan data aplikasi Java. |
| Agen SkyWalking untuk Go | Mendukung Gin, go-restful, http, Kratos v2, Go Micro, Go Resty. Lihat Gunakan SkyWalking untuk melaporkan data aplikasi Go. |
Instrumentasi manual
Jika auto-instrumentation tidak tersedia untuk framework Anda, uraikan konteks jejak dari header permintaan masuk dan buat rentang anak secara manual.
Java dengan OpenTelemetry
Tambahkan dependensi OpenTelemetry ke proyek Anda.
<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-api</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-trace</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-extension-annotations</artifactId> <version>1.18.0</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-otlp</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-semconv</artifactId> <version>1.30.1-alpha</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId> <version>1.34.1</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-extension-incubator</artifactId> <version>1.35.0-alpha</version> </dependency>Konfigurasikan propagasi W3C selama inisialisasi OpenTelemetry.
Resource resource = Resource.getDefault() .merge(Resource.create(Attributes.of( ResourceAttributes.SERVICE_NAME, "otel-demo", ResourceAttributes.HOST_NAME, "xxxx" ))); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder(OtlpHttpSpanExporter.builder() .setEndpoint("Your Endpoint") .addHeader("Authentication", "Your Token") .build()).build()) .setResource(resource) .build(); openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) // Tambahkan pengaturan propagasi W3C .setPropagators(ContextPropagators.create( TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())) ).buildAndRegisterGlobal(); // Konfigurasikan tracer tracer = ExtendedTracer.create(openTelemetry.getTracer("com.example.tracer", "1.0.0"));Uraikan konteks jejak dari header permintaan dan buat rentang anak.
@RequestMapping("/test") public String test(@RequestHeader Map<String, String> headers) { Span span = OpenTelemetrySupport.getTracer() .spanBuilder("/test") // Uraikan rentang induk dari header .setParentFrom(OpenTelemetrySupport.getContextPropagators(), headers) .setSpanKind(SpanKind.SERVER) .startSpan(); try (Scope scope = span.makeCurrent()) { // Proses permintaan } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "handle parent span error"); } finally { span.end(); } return "success"; }
Java dengan Jaeger
Tambahkan dependensi klien Jaeger.
<dependency> <groupId>io.jaegertracing</groupId> <artifactId>jaeger-client</artifactId> <version>Latest version</version> </dependency>Inisialisasi tracer. Ganti
<endpoint>dengan endpoint dari tab Access point information pada halaman Cluster Configurations di konsol Managed Service for OpenTelemetry.// Ganti manualDemo dengan nama aplikasi Anda io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("manualDemo"); io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration(); sender.withEndpoint("<endpoint>"); config.withSampler(new io.jaegertracing.Configuration.SamplerConfiguration().withType("const").withParam(1)); config.withReporter(new io.jaegertracing.Configuration.ReporterConfiguration().withSender(sender).withMaxQueueSize(10000)); GlobalTracer.register(config.getTracer());Uraikan konteks jejak dan buat rentang anak.
@RequestMapping("/test") public String test(@RequestHeader Map<String, String> headers) { Tracer tracer = GlobalTracer.get(); SpanContext parentCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(headers)); Span span; if (parentCtx != null) { span = tracer.buildSpan("/test").asChildOf(parentCtx).start(); } else { span = tracer.buildSpan("/test").start(); } try (Scope ignored = tracer.activateSpan(span)) { tracer.activeSpan().setTag("methodName", "test"); // Proses permintaan } catch (Throwable t) { TracingHelper.onError(t, span); throw t; } finally { span.finish(); } return "success"; }
Java dengan Zipkin
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry melalui Zipkin. Lihat Gunakan Zipkin untuk melaporkan data aplikasi Java.
Uraikan konteks jejak dari header permintaan:
// Uraikan konteks jejak dari header permintaan
extractor = tracing.propagation().extractor(Request::getHeader);
// Konversi konteks menjadi rentang
oneWayReceive = nextSpan(tracer, extractor.extract(request))
.name("process-request")
.kind(SERVER)
... add tags etc.
// Mulai rentang sisi server dan flush
oneWayReceive.start().flush();
// Buat rentang anak untuk pekerjaan lanjutan
next = tracer.newSpan(oneWayReceive.context()).name("step2").start();Go dengan OpenTelemetry
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry. Lihat Gunakan OpenTelemetry untuk mengirimkan data jejak aplikasi Go.
Buat rentang dari konteks permintaan:
// Inisialisasi tracer
tracer := otel.Tracer(common.TraceInstrumentationName)
// Buat rentang dari konteks permintaan
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
span := trace.SpanFromContext(ctx)
// Proses permintaan
w.Write([]byte("Hello World"))
})Go dengan Jaeger
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry. Lihat Gunakan Jaeger untuk melaporkan data aplikasi Go.
Uraikan konteks rentang dari header permintaan HTTP:
// Uraikan konteks rentang dari header permintaan HTTP
spanCtx, _ := tracer.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
span := tracer.StartSpan("myspan", opentracing.ChildOf(spanCtx))
...
defer span.Finish()Go dengan Zipkin
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry. Lihat Gunakan Zipkin untuk mengirimkan data jejak aplikasi Go.
Ambil rentang dari konteks permintaan:
// Inisialisasi tracer
tracer, err := exampletracer.NewTracer("go-frontend", frontendPort)
// Buat rentang dari konteks permintaan
router.Methods("GET").Path("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
span := zipkin.SpanFromContext(r.Context())
span.Tag("some_key", "some_value")
// Proses permintaan
span.Annotate(time.Now(), "some_event")
})Go dengan SkyWalking
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry. Lihat Gunakan SkyWalking untuk melaporkan data aplikasi Go.
Uraikan konteks jejak dari header sw8:
// Ekstrak konteks dari header permintaan HTTP sw8
span, ctx, err := tracer.CreateEntrySpan(r.Context(), "/api/test", func(key string) (string, error) {
return r.Header.Get(key), nil
})Python dengan OpenTelemetry
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry. Lihat Gunakan OpenTelemetry untuk melaporkan data jejak aplikasi Python.
Uraikan konteks jejak dari header traceparent dan tracestate:
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
tracer = trace.get_tracer(__name__)
@app.route('/test')
def test():
headers = dict(request.headers)
# Uraikan konteks jejak dari header permintaan
carrier = {'traceparent': headers['Traceparent'], 'tracestate': headers['Tracestate']}
ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
with tracer.start_span("test", context=ctx):
# Proses permintaan
return "success"Python dengan Jaeger
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry. Lihat Gunakan Jaeger untuk melaporkan data aplikasi Python.
Uraikan konteks jejak dari header permintaan:
import logging
from flask import Flask
from jaeger_client import Config
from opentracing.ext import tags
from opentracing.propagation import Format
# Inisialisasi tracer
def init_tracer(service, scope_manager=None):
logging.getLogger('').handlers = []
logging.basicConfig(format='%(message)s', level=logging.DEBUG)
config = Config(
config={
'sampler': {
'type': 'const',
'param': 1,
},
'logging': True,
'reporter_batch_size': 1,
},
service_name=service,
scope_manager=scope_manager
)
return config.initialize_tracer()
# Dekorator pelacakan
def trace(tracer, span_name):
def decorator(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
# Uraikan konteks jejak dari header permintaan
span_ctx = tracer.extract(Format.HTTP_HEADERS, request.headers)
span_tags = {tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER}
with tracer.start_active_span(span_name, child_of=span_ctx, tags=span_tags) as scope:
rv = f(*args, **kwargs)
return rv
return wrapped
return decorator
# Contoh endpoint
@app.route('/test')
@trace(tracer, 'test')
def test():
return "success"Python dengan SkyWalking
Integrasikan aplikasi Anda dengan Managed Service for OpenTelemetry. Lihat Gunakan SkyWalking untuk melaporkan data aplikasi Python.
Uraikan konteks jejak dari header sw8:
from skywalking import config, agent
from skywalking.trace.context import SpanContext, get_context
from skywalking.trace.carrier import CarrierItem
# Konfigurasi SkyWalking
config.init(agent_collector_backend_services='<endpoint>',
agent_authentication='<auth-token>')
agent.start()
def handle_request(headers):
# Ekstrak informasi jejak dari header permintaan
carrier_items = []
for item in SpanContext.make_carrier():
carrier_header = headers.get(item.key.lower())
if carrier_header:
carrier_items.append(CarrierItem(item.key, carrier_header))
carrier = SpanContext.make_carrier(carrier_items)
# Ekstrak konteks jejak dari carrier
context = get_context().extract(carrier)
# Buat rentang
with get_context().new_entry_span(op='operation_name') as span:
# Proses permintaan. Rentang dikirimkan secara otomatis saat selesai.
...
# Contoh: header permintaan masuk simulasi
incoming_headers = {
'sw8': '1-My40LjU=-MTY1MTcwNDI5OTk5OA==-xxxx-xx-x-x==',
}
handle_request(incoming_headers)Langkah 4: Lihat data jejak
Setelah pelacakan end-to-end diaktifkan, lihat data jejak lengkap untuk setiap permintaan antarmuka depan di modul RUM pada konsol ARMS.
Klik View Call Chain untuk melihat jejak lengkap suatu permintaan dan topologi aplikasi. Gunakan data ini untuk menganalisis permintaan yang lambat atau gagal dengan mengorelasikan waktu antarmuka depan dengan detail rentang backend.
Rentang teratas dalam jejak adalah rentang root. Nama rentang dan nama aplikasi bervariasi tergantung jenis aplikasi:
| Jenis aplikasi | Nama aplikasi | Awalan nama rentang |
|---|---|---|
| Web atau HTML5 | rum-browser | browser.request: |
| Program mini | rum-miniapp | miniapp.request: |
| Android | rum-android | android.request: |
| iOS | rum-ios | ios.request: |
Tampilan topologi menunjukkan layanan hulu dan hilir yang terlibat dalam setiap permintaan.