本文介绍通过日志服务SDK接入Android Trace数据的操作步骤。

前提条件

已创建Trace实例。更多信息,请参见创建Trace实例
说明 用于采集Trace的Android SDK后续将停止更新维护,建议通过OpenTelemetry SDK接入Android Trace数据。具体操作,请参见通过OpenTelemetry接入Android Trace数据

步骤一:集成SDK

您可以通过自动或手动方式集成SDK。

(推荐)自动集成

说明 目前,只支持Maven中央仓库
  1. 在Project级别的build.gradle文件中添加以下配置。
    buildscript {
        repositories {
            google()
            jcenter()
            mavenCentral()
        }
    }
    
    allprojects {
        repositories {
            google()
            jcenter()
            mavenCentral()
        }
    }
  2. 在app级别的build.gradle文件中添加如下配置。
    android {
       defaultConfig {
           ndk {
               // 设置支持的so库架构,不设置时默认支持全部架构。
               abiFilters 'armeabi' //, 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
           }
       }
    }
    
    dependencies {
        // Gradle 3.0以上版本请使用implementation。
        implementation 'com.aliyun.openservices:aliyun-log-android-sdk:2.6.12'
        implementation 'com.aliyun.openservices:sls-android-core:1.0.7'
        implementation 'com.aliyun.openservices:sls-android-ot:1.0.7'
        implementation 'com.aliyun.openservices:sls-android-trace:1.0.6'
        // 打通移动端与服务端时需添加如下配置,且网络库需使用OkHttp3。
        implementation 'com.aliyun.openservices:sls-android-okhttp:1.0.7'
    }
    说明 在打通移动端与服务端的Trace链路时,如果需要使用其他网络库,请提工单申请。

手动集成

步骤二:配置权限

AndroidManifest.xml文件中加上如下权限申明:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

步骤三:混淆配置

如果您的项目代码进行了打包混淆,则您需要进行混淆配置。在打包混淆规则中,需要保留com.aliyun.sls.android包名下所有的类名和方法名。例如在progaurd.cfg文件中添加如下配置。

-keep class com.aliyun.sls.android.producer.* { *; }
-keep interface com.aliyun.sls.android.producer.* { *; }
-keep class com.aliyun.sls.android.** { *; }

