All Products
Search
Document Center

Simple Log Service:Import trace data from Android apps to Simple Log Service by using OpenTelemetry SDK for Android

Last Updated:Aug 29, 2023

This topic describes how to import trace data from Android apps to Simple Log Service by using OpenTelemetry SDK for Java.

Prerequisites

A trace instance is created. For more information, see Create a trace instance.

Step 1: Integrate the SDK

Add the following settings to the build.gradle file of your app or module:

// The bill of materials (BOM) list that is used to synchronize dependency versions. 
implementation(platform("io.opentelemetry:opentelemetry-bom:1.22.0"))
// Call an API operation.
implementation("io.opentelemetry:opentelemetry-api")
implementation("io.opentelemetry:opentelemetry-context")
// API extensions
implementation("io.opentelemetry:opentelemetry-extension-kotlin")
// SDK
implementation('io.opentelemetry:opentelemetry-sdk')
implementation('io.opentelemetry:opentelemetry-sdk-logs')
// semantic conventions
implementation("io.opentelemetry:opentelemetry-semconv")
// Exporters
// Create an official gRPC exporter.
implementation("io.opentelemetry:opentelemetry-exporter-otlp")

For more information, see OpenTelemetry Java SDK Release.

Step 2: Configure permissions

To report trace data, you must apply for network permissions by adding the following permission statement to the AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET" />

Step 3: Initialize the SDK

We recommend that you initialize the SDK by calling the onCreate method of the Application class.

// Initialize the exporter. The exporter is used to export trace data to a Log Service Logstore. 
OtlpGrpcSpanExporter grpcSpanExporter = OtlpGrpcSpanExporter.builder()
  .setEndpoint("https://${endpoint}") 
  .addHeader("x-sls-otel-project", "${project}")
  .addHeader("x-sls-otel-instance-id", "${instanceId}")
  .addHeader("x-sls-otel-ak-id", "${access-key-id}")
  .addHeader("x-sls-otel-ak-secret", "${access-key-secret}")
  .build();

// Initialize the tracer provider. The tracer provider is used to expose main API operations, preprocess spans, and configure custom clocks. 
// The custom rule that is used to generate TraceIds and SpanIds, and custom samplers. You can configure the settings based on your business scenario. 
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
  .addSpanProcessor(BatchSpanProcessor.builder(grpcSpanExporter).build())
  .setResource(Resource.create(Attributes.builder()
                               .put(ResourceAttributes.SERVICE_NAME, "${service}")
                               .put(ResourceAttributes.SERVICE_NAMESPACE, "${service.namespace}")
                               .put(ResourceAttributes.SERVICE_VERSION, "${version}")
                               .put(ResourceAttributes.HOST_NAME, "${host}")
                               .put(ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "${environment}")
                               .build()
                              )
              )
  .build();

// Initialize the OpenTelemetry SDK. 
OpenTelemetrySdk telemetrySdk = OpenTelemetrySdk.builder()
  .setTracerProvider(tracerProvider)
  .build(); // If you call the build() method to generate an instance, you must check whether to define the OpenTelemetry SDK as a global variable based on your business scenario. 

// You can also define a global variable named OpenTelemetrySdk. 
// OpenTelemetrySdk telemetrySdk = OpenTelemetrySdk.builder()
//    .setTracerProvider(tracerProvider)
//    .buildAndRegisterGlobal(); // You can call the GlobalOpenTelemetry.get() or GlobalOpenTelemetry.getTracer() method to access the instance.

Variable

Description

Example

${endpoint}

The endpoint of the Simple Log Service project. Format: ${region-endpoint}:Port.

  • ${region-endpoint}: the Simple Log Service endpoint for the region where the project resides. You can access Simple Log Service by using an internal or public endpoint. An internal endpoint can be accessed over the classic network or a virtual private cloud (VPC). A public endpoint can be accessed over the Internet. For more information, see Endpoints.

  • Port: the port number. The value is set to 10010 and cannot be changed.

cn-hangzhou.log.aliyuncs.com:10010

${project}

The name of the Simple Log Service project.

test-project

${instance}

The ID of the trace instance. For more information, see Create a trace instance.

test-traces

${access-key-id}

The AccessKey ID of your Alibaba Cloud account.

We recommend that you use the AccessKey pair of a RAM user that has only the write permissions on the Simple Log Service project. An AccessKey pair consists of an AccessKey ID and an AccessKey secret. For more information about how to grant the write permissions on a specified project to a RAM user, see Use custom policies to grant permissions to a RAM user. For information about how to obtain an AccessKey pair, see AccessKey pair.

None

${access-key-secret}

The AccessKey secret of your Alibaba Cloud account.

We recommend that you use the AccessKey pair of a RAM user that has only the write permissions on the Simple Log Service project.

None

${service.namespace}

The namespace to which the service belongs.

order

${service}

The name of the service. Specify the value based on your business scenario.

payment

${version}

The version of the service. We recommend that you specify a version in the va.b.c format.

v0.1.2

${host}

The hostname.

localhost

${environment}

The deployment environment. Example: test environment or production environment. Specify the value based on your business scenario.

pre

Step 4: Use the SDK

Create a tracer

We recommend that you create a tracer based on your business scenario. When you create a tracer, you must specify an instrumentation scope name. Different trace data is distinguished by scope.

Tracer tracer = telemetrySdk.getTracer("otel application", "1.0.0");

Create a root span

A span indicates an operation in a transaction. Each span encapsulates the operation name, start timestamp and end timestamp, attributes, events, and context.

