Após instrumentar um aplicativo com OpenTelemetry e relatar dados de rastreamento para o Managed Service for OpenTelemetry, o Managed Service for OpenTelemetry passa a monitorar o aplicativo. É possível visualizar diversos dados de monitoramento, como topologia do aplicativo, traces, transações anômalas, transações lentas e análise de SQL. Este tópico descreve como instrumentar um aplicativo Android com OpenTelemetry e relatar dados.
Pré-requisitos
Aplicativo de exemplo
Este tópico utiliza um aplicativo de exemplo para demonstrar como relatar dados de rastreamento de um aplicativo Android com OpenTelemetry. O procedimento se aplica a aplicativos escritos tanto em Java quanto em Kotlin.
Repositório de código de exemplo: opentelemetry-android-demo
Etapa 1: Criar e configurar o aplicativo
-
Crie um aplicativo.
No Android Studio, crie um novo aplicativo. Selecione o modelo Basic Views Activity e clique em Next.
Escolha Java ou Kotlin como linguagem, selecione API 24: Android 7.0 (Nougat) como versão mínima do SDK e clique em Finish.
-
Adicione as dependências.
No arquivo build.gradle no nível do módulo ou do projeto, adicione as seguintes dependências.
Este exemplo usa a versão 1.25.0 do OpenTelemetry SDK para Java. Para outras versões, consulte Opentelemetry Java Releases. Para o arquivo build.gradle completo, veja build.gradle.
implementation platform('io.opentelemetry:opentelemetry-bom:1.25.0') implementation "io.opentelemetry:opentelemetry-api" implementation "io.opentelemetry:opentelemetry-context" implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-exporter-logging' implementation 'io.opentelemetry:opentelemetry-extension-kotlin' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-semconv' -
Adicione a configuração de rede.
-
No diretório
app/res/xml, crie um arquivo chamado network_security_config.xml e adicione o seguinte conteúdo.<!-- For the complete file content, see https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/res/xml/network_security_config.xml --> <?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <!-- Replace the following domain name with the endpoint you obtained in the Prerequisites section. Do not include "http://", the port number, or the URL path. --> <domain includeSubdomains="true">tracing-analysis-dc-hz.aliyuncs.com</domain> </domain-config> </network-security-config> -
Modifique o arquivo
app/src/main/AndroidManifest.xml. Adicione as duas linhas a seguir para conceder permissão de rede ao aplicativo.<!-- For the complete file content, see https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/AndroidManifest.xml --> <?xml version="1.0" encoding="utf-8"?> <manifest ...> <!-- Add the following line to grant network permission. --> <uses-permission android:name="android.permission.INTERNET" /> <application ... <!-- Add the following line to configure network settings for the domain to which you want to report data. --> android:networkSecurityConfig="@xml/network_security_config" ...> ... </application> </manifest>
-
Etapa 2: Inicializar o OpenTelemetry
-
Crie uma classe utilitária do OpenTelemetry.
No mesmo diretório da MainActivity, crie um arquivo chamado
OpenTelemetryUtile adicione o seguinte conteúdo.-
Opção 1: Relatar dados de rastreamento usando gRPC
/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/OpenTelemetryUtil.java */ Resource otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( // Replace <your-service-name> with your application name. ResourceAttributes.SERVICE_NAME, "<your-service-name>", // Replace <your-host-name> with your host name. ResourceAttributes.HOST_NAME, "<your-host-name>" ) ) ); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature. // Replace <gRPC-endpoint> with the endpoint you obtained in the Prerequisites section and replace <gRPC-token> with your authentication token. .addSpanProcessor(BatchSpanProcessor.builder( OtlpGrpcSpanExporter.builder() .setEndpoint("<gRPC-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com:8090 .addHeader("Authentication", "<gRPC-token>") // Example: xxxx@xxxx_xxxx@xxxx .build()).build() ) .setResource(otelResource) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); // Obtain a tracer to create spans. tracer = openTelemetry.getTracer("android-tracer", "1.0.0");/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/OpenTelemetryUtil.kt */ val otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( ResourceAttributes.SERVICE_NAME, "<your-service-name>", // Replace <your-service-name> with your application name. ResourceAttributes.HOST_NAME, "<your-host-name>" // Replace <your-host-name> with your host name. ) ) ) /* Report trace data over gRPC. */ val sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature. // Replace <gRPC-endpoint> with the endpoint you obtained in the Prerequisites section and replace <gRPC-token> with your authentication token. .addSpanProcessor( BatchSpanProcessor.builder( OtlpGrpcSpanExporter.builder() .setEndpoint("<gRPC-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com:8090 .addHeader("Authentication", "<gRPC-token>") // Example: xxxx@xxxx_xxxx@xxxx .build() ).build() ) .setResource(otelResource) .build() val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal() // Obtain a tracer to create spans. tracer = openTelemetry.getTracer("android-tracer", "1.0.0") -
Opção 2: Relatar dados de rastreamento usando HTTP
/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/OpenTelemetryUtil.java */ Resource otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( // Replace <your-service-name> with your application name. ResourceAttributes.SERVICE_NAME, "<your-service-name>", // Replace <your-host-name> with your host name. ResourceAttributes.HOST_NAME, "<your-host-name>" ) ) ); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature. // Replace <HTTP-endpoint> with the endpoint you obtained in the Prerequisites section. .addSpanProcessor(BatchSpanProcessor.builder( OtlpHttpSpanExporter.builder() .setEndpoint("<HTTP-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com/adapt_xxxx@xxxx_xxxx@xxxx/api/otlp/traces .build()).build() ) .setResource(otelResource) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); // Obtain a tracer to create spans. tracer = openTelemetry.getTracer("android-tracer", "1.0.0");/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/OpenTelemetryUtil.kt */ val otelResource = Resource.getDefault().merge( Resource.create( Attributes.of( ResourceAttributes.SERVICE_NAME, "<your-service-name>", // Replace <your-service-name> with your application name. ResourceAttributes.HOST_NAME, "<your-host-name>" // Replace <your-host-name> with your host name. ) ) ) /* Report trace data over HTTP. */ val sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) // Optional: Prints trace data to the console. Comment out this line to disable this feature. // Replace <HTTP-endpoint> with the endpoint you obtained in the Prerequisites section. .addSpanProcessor(BatchSpanProcessor.builder( OtlpHttpSpanExporter.builder() .setEndpoint("<HTTP-endpoint>") // Example: http://tracing-analysis-dc-hz.aliyuncs.com/adapt_xxxx@xxxx_xxxx@xxxx/api/otlp/traces .build()).build() ) .setResource(otelResource) .build(); val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal() // Obtain a tracer to create spans. tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
-
-
Inicialize o OpenTelemetry quando o aplicativo for iniciado.
No método
onCreatedaMainActivity, chame o método OpenTelemetryUtil.init()./** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/MainActivity.java */ ... public class MainActivity extends AppCompatActivity { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Add this line to initialize OpenTelemetry. OpenTelemetryUtil.init(); ... } ... }/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/MainActivity.kt */ ... class MainActivity : AppCompatActivity() { ... override fun onCreate(savedInstanceState: Bundle?) { WindowCompat.setDecorFitsSystemWindows(window, false) super.onCreate(savedInstanceState) // Add this line to initialize OpenTelemetry. OpenTelemetryUtil.init() ... } }
Etapa 3: Criar spans para rastrear dados
-
Crie um span.
No arquivo FirstFragment, crie um span chamado First Fragment Button onClick no manipulador de clique do botão.
/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ public void onClick(View view) { // Get the tracer. Tracer tracer = OpenTelemetryUtil.getTracer(); // Create a span. Span span = tracer.spanBuilder("First Fragment Button onClick").startSpan(); try (Scope scope = span.makeCurrent()) { // Get the trace ID. System.out.println(span.getSpanContext().getTraceId()); ... } finally { span.end(); } }/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ binding.buttonFirst.setOnClickListener { // Get the tracer. val tracer: Tracer = OpenTelemetryUtil.getTracer()!! // Create a span. val span = tracer.spanBuilder("First Fragment Button onClick").startSpan() try { span.makeCurrent().use { scope -> // Get the trace ID. println(span.spanContext.traceId) // Get the span ID. println(span.spanContext.spanId) findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) } } catch (t: Throwable) { span.setStatus(StatusCode.ERROR, "Something wrong in onClick") throw t } finally { span.end() } } -
Defina atributos e eventos para o span.
/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ // Set an attribute. span.setAttribute("key", "value"); Attributes eventAttributes = Attributes.of( AttributeKey.stringKey("key"), "value", AttributeKey.longKey("result"), 0L); // Add an event. span.addEvent("onClick", eventAttributes);/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ // Set an attribute. span.setAttribute("key", "value") val eventAttributes = Attributes.of( AttributeKey.stringKey("key"), "value", AttributeKey.longKey("result"), 0L ) // Add an event. span.addEvent("onClick", eventAttributes) -
Defina o status do span.
/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ ... try (Scope scope = span.makeCurrent()) { ... } catch (Throwable t) { // Set the span status. span.setStatus(StatusCode.ERROR, "Something wrong in onClick"); throw t; } finally { span.end(); }/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ ... try { ... } catch (t: Throwable) { // Set the span status. span.setStatus(StatusCode.ERROR, "Something wrong in onClick") throw t } finally { span.end() } -
Crie um span aninhado.
/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidJavaDemo/app/src/main/java/com/example/androidjavademo/FirstFragment.java */ public void parentSpan() { // Get the tracer. Tracer tracer = OpenTelemetryUtil.getTracer(); // Create a span. Span span = tracer.spanBuilder("Parent Span").startSpan(); try (Scope scope = span.makeCurrent()) { // Get the trace ID. System.out.println(span.getSpanContext().getTraceId()); // Get the span ID. System.out.println(span.getSpanContext().getSpanId()); childSpan(); } finally { span.end(); } } public void childSpan() { // Get the tracer. Tracer tracer = OpenTelemetryUtil.getTracer(); // Create a span. Span span = tracer.spanBuilder("Child Span").startSpan(); try (Scope scope = span.makeCurrent()) { // Get the trace ID. System.out.println(span.getSpanContext().getTraceId()); // Get the span ID. System.out.println(span.getSpanContext().getSpanId()); } finally { span.end(); } }/** For the complete code, visit the following link: https://github.com/alibabacloud-observability/android-demo/blob/master/AndroidKotlinDemo/app/src/main/java/com/example/androidkotlindemo/FirstFragment.kt */ // Nested span fun parentSpan() { // Get the tracer. val tracer: Tracer = OpenTelemetryUtil.getTracer()!! // Create a span. val span = tracer.spanBuilder("Parent Span").startSpan() try { span.makeCurrent().use { scope -> // Get the trace ID. println(span.spanContext.traceId) // Get the span ID. println(span.spanContext.spanId) childSpan() } } finally { span.end() } } // Nested span fun childSpan() { // Get the tracer. val tracer: Tracer = OpenTelemetryUtil.getTracer()!! // Create a span. val span = tracer.spanBuilder("Child Span").startSpan() try { span.makeCurrent().use { scope -> // Get the trace ID. println(span.spanContext.traceId) // Get the span ID. println(span.spanContext.spanId) } } finally { span.end() } }
Etapa 4: Executar o projeto e visualizar dados de rastreamento
-
Execute o projeto e toque no botão na página do aplicativo de demonstração. No painel Running Devices do Android Studio, o emulador (por exemplo, Pixel 3a API 33) executa com sucesso o aplicativo AndroidJavaDemo e exibe a página padrão First Fragment.
Verifique o Logcat para visualizar as informações de span exportadas pelo
LoggingSpanExporter.System.out I 0c8b92db3d8b038ea3eedd0ec25a4abb System.out I 9ecd666297f5d8f6 System.out I 0c8b92db3d8b038ea3eedd0ec25a4abb System.out I 7e7eaffe7bd23cb8 System.out I 0c8b92db3d8b038ea3eedd0ec25a4abb System.out I 98ef17d962ecf4d1 LoggingSpanExporter I 'Child Span' : 0c8b92db3d8b038ea3eedd0ec25a4abb 98ef17d962ecf4d1 INTERNAL [tracer: android-tracer:1.0.0] LoggingSpanExporter I 'Parent Span' : 0c8b92db3d8b038ea3eedd0ec25a4abb 7e7eaffe7bd23cb8 INTERNAL [tracer: android-tracer:1.0.0] LoggingSpanExporter I 'First Fragment Button onClick' : 0c8b92db3d8b038ea3eedd0ec25a4abb 9ecd666297f5d8f6 INTERNAL [tracer: android-tracer:1.0.0] EGL_emulation D app_time_stats: avg=460.19ms min=2.23ms max=3653.05ms count=8 -
A página de detalhes do trace exibe métricas resumidas (como duração, número de aplicativos, profundidade do trace e número total de spans) e uma lista de spans. O exemplo inclui uma hierarquia de spans de três níveis: o span raiz First Fragment Button onClick (duração: 6.835 ms), o span filho Parent Span (duração: 2.998 ms) e o span neto Child Span (duração: 0,14 ms). O nome do aplicativo para todos os spans é
otel-android-demo. Isso mostra a distribuição de tempo e as relações pai-filho.Faça login no console do ARMS. No painel de navegação à esquerda, escolha . Na página Applications, clique em nome do aplicativo. Na página exibida, visualize os dados de rastreamento.
NotaSe o ícone
for exibido na coluna Language, o aplicativo está conectado ao Application Monitoring. Se um hífen (-) for exibido, o aplicativo está conectado ao Managed Service for OpenTelemetry.
Etapa 5: Conectar traces de cliente e servidor
-
Modifique o formato de propagação de contexto de trace nos cabeçalhos.
Protocolos diferentes usam cabeçalhos HTTP distintos para passar o contexto de trace aos services downstream. Por exemplo, o OpenTelemetry usa o formato W3C Trace Context por padrão, mas também suporta outros formatos. O Zipkin usa o formato B3 ou B3 Multi. Para mais informações sobre formatos de propagação de contexto, consulte Specify the context propagation format for OpenTelemetry.
-
Para conectar traces de cliente e servidor, configure o
textPropagatorsno cliente para corresponder ao protocolo usado pelo servidor:Se o servidor usar o formato W3C Trace Context padrão do OpenTelemetry, não é necessário configurar o
textPropagatorsno cliente.-
Caso o servidor utilize o formato B3 ou B3 Multi do Zipkin, defina o
textPropagatorsno cliente comoB3Propagator.// Set the B3 context propagation format. OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(TextMapPropagator.composite( B3Propagator.injectingMultiHeaders(), B3Propagator.injectingSingleHeader()))) .buildAndRegisterGlobal(); -
Quando o servidor utilizar o protocolo Jaeger, defina o
textPropagatorsno cliente comoJaegerPropagator.// Set the Jaeger context propagation format. OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(TextMapPropagator.composite( JaegerPropagator.getInstance()))) .buildAndRegisterGlobal(); -
Também é possível definir múltiplos formatos de propagação de contexto de trace.
// Use W3C Trace Context, B3, and Jaeger as the trace context propagation formats. OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(TextMapPropagator.composite( W3CTraceContextPropagator.getInstance(), B3Propagator.injectingMultiHeaders(), B3Propagator.injectingSingleHeader(), JaegerPropagator.getInstance()))) .buildAndRegisterGlobal();
-
Importe okhttp3 e opentelemetry-okhttp.
O plugin
opentelemetry-okhttp-3.0para OkHttp instrumenta automaticamente o aplicativo interceptando todas as requisições de rede enviadas via OkHttp3 e criando traces.-
Adicione as duas dependências a seguir ao arquivo
build.gradle.dependencies { ... implementation 'io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0:2.3.0-alpha' implementation 'com.squareup.okhttp3:okhttp:4.12.0' } -
Crie a classe
OkHttpConfiguration.import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry; import okhttp3.Call; import okhttp3.OkHttpClient; public class OkHttpConfiguration { //Use this Call.Factory implementation for making standard http client calls. public Call.Factory createTracedClient(OpenTelemetry openTelemetry) { return OkHttpTelemetry.builder(openTelemetry).build().newCallFactory(createClient()); } //your configuration of the OkHttpClient goes here: private OkHttpClient createClient() { return new OkHttpClient.Builder().build(); } }
-
-
Use OkHttp3 para enviar uma requisição de rede ao servidor.
private void callHttpService() throws IOException { Tracer tracer = OpenTelemetryUtil.getTracer(); // Create a span. Span span = tracer.spanBuilder("AsyncRequestZipkinServer").startSpan(); System.out.println("AsyncRequestZipkinServer TraceID: " + span.getSpanContext().getTraceId()); System.out.println("AsyncRequestZipkinServer SpanID: " + span.getSpanContext().getSpanId()); try (Scope scope = span.makeCurrent()) { // Send a network request, for example, by using OkHttp. OkHttpConfiguration configuration = new OkHttpConfiguration(); Call.Factory tracedClient = configuration.createTracedClient(GlobalOpenTelemetry.get()); Request request = new Request.Builder().url("${ServerAddress}").get().build(); Call call = tracedClient.newCall(request); try (Response response = call.execute()) { // Process the response. String responseBody = response.body().string(); System.out.println(responseBody); } catch (IOException e) { // Handle the error. e.printStackTrace(); } } finally { span.end(); } } -
Na página Trace Explorer, visualize o trace ponta a ponta entre o cliente e o servidor.
AsyncRequestZipkinServerrepresenta o aplicativo Android ezipkin-demo-serveré o aplicativo do lado do servidor.