步骤四:接入配置

  1. 添加Application类,即在$PROJECT/app/src/main/AndroidManifest.xml文件中增加Application类。

    例如添加MyApplication类,配置示例如下:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.aliyun.sls.android.demo">
        ...
    
        <application
            android:icon="@mipmap/ic_launcher"
            ...
            android:name="com.aliyun.sls.android.demo.SLSDemoApplication"
            ...
            android:theme="@style/AppTheme">
                ...
        </application>
    </manifest>
    IDE将根据Android Studio提示,自动创建一个名为MyApplication的类添加到当前项目中。
  2. 在MyApplication.onCreate方法中,增加如下初始化代码。
    public class MyApplication extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            Credentials credentials = new Credentials();
            credentials.accessKeyId = "your access key id";
            credentials.accessKeySecret = "your access key secret";
            // 上述AccessKey是通过STS方式获取时,需配置securityToken。
            credentials.securityToken = "your access security token";
    
            TracerCredentials tracerCredentials = credentials.createTraceCredentials();
            tracerCredentials.endpoint = "your trace endpoint";
            tracerCredentials.project = "your trace project";
            tracerCredentials.logstore = "your trace logstore";
    
            // 使用Trace功能时,必须先完成SLSAndroid初始化。
            SLSAndroid.initialize(
                this,
                credentials,
                configuration -> {
                    // 开启Trace功能。
                    configuration.enableTracer = true;
                }
            );
    
            // 如果需要打通移动端与服务端的Trace链路,还需要配置网络库。具体操作,请参见步骤3。
        }
    
    }
    • Credentials
      Credentials类定义了鉴权参数。
      字段示例值说明
      accessKeyIdLTAI****eYDw日志服务Project的AccessKey ID。如何获取,请参见访问密钥
      accessKeySecretlrRq****GOVM日志服务Project的AccessKey Secret。如何获取,请参见访问密钥
      securityToken124f****a369日志服务Project的访问密钥Token。使用STS方式接入时,需要配置。如何获取,请参见AssumeRole
    • TracerCredentials

      TracerCredentials类定义了关键的配置字段。

      字段示例值说明
      endpointhttps://cn-hangzhou.log.aliyuncs.com您在创建Trace实例时所绑定的Project的访问域名,此处必须添加https://前缀。如何获取,请参见公网服务入口
      重要 只支持公网服务入口。
      projectsls-ayasls-demo您在创建Trace实例时所绑定的Project。更多信息,请参见创建Trace实例
      logstoreayasls-traces创建Trace实例后,日志服务会自动生成一个名为{instance}-traces的Logstore。其中{instance}为Trace实例ID。更多信息,请参见创建Trace实例

      此处需配置为该Logstore。

    • SLSAndroid

      SLSAndroid类提供了SDK初始化相关的全部参数配置、用户信息配置等接口。

      类型字段或方法说明
      调试方法setLogLevel配置SDK的日志等级。可选值为Log.VERBOSE、Log.DEBUG、Log.INFO、Log.WARN和Log.ERROR。
      凭证更新setCredentials更新Credentials凭证信息,支持热更新。
      registerCredentialsCallback发送Span数据成功或失败时会回调onCall方法。
      配置方法setUserInfo更新用户信息。
      扩展参数配置setExtra新增全局扩展参数,全局生效。
      removeExtra移除全局扩展参数,全局生效。
      clearExtra清空全局扩展参数,全局生效。
    • Configuration
      Configuration类提供了SDK初始化额外参数配置的接口。
      类型字段/方法说明
      配置方法enableTracer是否启用Trace功能。
      spanProvider自定义Span的Resource和Attribute信息。
      环境配置envApp的环境信息,默认为default。

      建议开发环境配置为dev;线上环境配置为prod。

  3. 可选:配置网络库。
    如果需要打通移动端与服务端的Trace链路,还需添加OkHttp3网络库。即在您项目中调用OkHttp的位置,将调用方式替换为如下内容。
    // client为传入参数。
    // callFactory 建议作为单例来使用。
    Call.Factory callFactory = OKHttp3Tracer.newCallFactory(client);
    
    // 产生一个请求。
    Call call = callFactory.newCall(request);
  4. 可选:通过STS方式更新credentials.accessKeyIdcredentials.accessKeySecretcredentials.securityToken
    public class MyApplication extends Application {
    
        // 在请求AccessKey等信息后,发起调用。
        private void onUpdateSLS() {
            Credentials credentials = new Credentials();
    
            // (可选)更新AccessKey。
            credentials.accessKeyId = "your access key id";
            credentials.accessKeySecret = "your access key secret";
            credentials.securityToken = "your access security token";
    
            // (可选)更新Project等信息。
            TracerCredentials tracerCredentials = credentials.createTraceCredentials();
            tracerCredentials.endpoint = "your trace endpoint";
            tracerCredentials.project = "your trace project";
            tracerCredentials.logstore = "your trace logstore";
    
            SLSAndroid.setCredentials(credentials);
        }
    
    }

步骤五:构造Trace数据

构造单个Span

