The Real User Monitoring (RUM) sub-service of Application Real-Time Monitoring Service (ARMS) replays user sessions to track errors, delays, and exceptions that occur during user interaction. In addition, RUM implements end-to-end tracing in conjunction with Application Monitoring. This topic describes how to enable end-to-end tracing for a web application or mini program.
Prerequisites
The frontend is monitored in RUM. For more information, see Integrate a web application or an HTML5 application and Integrate a mini program.
The backend is monitored in Application Monitoring or Managed Service for OpenTelemetry. For more information, see Integrate services or components.
The backend provides an HTTP-based web service for header parsing and trace context propagation.
Supported tracing protocols
RUM supports the following mainstream tracing protocols for propagation:
W3C: applicable to the OpenTelemetry client and the ARMS agent.
B3 single and multi: applicable to Zipkin.
Jaeger
sw8: applicable to SkyWalking.
Enable tracing for the frontend
Enable tracing when you integrate the frontend into RUM.
Tracing charges fees, which are included in the bills of Application Monitoring or Managed Service for OpenTelemetry.
Synchronous loading through CDN
Simple mode
We recommend that you use this mode only for a web application. For a mini program, you must use the full mode and configure the allowedUrls parameter because the requests of mini programs do not differentiate domains.
This mode is applicable to scenarios that do not involve cross-origin requests. By default, the backend adopts the OpenTelemetry protocol. The allowedUrls parameter can be set to undefined, but the URLs of intra-domain requests are added to the whitelist.
<script>
window.__rum = {
pid: "<your pid>",
endpoint: "<your endpoint>",
// Specify more parameters based on your needs.
// Specify whether to enable tracing. Valid values: true and false. Default value: false.
tracing: true // This configuration is equivalent to { enable: true, sample: 100, tracestate: true, allowedUrls:[], baggage: false }.
};
</script>
<script type="text/javascript" src="https://sdk.rum.aliyuncs.com/v2/browser-sdk.js " crossorigin></script>
Full mode
In this mode, you need to configure all parameters. Set the allowedUrls parameter to an array of tracing options.
<script>
window.__rum = {
pid: "<your pid>",
endpoint: "<your endpoint>",
// Specify more parameters based on your needs.
// Specify whether to enable tracing. Valid values: true and false. Default value: false.
tracing: {
enable: true, // Specify whether to enable tracing.
sample: 60, // Specify the sampling rate. Default value: 100.
tracestate: true, // Specify whether to enable the tracestate header. Valid values: true and false. Default value: true.
baggage: false, // Specify whether to enable the baggage header. Valid values: true and false. Default value: false.
allowedUrls:[
{match: 'tracontext', propagatorTypes:['tracecontext', 'b3']}, // Matches URLs prefixed with https://api.aliyun.com based on W3C and B3 single.
{match: /api\.alibaba\.com/i, propagatorTypes:['b3multi']}, // Uses a regular expression to match URLs containing api.aliyun.com based on B3 multi.
{match: (url)=>url.includes('.api'), propagatorTypes:['jaeger']}, // Uses a function to match URLs containing .api based on Jaeger.
]
}
};
</script>
<script type="text/javascript" src="https://sdk.rum.aliyuncs.com/v2/browser-sdk.js " crossorigin></script>
Asynchronous loading through CDN
Simple mode
We recommend that you use this mode only for a web application. For a mini program, you must use the full mode and configure the allowedUrls parameter because the requests of mini programs do not differentiate domains.
This mode is applicable to scenarios that do not involve cross-origin requests. By default, the backend adopts the OpenTelemetry protocol. The allowedUrls parameter can be set to undefined, but the URLs of intra-domain requests are added to the whitelist.
<script>
!(function(c,b,d,a){c[a]||(c[a]={});c[a].config=
{
pid: "<your pid>",
endpoint: "<your endpoint>",
// Specify more parameters based on your needs.
// Specify whether to enable tracing. Valid values: true and false. Default value: false.
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>
Full mode
In this mode, you need to configure all parameters. Set the allowedUrls parameter to an array of tracing options.
<script>
!(function(c,b,d,a){c[a]||(c[a]={});c[a].config=
{
pid: "<your pid>",
endpoint: "<your endpoint>",
// Specify more parameters based on your needs.
// Specify whether to enable tracing. Valid values: true and false. Default value: false.
tracing: {
enable: true, // Specify whether to enable tracing.
sample: 100, // Specify the sampling rate. Default value: 100.
tracestate: true, // Specify whether to enable the tracestate header. Valid values: true and false. Default value: true.
baggage: true, // Specify whether to enable the baggage header. Valid values: true and false. Default value: false.
allowedUrls:[
{match: 'tracontext', propagatorTypes:['tracecontext', 'b3']}, // Matches URLs prefixed with https://api.aliyun.com based on W3C and B3 single.
{match: /api\.alibaba\.com/i, propagatorTypes:['b3multi']}, // Uses a regular expression to match URLs containing api.aliyun.com based on B3 multi.
{match: (url)=>url.includes('.api'), propagatorTypes:['jaeger']}, // Uses a function to match URLs containing .api based on 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 package
Simple mode
We recommend that you use this mode only for a web application. For a mini program, you must use the full mode and configure the allowedUrls parameter because the requests of mini programs do not differentiate domains.
This mode is applicable to scenarios that do not involve cross-origin requests. By default, the backend adopts the OpenTelemetry protocol. The allowedUrls parameter can be set to undefined, but the URLs of intra-domain requests are added to the whitelist.
import ArmsRum from '@arms/rum-browser';
ArmsRum.init({
pid: 'your pid',
endpoint: 'your endpoint',
// Specify more parameters based on your needs.
// Specify whether to enable tracing. Valid values: true and false. Default value: false.
tracing: true // This configuration is equivalent to { enable: true, sample: 100, tracestate: true, allowedUrls:[], baggage: false }.
});
Full mode
In this mode, you need to configure all parameters. Set the allowedUrls parameter to an array of tracing options.
import ArmsRum from '@arms/rum-browser';
ArmsRum.init({
pid: "your pid",
endpoint: "your endpoint",
// Specify more parameters based on your needs.
tracing: {
enable: true, // Specify whether to enable tracing.
sample: 100, // Specify the sampling rate. Default value: 100.
tracestate: true, // Specify whether to enable the tracestate header. Valid values: true and false. Default value: true.
baggage: true, // Specify whether to enable the baggage header. Valid values: true and false. Default value: false.
allowedUrls:[
{match: 'tracontext', propagatorTypes:['tracecontext', 'b3']}, // Matches URLs prefixed with https://api.aliyun.com based on W3C and B3 single.
{match: /api\.alibaba\.com/i, propagatorTypes:['b3multi']}, // Uses a regular expression to match URLs containing api.aliyun.com based on B3 multi.
{match: (url)=>url.includes('.api'), propagatorTypes:['jaeger']}, // Uses a function to match URLs containing .api based on Jaeger.
]
}
});
Tracing parameters
Parameter | Type | Default value | Remarks |
tracing.enable | Boolean | true | Specifies whether to enable tracing. If the data type is invalid, the value is changed to true. |
tracing.sample | Number | 100 | The sampling rate. Valid values: 0 to 100. If the data type is invalid, the value is changed to 100. |
tracing.tracestate | Boolean | true | Specifies whether to enable the tracestate header. This parameter takes effect only when W3C is used. If you set this parameter to false, requests that use W3C do not carry the tracestate header. |
tracing.baggage | Boolean | false | Specifies whether to enable the baggage header. If you set this parameter to true, RUM adds the baggage header and related information to requests, regardless of the tracing protocol. |
tracing.propagatorTypes | PropagatorType | PropagatorType[] | null | The protocols that are used to propagate traces. Take note of the following information:
|
tracing.allowedUrls | Array<MatchOption | TraceOption> | undefined | undefined | The URLs that support tracing.
|
If you are using a web application, the following configuration is added to the tracing.allowedUrls parameter.
{
match: (url) => (/^https?:\/\/*/.test(url) || startsWith(url, location.origin)),
propagatorTypes: ['tracecontext']
}
MatchOption
type MatchOption = string | RegExp | ((value: string) => boolean);
The allowedUrls parameter matches full URLs. The follow methods are used:
string: matches any URLs that start with the specified value. Example:
https://api.aliyun.com
. In this case,https://api.aliyun.com/v1/resource
can be matched.RegExp: specifies a regular expression and URL.
function: uses a function to determine whether a URL is matched. If true is returned, the URL is matched.
PropagatorType
The OpenTelemetry trace context conforms to W3C.
type PropagatorType = 'tracecontext' | 'b3' | 'b3multi' | 'jaeger' | 'sw8';
The following table describes the propagation formats of the preceding protocols.
Protocol | Format |
traceparent : {version}-{trace-id}-{parent-id}-{trace-flags} tracestate: rum={version}&{appType}&{pid}&{sessionId} | |
b3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId} | |
X-B3-TraceId: {TraceId} X-B3-SpanId: {SpanId} X-B3-ParentSpanId: {ParentSpanId} X-B3-Sampled: {SamplingState} | |
uber-trace-id : {trace-id}:{span-id}:{parent-span-id}:{flags} | |
sw8: {sample}-{trace-id}-{segment-id}-{0}-{service}-{instance}-{endpoint}-{peer} |
The request headers that are propagated by the preceding protocols are neither standard HTTP request headers nor cross-origin resource sharing (CORS)-safelisted request headers. Therefore, you must specify the Access-Control-Allow-Headers
parameter on the server if your website or web application involves cross-domain requests. You must specify this parameter for mini programs because requests of mini programs do not differentiate domains. Otherwise, the cross-domain requests are blocked by browsers.
Verify the tracing configurations of the frontend
Web & HTML5 application
Visit your website or HTML5 page.
In the browser console, click the Network tab.
Check whether the API requests of the XHR or Fetch type initiated from the frontend contain the headers corresponding to the tracing protocol.
Mini program in Alipay, WeChat, or DingTalk
Run the mini program in the simulator.
Open the debugger of the simulator and go to the Network tab.
Check whether the requests initiated by the mini program contain the headers corresponding to the tracing protocol.
Enable tracing for the backend
To enable end-to-end tracing, you must configure tracing for the backend. This section describes the methods for enabling tracing for the backend based on the language.
Java
Use the ARMS agent
By default, the ARMS agent supports the OpenTelemetry protocol. Therefore, tracing is implemented for applications monitored in Application Monitoring without additional configurations. However, make sure that the following conditions are met:
The version of the ARMS agent is V2.x, V3.x, or V4.x. We recommend that you use V4.x for better user experience.
A mainstream web container, such as Apache Tomcat, Jetty, WebLogic, or Undertow, and a supported framework, such as Spring Boot or Spring Web MVC, are used. For more information about the components and frameworks supported by ARMS, see Java components and frameworks supported by ARMS.
For information about how to install an ARMS agent for an application, see Monitor Java applications.
Use OpenTelemetry
You can integrate an application into Managed Service for OpenTelemetry through OpenTelemetry and automatically or manually instrument the application.
If you automatically instrument the application, tracing can be implemented without additional configurations because OpenTelemetry supports most mainstream frameworks.
NoteFor information about the Java frameworks supported by OpenTelemetry, see Use OpenTelemetry to report the trace data of Java applications.
If you manually instrument the application, you need to use OpenTelemetry SDKs to enable tracing by parsing the trace context from the frontend request headers traceparent and tracestate. The following sample code shows how to manually instrument a Spring Boot application and enable tracing.
Import OpenTelemetry dependencies.
<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>
Configure W3C propagation during OpenTelemetry initialization.
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) // Add W3C propagation settings. .setPropagators(ContextPropagators.create( TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())) ).buildAndRegisterGlobal(); // Configure a tracer. tracer = ExtendedTracer.create(openTelemetry.getTracer("com.example.tracer", "1.0.0"));
Obtain header information, parse the trace context, and configure the parent span.
// Obtain header information in @Controller to parse the trace context. @RequestMapping("/test") public String test(@RequestHeader Map<String, String> headers) { Span span = OpenTelemetrySupport.getTracer() .spanBuilder("/test") // Parse the parent span from the headers. .setParentFrom(OpenTelemetrySupport.getContextPropagators(), headers) .setSpanKind(SpanKind.SERVER) .startSpan(); try (Scope scope = span.makeCurrent()) { // do something } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "handle parent span error"); } finally { span.end(); } return "success"; }
Use Jaeger
You can use Jaeger to integrate an application into Managed Service for OpenTelemetry. Jaeger provides two methods for enabling tracing for web applications: manual instrumentation and instrumentation through the Spring Cloud component. For more information, see Use Jaeger to report Java application data.
If you instrument an application through the Spring Cloud component, tracing can be implemented without additional configurations.
If you manually instrument an application, you must parse the trace context from the frontend request headers. Sample code:
Import dependencies.
<dependency> <groupId>io.jaegertracing</groupId> <artifactId>jaeger-client</artifactId> <version>Latest version</version> <!-- Make sure that the latest Jaeger version is used. --> </dependency>
Initialize the tracer.
Replace
<endpoint>
with the endpoint displayed on the Access point information tab of the page in the Managed Service for OpenTelemetry console.// Replace manualDemo with your application name. io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("manualDemo"); io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration(); // Replace <endpoint> with the endpoint that is displayed on the Access point information tab of the Cluster Configurations page in the Managed Service for OpenTelemetry console. 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());
Create a span.
// Obtain header information in @Controller to parse the trace context. @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"); // do something } catch (Throwable t) { TracingHelper.onError(e, span); throw e } finally { span.finish(); } return "success"; }
Use Zipkin
You can use Zipkin to integrate an application into Managed Service for OpenTelemetry. For more information, see Use Zipkin to report Java application data.
Then, parse the trace context from the request headers to enable tracing. Sample code:
// Parse the trace context from the request headers.
extractor = tracing.propagation().extractor(Request::getHeader);
// convert that context to a span which you can name and add tags to
oneWayReceive = nextSpan(tracer, extractor.extract(request))
.name("process-request")
.kind(SERVER)
... add tags etc.
// start the server side and flush instead of finish
oneWayReceive.start().flush();
// you should not modify this span anymore as it is complete. However,
// you can create children to represent follow-up work.
next = tracer.newSpan(oneWayReceive.context()).name("step2").start();
Use SkyWalking
You can use an SkyWalking agent for Java to integrate an application into Managed Service for OpenTelemetry. For more information, see Use SkyWalking to report Java application data.
Then, you can enable tracing for the backend.
If you use an SkyWalking agent for Java V8.x, SkyWalking Cross Process Propagation Headers Protocol v3 (sw8) must be used.
Go
Use OpenTelemetry
You can use OpenTelemetry to integrate an application into Managed Service for OpenTelemetry. For more information, see Use OpenTelemetry to submit the trace data of a Go application.
Then, use an HTTP request handler to generate a span from the request context and enable tracing. Sample code:
// Initialize the tracer.
tracer := otel.Tracer(common.TraceInstrumentationName)
// Generate a span from the request context.
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
span := trace.SpanFromContext(ctx)
// do something
w.Write([]byte("Hello World"))
})
Use Jaeger
You can use Jaeger to integrate an application into Managed Service for OpenTelemetry. For more information, see Use Jaeger to report Go application data.
Then, parse the span context from the HTTP request headers to enable tracing. Sample code:
// Parse the span context from the HTTP request headers.
spanCtx, _ := tracer.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
span := tracer.StartSpan("myspan", opentracing.ChildOf(spanCtx))
...
defer span.Finish()
Use Zipkin
You can use Zipkin to integrate an application into Managed Service for OpenTelemetry. For more information, see Use Zipkin to submit the trace data of a Go application.
Then, parse the span context from the HTTP request headers to enable tracing. Sample code:
// Initialize the tracer.
tracer, err := exampletracer.NewTracer("go-frontend", frontendPort)
// Generate a span from the request context.
router.Methods("GET").Path("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// retrieve span from context
span := zipkin.SpanFromContext(r.Context())
// add some tag
span.Tag("some_key", "some_value")
// do something...
span.Annotate(time.Now(), "some_event")
})
Use SkyWalking
You can use SkyWalking to integrate an application into Managed Service for OpenTelemetry. For more information, see Use SkyWalking to report Go application data.
We recommend that you use a SkyWalking agent for Go, which supports mainstream web frameworks, such as Gin, go-restful, http, Kratos v2, Go Micro, and Go Resty. Then, tracing can be implemented without modifying the code.
You can also manually parse the trace context from the HTTP request headers. Sample code:
//Extract context from HTTP request header `sw8`
span, ctx, err := tracer.CreateEntrySpan(r.Context(), "/api/test", func(key string) (string, error) {
return r.Header.Get(key), nil
})
Python
Use OpenTelemetry
You can use OpenTelemetry to integrate an application into Managed Service for OpenTelemetry. For more information, see Use OpenTelemetry to report the trace data of Python applications.
Then, parse the span context from the HTTP request headers to enable tracing. Sample code:
// Initialize the tracer.
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)
// Parse the trace context from the request headers.
carrier ={'traceparent': headers['Traceparent'], 'tracestate': headers['Tracestate']}
ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
with tracer.start_span("test", context=ctx):
// do something
return "success"
Use Jaeger
You can use Jaeger to integrate an application into Managed Service for OpenTelemetry. For more information, see Use Jaeger to report Python application data.
Then, parse the span context from the HTTP request headers to enable tracing. Sample code:
import logging
from flask import Flask
from jaeger_client import Config
from opentracing.ext import tags
from opentracing.propagation import Format
## Initialize the 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()
## trace decorator
def trace(tracer, span_name):
def decorator(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
## Parse the trace context from the request headers.
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
## api test example
@app.route('/test')
@trace(tracer, 'test')
def test():
return "success"
Use SkyWalking
You can use SkyWalking to integrate an application into Managed Service for OpenTelemetry. For more information, see Use SkyWalking to report Python application data.
Then, parse the span context from the HTTP request headers to enable tracing. Sample code:
from skywalking import config, agent
from skywalking.trace.context import SpanContext, get_context
from skywalking.trace.carrier import CarrierItem
# Configure SkyWalking and adjust the parameters as needed.
config.init(agent_collector_backend_services='<endpoint>',
agent_authentication='<auth-token>')
agent.start()
# Use the function to process the HTTP request headers.
def handle_request(headers):
# Obtain the trace information from the request headers.
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)
# Obtain the trace context from the carrier.
context = get_context().extract(carrier)
# Create a span.
with get_context().new_entry_span(op='operation_name') as span:
# Process the request and automatically submit the span upon processing completion.
...
# Use a dictionary with SkyWalking segment IDs to simulate the HTTP request headers.
incoming_headers = {
'sw8': '1-My40LjU=-MTY1MTcwNDI5OTk5OA==-xxxx-xx-x-x==', # Specify the value.
# Other headers...
}
# Call the function to process the request.
handle_request(incoming_headers)
View the full trace data
After end-to-end tracing is enabled, you can view the trace data of a frontend request in the RUM module of the ARMS console.
Click View Call Chain to view the complete trace data of a request and the application topology. You can analyze issues such as slow or abnormal requests based on the request details and backend trace data.
The span on the top is the root span. The span name and application name vary based on the application type:
Web or HTML5 application: The application name is rum-browser and the span name is prefixed with
browser.request:
.Mini program: The mini program name is rum-miniapp and the span name is prefixed with
miniapp.request:
.Android app: The app name is rum-android and the span name is prefixed with
android.request:
.iOS app: The app name is rum-ios and the span name is prefixed with
ios.request:
.
You can also view the upstream and downstream services involved in the request based on the topology.