final Span span = tracer.spanBuilder("root span").startSpan();
// do stuff
// ...
span.end();

Create nested spans

If you want to associate nested operations with spans, you can use OpenTelemetry to track the operation threads in an on-premises process and across remote processes. In this example, methodB is called by methodA. To nest spans, use the following method.

void methodA() {
  Span parentSpan = tracer.spanBuilder("operation A").startSpan();
  methodB(parentSpan);
  parentSpan.end();
}
void methodB(Span parentSpan) {
  Span childSpan = tracer.spanBuilder("operation B")
    .setParent(parentSpan)
    .startSpan();
  // do stuff
  childSpan.end();
}

The OpenTelemetry API also provides an automated method that is used to propagate the parent span.

void methodA() {
  Span parentSpan = tracer.spanBuilder("operation A").startSpan();
  try (Scope scope = parentSpan.makeCurrent()) {
    methodB();
  } finally {
    parentSpan.end();
  }
}

void methodB() {
  Span childSpan = tracer.spanBuilder("operation B").startSpan();
  // do stuff
  childSpan.end();
}

Create a span with attributes

You can provide context for a specific operation in a span by specifying attributes, such as the execution result and other associated business information.

Span span = tracer.spanBuilder("GET /resource/catalog").setSpanKind(Span.Kind.CLIENT).startSpan();
span.setAttribute("http.method", "GET");
span.setAttribute("http.url", url.toString());

Create a span with events

You can use multiple events to annotate a span.

span.addEvent("start");
// do stuff
// ...
span.addEvent("end");

// A span can also carry attributes. 
Attributes eventAttributes = Attributes.of(
  "key1", AttributeValue.stringAttributeValue("value1"),
  "key2", AttributeValue.longAttributeValue(111L)
);
span.addEvent("End Computation", eventAttributes);

Create a span with links

You can use links to associate one span with one or more spans, which implies a causal relationship.

Link link1 = LinkData.create(parentSpan1.getContext());
Link link2 = LinkData.create(parentSpan2.getContext());
Span child = tracer.spanBuilder("child_with_link")
    .addLink(link1)
    .addLink(link2)
    .addLink(parentSpan3.getContext())
    .startSpan();

For information about how to read context from a remote process, see Context Propagation.

Specify a status value for a span

You can attach one of the following status values to a span: StatusCode.UNSET, StatusCode.OK, and StatusCode.ERROR. UNSET indicates the default status. OK indicates that the operation is completed. ERROR indicates that the operation contains an error.

Span span = tracer.spanBuilder("operation name").startSpan();

try (Scope scope = span.makeCurrent()) {
  // do stuff
} catch (Throwable t) {
  span.setStatus(StatusCode.ERROR, "Something bad happened!");
  throw t;
} finally {
  span.end(); // After you call the end() method, you cannot specify a status value for the span. 
}

Record exceptions in a span

After an exception is captured, we recommend that you add the exception to the associated span. We also recommend that you update the status of the span at the same time.

Span span = tracer.spanBuilder("operation name").startSpan();
try (Scope scope = span.makeCurrent()) {
  // do stuff
} catch (Throwable throwable) {
  span.setStatus(StatusCode.ERROR, "Something bad happened!");
  span.recordException(throwable)
} finally {
  span.end();
}

Propagate context

OpenTelemetry provides a text-based method to propagate context. The following example shows how to initiate an HTTP request by using HttpURLConnection.

// Inject the context in the HTTP headers by using the HttpURLConnection Header setter.
TextMapSetter<HttpURLConnection> setter =
  new TextMapSetter<HttpURLConnection>() {
    @Override
    public void set(HttpURLConnection carrier, String key, String value) {
      // Insert the context as Header
      carrier.setRequestProperty(key, value);
    }
};

URL url = new URL("http://127.0.0.1:8088/resource/catalog");
Span httpSpan = tracer.spanBuilder("GET /resource/catalog").setSpanKind(SpanKind.CLIENT).startSpan();
try (Scope scope = httpSpan.makeCurrent()) {
  // Inject attributes to record the details of the HTTP request. 
  httpSpan.setAttribute(SemanticAttributes.HTTP_METHOD, "GET");
  httpSpan.setAttribute(SemanticAttributes.HTTP_URL, url.toString());
  HttpURLConnection transportLayer = (HttpURLConnection) url.openConnection();
  // Inject the current context into the HTTP request. 
  telemetrySdk.getPropagators().getTextMapPropagator().inject(Context.current(), transportLayer, setter);
  // do stuff
} finally {
  httpSpan.end();
}

The OpenTelemetry SDK supports context propagation by using the W3C Trace Context HTTP headers. For more information, see W3CTraceContextPropagator class.

For more information about the OpenTelemetry SDK, see OpenTelemetry documentation.

FAQ

If OpenTelemetry SDK for Java uses Java 8+ API features, the following error message may appear on your device:

FATAL EXCEPTION: main
Process: xx.xx.xx.xx, PID: 2810
java.lang.NoClassDefFoundError: io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder$$ExternalSyntheticLambda0
	at io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder.<init>(OtlpGrpcSpanExporterBuilder.java:38)
	at io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter.builder(OtlpGrpcSpanExporter.java:39)

To resolve the preceding issue, turn on coreLibraryDesugaringEnabled if your Android app supports devices that run API level 26 or earlier. For more information, see core library desugaring.

After coreLibraryDesugaringEnabled is turned on, your Android app can support devices that run API level 21 or later.

Note

OpenTelemetry SDK for Java does not support devices that run an API level lower than 21.