SDK提供多种方式构造单个Span。

  • 通过SpanBuilder构造
    • 代码格式
      SpanBuilder builder = Tracer.spanBuilder("span name");
      builder.setParent(span); // 设置父Span。
      builder.setStart(start); // 设置起始时间。
      builder.addAttribute(attribute); // 增加属性信息。
      builder.addResource(resource); // 增加资源信息。
      builder.setActive(true/false); // 是否保持Span活跃。
      Span span = builder.build(); // 构造并开启一个Span。
      span.end(); // 结束当前Span。
    • 配置示例
      Span span = Tracer.spanBuilder("span with children (SpanBuilder)")
                      .addAttribute(Attribute.of("attr_key", "attr_value"))
                      .addResource(Resource.of("res_key", "res_value"))
                      .build();
      span.end();
  • 通过startSpan构造
    • 代码格式
      Span span = Tracer.startSpan("span name"); // 调用startSpan方法后,Span处于开始状态。
      span.addAttribute(attribute); // 增加属性信息。
      span.addResource(resource); // 增加资源信息。
      span.setStart(start); // 设置起始时间,一般无需设置。
      span.setName("span name"); // 设置Span名称。
      span.setStatus(ERROR/OK/UNSET); // 设置Span状态,默认是UNSET。
      span.setStatusMessage("span status message"); // 设置Span状态的描述信息。
      span.setParentSpanId("parent span id"); // 设置父Span ID。
      span.setService("service name"); // 设置服务名称,默认为Android,一般无需设置。
      span.setSpanId("span id"); // 自定义Span ID,一般无需设置。
      span.setTraceId("trace id"); // 自定义Trace ID,一般无需设置。
      span.end(); // 结束当前Span。
    • 配置示例
      Span span = Tracer.startSpan("span 1");
              span.addAttribute(Attribute.of("attr_key", "attr_value"))
                  .addResource(Resource.of("res_key", "res_value"));
              span.end();
  • 通过withinSpan构造

    通过withinSpan方式构造Span,无需关注Span的startend设置。一般情况下,需要把业务代码放入到Runnable中,并且构造的Span无法设置额外信息。

    • 代码格式
      Tracer.withinSpan("span name", new Runnable() {
          @Override
          public void run() {
              // 代码块。
          }
      });
    • 配置示例
      Tracer.withinSpan("span with block", new Runnable() {
          @Override
          public void run() {
              android.util.Log.d("debug", "print log from withinSpan");
          }
      });

构造一条包含多个Span的Trace数据

一条Trace数据会关联1个或多个Span。SDK提供多种方式,关联不同Span。

  • 通过SpanBuilder构造
    Span span = Tracer.spanBuilder("span with children (SpanBuilder)")
        .setActive(true) // 必须设置为true。
        .addAttribute(Attribute.of("attr_key", "attr_value"))
        .addResource(Resource.of("res_key", "res_value"))
        .build();
    
    Tracer.startSpan("child span 1 (SpanBuilder)").end();
    Tracer.startSpan("child span 2 (SpanBuilder)").end();
    
    span.end(); // 结束Trace。
  • 通过startSpan构造
    Span span = Tracer.startSpan("span with children", true); // 第二个参数必须设置为true。
    
    Tracer.startSpan("child span 1").end();
    Tracer.startSpan("child span 2").end();
    
    span.end(); // 结束Trace。
  • 通过withinSpan构造
    Tracer.withinSpan("span with func block", new Runnable() {
        @Override
        public void run() {
            Tracer.startSpan("span within func block 1").end();
    
            // 子Trace。
            Tracer.withinSpan("nested span with func block", new Runnable() {
                @Override
                public void run() {
                    Tracer.startSpan("nested span 1").end();
                    Tracer.startSpan("nested span 2").end();
                }
            });
    
            Tracer.startSpan("span within func block 2").end();
        }
    });

自定义Attribute和Resource

SDK支持通过SpanProvider添加自定义信息。通过SpanProvider创建的Resource和Attribute将添加到所有Span中。您可以根据这个特性为所有Span添加业务关联的Resource和Attribute信息。

// 此处省略Credentials的初始化过程。
// ...

SLSAndroid.initialize(
    this,
    credentials,
    configuration -> {
        // 此处省略configuration的其他配置。
        // ...
        configuration.spanProvider = new ISpanProvider() {
            @Override
            public Resource provideResource() {
                return Resource.of("other_resource_key", "other_resource_value");
            }

            @Override
            public List<Attribute> provideAttribute() {
                List<Attribute> attributes = new ArrayList<>();
                attributes.add(Attribute.of("other_attribute_key", "other_attribute_value"));
                return attributes;
            }
        };
    }
);
// 此处省略其他配置过程。
// ...

参数说明

  • Tracer
    字段/方法说明
    spanBuilder(name)构造一个SpanBuider对象。
    startSpan(name)构造一个Span对象。
    startSpan(name, active)构造一个Span对象,根据active的值决定是否设置为活跃Span。
    withinSpan(name, runnable)构造一个Span对象,并设置为活跃Span,自动执行runnable代码块。
    withinSpan(name, active, runnable)构造一个Span对象,根据active的值决定是否设置为活跃Span,并自动执行runnable代码块
    withinSpan(name, active, parent, runnable)构造一个Span对象,根据active的值决定是否设置为活跃Span,并设置该Span对象的父Span为parent,自动执行runnable代码块。
  • SpanBuilder
    字段/方法说明
    SpanBuilder(name, processor, provider)构造一个SpanBuilder对象,并指定Span名称,SpanProcessor,SpanProvider。

    不建议直接调用方法。

    setParent(parent)设置父Span。
    setActive(active)设置是否为活跃Span。
    setKind(SpanKind)设置Span类型,支持设置为INTERNAL、SERVER、CLIENT、PRODUCER、CONSUMER。默认为CLIENT。
    setStart(start)设置Span的开始时间。
    addAttribute(attribute)增加Attribute属性信息。
    addAttribute(attributes)增加一组Attribute属性信息。
    addResource(resource)增加Resource资源信息。
  • Span
    字段/方法说明
    setName(name)设置Span名称。
    setKind(SpanKind)设置Span类型,支持设置为INTERNAL、SERVER、CLIENT、PRODUCER、CONSUMER。默认为CLIENT。
    setTraceId(traceId)设置Trace ID,不建议手动设置。
    setSpanId(spanId)设置Span ID,不建议手动设置。
    setParentSpanId(spanId)设置父Span ID。
    setStart(start)设置Span开始时间,不建议手动设置。
    setEnd(end)设置Span结束时间。
    setDuration(duration)设置Span持续时间,不建议手动设置。
    setStatus(StatusCode)设置Span状态,支持设置为ERROR、UNSET、OK。默认为UNSET。
    setStatusMessage(message)设置Span状态的描述信息。
    setHost(host)设置Host。
    setService(service)设置服务名称,默认为Android。
    addAttribute(attribute)增加Attribute属性信息。
    addAttribute(attribute...)增加Attribute属性信息。
    addAttribute(attributes)增加Attribute属性信息。
    addResource(resource)增加Resource资源信息。
    end()结束当前Span。
    isEnd()判断当前Span是否结束。
    toMap()转换Span数据结构为Map对象。
  • Resource
    字段/方法说明
    getDefault()返回默认的Resource对象,包含的默认资源信息,请参见Resource对象信息
    of(String key, Object value)基于传入的key和value,返回一个Resource对象。
    of(Pair<String, Object>... resources)根据传入的Pair键值对,返回一个Resource对象。
    of(List<Attribute> attributes)根据传入的Attribute List,返回一个Resource对象。
    add(String key, Object value)添加key和value信息到当前Resource对象。
    merge(Resource resource)将传入的Resource对象信息合并到当前Resource中实现。

    Resource对象信息

    keyvalue
    sdk.languageAndroid
    host.nameAndroid
    device.model.identifierBuild.MODEL
    device.model.nameBuild.PRODUCT
    device.manufacturerBuild.MANUFACTURER
    os.typeLinux
    os.descriptionBuild.DISPLAY
    os.nameAndroid
    os.versionBuild.VERSION.RELEASE
    os.sdkBuild.VERSION.SDK
    host.nameBuild.HOST
    host.typeBuild.TYPE
    host.archBuild.CPU_ABI + (TextUtils.isEmpty(Build.CPU_ABI2) ? "" : (", " + Build.CPU_ABI2))
    sls.sdk.versionBuildConfig.VERSION_NAME
  • Attribute
    字段/方法说明
    of(String key, boolean value)返回一个Attribute对象。
    of(String key, int value)返回一个Attribute对象。
    of(String key, long value)返回一个Attribute对象。
    of(String key, double value)返回一个Attribute对象。
    of(String key, String value)返回一个Attribute对象。
    of(final String key, final Object value)返回一个Attribute对象。
    of(Pair<String, Object>... kvs)返回一个Attribute List对象。

其他说明

设置Span为活跃后,在当前上下文环境中新产生的Span都会与活跃Span自动关联。具体表现为currentSpan.parentSpanID = activeSpan.spanIDcurrentSpan.traceID = activeSpan.traceID
说明 不同的业务代码运行在同一个线程时,上下文环境就是指当前线程。同一个上下文环境只有一个Span处于活跃状态。

后续步骤