1. 在项目中集成神策分析 SDK

Java SDK 已经开源到 GitHub,链接地址:https://github.com/sensorsdata/sa-sdk-java。并且已经发布到 maven 中央仓库。您可以选择以下方式进行集成:

最新版本的神策 Java SDK 支持的 JDK 最低版本为 JDK 1.7 及以上版本

1.1. 使用 Maven 集成

	<dependencies>
        <!-- 引入神策分析 SDK -->
        <dependency>
            <groupId>com.sensorsdata.analytics.javasdk</groupId>
            <artifactId>SensorsAnalyticsSDK</artifactId>
            <version>3.4.3</version>
        </dependency>
	</dependencies>
CODE

1.2. 使用 Gradle 集成

dependencies {
    compile 'com.sensorsdata.analytics.javasdk:SensorsAnalyticsSDK:3.4.3'
}
CODE

1.3. 依赖本地 Lib

如果您的项目没有使用任何 jar 包管理工具,可以选择从 GitHub 下载指定 release 版本,进行本地依赖;

2. 初始化神策分析 SDK

Java SDK 主要由以下两个组件组成:

  • ISensorsAnalytics :对外暴露的生成数据的顶层接口对象,构造函数需要传入一个 consumer 实例对象
  • Consumer :提供不同能力的数据发送机制

2.1. 获取数据接收地址

如下图所示获取数据接收地址:

2.2. 初始化 SDK

由于 SDK 初始化操作,会创建一个与之对应的内存缓存队列,所以请谨慎创建 SDK 实例对象,推荐在应用程序启动时全局初始化一次,然后进行全局调用。避免在方法内部进行初始化操作,程序运行过程中创建多个实例对象,导致 OOM 现象。

在很多客户的使用过程中,我们观察到因为使用 SDK 方式不对,而导致影响整体业务逻辑的性能。所以在按照官网教程完成初始化之后,在采集日志的过程中,不推荐主动调用 flush 操作。因为 flush 操作,会由 SDK 内部主动触发。

如果每次 track 之后,进行 flush 操作,会使得内部缓存队列失效,高并发情况下,会引起频繁锁竞争,会导致服务性能下降。

2.2.1. 在普通 Java 程序中初始化 SDK 

在程序启动时(如 public static void main(String[] args) 方法中),调用构造函数 new SensorsAnalytics(Consumer) 初始化 Java SDK 实例(需要全局初始化一次即可)

// 使用 ConcurrentLoggingConsumer 初始化 SensorsAnalytics
final SensorsAnalytics sa = new SensorsAnalytics(new ConcurrentLoggingConsumer("您的日志文件路径"));

// 用户的 Distinct ID
String distinctId = "ABCDEF123456789";

// 记录用户登录事件
EventRecord loginRecord = EventRecord.builder().setDistinctId(distinctId).isLoginId(Boolean.TRUE)
                              .setEventName("UserLogin")
                              .build();
sa.track(loginRecord);

// 使用神策分析记录用户行为数据
// ...
CODE

2.2.2. 在 Spring 框架里面初始化 SDK

如果您的项目使用 Spring 框架,推荐将初始化操作装配成 Bean,交给 Spring 容器来管理。在使用的类中注入即可使用。

2.2.2.1. 使用注解创建 Bean 对象

@Configuration
public class SensorsConfig {

    @Bean(destroyMethod = "shutdown")
    public ISensorsAnalytics init() throws IOException {
        //本地日志模式(此模式会在指定路径生成相应的日志文件)
        return new SensorsAnalytics(new ConcurrentLoggingConsumer("您的日志文件路径"));
        //debug 模式(此模式只适用于测试集成 SDK 功能,千万不要使用到生产环境!!!)
        //return new SensorsAnalytics(new DebugConsumer("数据接收地址", true));
        //网络批量发送模式(此模式在容器关闭的时候,如果存在数据还没有发送完毕,就会丢失未发送的数据!!!)
        //return new SensorsAnalytics(new BatchConsumer("数据接收地址"));
    }

}
CODE

2.2.2.2. 使用 xml 配置文件创建 Bean 对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <!-- 本地日志模式(此模式会在指定路径生成相应的日志文件) -->
    <bean id="loggingConsumer" class="com.sensorsdata.analytics.javasdk.consumer.ConcurrentLoggingConsumer">
        <constructor-arg name="filenamePrefix" value="您的日志文件路径"/>
    </bean>

    <!-- debug 模式(此模式只适用于测试集成 SDK 功能,千万不要使用到生产环境!!!) -->
    <!--<bean id="debugConsumer" class="com.sensorsdata.analytics.javasdk.consumer.DebugConsumer">
        <constructor-arg name="serverUrl" value="数据接收地址"/>
        <constructor-arg name="writeData" value="true"/>
    </bean>-->

    <!-- 网络批量发送模式(此模式在容器关闭的时候,如果存在数据还没有发送完毕,就会丢失未发送的数据!!!)-->
    <!--<bean id="batchConsumer" class="com.sensorsdata.analytics.javasdk.consumer.BatchConsumer">
        <constructor-arg name="serverUrl" value="数据接收地址"/>
    </bean>-->

    <!-- 此处选择合适的模式进行数据采集操作(此处选择本地日志模式) -->
    <bean id="sensorsAnalytics" class="com.sensorsdata.analytics.javasdk.SensorsAnalytics" destroy-method="shutdown">
        <constructor-arg name="consumer" ref="loggingConsumer"/>
    </bean>

</beans>
CODE

2.3. ISensorsAnalytics API 介绍

接口方法名称请求参数返回参数描述
setEnableTimeFreeboolean  true:表示开启历史数据导入模式,默认关闭void开启导入历史数据模式

registerSuperProperties

SuperPropertiesRecord:公共属性实体

void给事件属性设置全局公共属性,避免给单个事件都添加

clearSuperProperties

-void清除设置的全局公共属性

track

EventRecord:事件信息实体,填充用户行为属性记录

void记录用户行为埋点操作

trackSignUp

  • loginId:登录 ID
  • anonymousId:匿名 ID
void记录匿名用户和登录 ID 绑定操作,用于识别用户登录前后的行为序列
profileSetUserRecord:用户信息实体,填充用户属性记录void记录单个用户的属性信息
profileSetOnceUserRecord:用户信息实体,填充用户属性记录void首次设置用户属性;与 profileSet 接口不同的是:在这个用户的 profile 中已经存在,则不处理,否则,新创建
profileIncrementUserRecord:用户信息实体,填充用户属性记录void为指定用户的一个或多个数值类型的属性累加一个数值,若该属性不存在,则创建它并设置默认值为0。属性取值只接受 Number类型
profileAppendUserRecord:用户信息实体,填充用户属性记录void为指定用户的一个或多个数组类型的属性追加字符串,属性取值类型必须为 java.util.List,且列表中元素的类型 必须为 String
profileUnsetUserRecord:用户信息实体,填充用户属性记录void删除指定用户已存在的一条或者多条属性
profileDeleteUserRecord:用户信息实体,填充用户属性记录void删除指定用户所有属性
itemSetItemRecord:维度表信息实体void增加item 记录
itemDeleteItemRecord:维度表信息实体void删除 item
flush-void立即发送缓存中的所有日志(非调试或程序关闭时,请不要主动调用该方法
shutdown-void停止SensorsDataAPI所有线程,API停止前会清空所有本地数据

3. SDK Consumer 介绍

3.1. DebugConsumer

用于校验 SDK 是否集成正常,以及数据发送到神策服务器是否正常。

由于 Debug 模式是为了校验 SDK 集成以及数据传输地址是否正常而提供的模式,该模式会逐条校验数据并在校验失败时抛出异常,性能远低于正常模式。

即仅适用于本地调试环境,任何线上服务请务必不要使用该模式。

构造参数说明:

参数名参数类型是否必填说明
serverUrlString数据接收地址
writeDataboolean数据是否入库,true:表示数据入库;false:表示数据不入库(只展示不保存)

代码示例:

// 从神策服务器数据接入引导页面获取的数据接收的 URL
String serverUrl = ""; 
ISensorsAnalytics sa = new SensorsAnalytics(new DebugConsumer(serverUrl,true));
CODE

3.2. ConcurrentLoggingConsumer

用于将数据输出到指定文件目录并按天切割生成日志,并使用 LogAgent 等工具导入,该工具能保证导入不重复、不遗漏。推荐在生产环境中使用 ConcurrentLoggingConsumer 导入数据。支持多个进程写同一个目录(目录不能是 nas、nfs 类文件系统),生成的文件始终是带日期后缀的,默认每天一个。

构造参数说明:

参数名参数类型是否必填说明
filenamrPrefixString数据保存文件路径
bufferSizeintConsumer 内部缓存大小; 默认 8192 字节数
lockFileNameString

用于 windows 环境下,指定一个文件地址用于文件锁;用于避免 LogAgent 和 SDK 同时读写文件

splitModeLogSplitMode生成日志切割模式,默认是 LogSplitMode.DAY;可选 LogSplitMode.HOUR

代码示例:

// 将数据输出到 /data/sa 下的 access.log.2017-01-11 文件中,每天一个文件;对应目录文件需要自己创建,日志文件后缀会自动生成
final SensorsAnalytics sa = new SensorsAnalytics(new ConcurrentLoggingConsumer("/data/sa/access.log"));

// !! 注意 !! 如果是在 Windows 环境下使用 ConcurrentLoggingConsumer 并使用 LogAgent 发送数据,
// 需要额外通过构造函数的第二个参数指定一个文件地址用于文件锁,例如:
// SensorsAnalytics sa = new SensorsAnalytics(new ConcurrentLoggingConsumer("D:\\data\\service", "D:\\var\\sa.lock"));
// 若该文件与数据文件同目录,配置 LogAgent 的 pattern 时请不要匹配到这个文件。
CODE

3.3. BatchConsumer 

批量发送数据的 Consumer,当数据达到指定的量时(默认50条,最多可指定1000条),才将数据进行发送。也可以调用 flush() 方法去强制发送。注意:BatchConsumer 默认不会抛出异常,如果网络出现异常,导致数据发送失败,会造成数据丢失。如果你想获取对应的异常信息,需要通过初始化函数  BatchConsumer(final String serverUrl, final int bulkSize, final boolean throwException) 指定 throwException 参数为 true。

通常用于导入小规模历史数据,或者离线 / 旁路导入数据的场景。由于是网络直接发送数据,如果网络出现异常可能会导致数据丢失,因此不推荐在线上服务中使用。

若使用网络发送模式,不想发送异常丢失数据,推荐使用 FastBatchConsumer  模式

构造参数说明:

参数名参数类型是否必填说明
serverUrlString数据接收地址
bulkSizeint触发 flush 操作阈值,当内存缓存队列达到该值时,将缓存中的数据批量上报,默认 50
timeoutSecint

网络请求超时时间,默认 3S

maxCacheSizeint最大缓存刷新大小,若超过该值,立即触发 flush 操作,默认为 0 ,根据 bulkSize 来进行判断
throwExceptionboolean网络请求时发生异常是否抛出,true:抛出;false:不抛出;默认不抛出

代码示例:

// 从神策分析获取的数据接收的 URL
final String SA_SERVER_URL = "YOUR_SERVER_URL";
// 当缓存的数据量达到50条时,批量发送数据
final int SA_BULK_SIZE = 50;
// 数据同步失败不抛出异常
final boolean THROW_EXCEPTION = false;
// 内存中数据最大缓存条数,如此值大于0,代表缓存的数据会有条数限制,最小 3000 条,最大 6000 条。否则无条数限制。
final int MAX_CACHE_SIZE = 0;
// 使用 BatchConsumer 初始化 SensorsAnalytics
// 不要在任何线上的服务中使用此 Consumer
final SensorsAnalytics sa = new SensorsAnalytics(new BatchConsumer(SA_SERVER_URL, SA_BULK_SIZE, MAX_CACHE_SIZE, THROW_EXCEPTION));
CODE

3.4. FastBatchConsumer

针对 BatchConsumer 模式的一种优化模式,通过提供回调函数收集发送失败的数据。

回调函数会收集放入缓存失败的数据以及网络请求过程中发送失败的数据,3.4.0+ 版本提供了 resendFailedData() 接口用于重发送失败的数据。

FastBatchConsumer 创建一个新的线程来消费缓存中的数据,这样不会阻塞主线程的操作;如果在接口中初始化,会导致创建无限个消费者线程,导致系统资源紧张,所以请务必在全局初始化一次即可!!!

构造参数说明:

参数名参数类型是否必填说明
serverUrlString数据接收地址
timingboolean消费者线程运行时,true:表示消费者线程定时运行执行 flush 操作(设置该值就会使 bulkSize 失效); false:表示消费者线程定时运行时检查缓存队列是否达到 bulkSize,进行 flush 操作
bulkSizeint触发 flush 操作阈值,当内存缓存队列达到该值时,将缓存中的数据批量上报,默认 50
timeoutSecint

网络请求超时时间,默认 3S

maxCacheSizeint内存缓存队列保存记录最大条数,默认 6000,上限 10000,下限 1000
flushSecint消费者线程定时执行频率,默认 1S
callbackCallback回调函数返回失败数据;3.4.5 版本针对返回的数据进行优化,在此之前返回缓存中全部的数据(有发送成功和发送失败的);3.4.5 版本进行优化,只返回发送失败的那一批数据;比如有100条数据,分成两个批次上报,第一次上报失败,第二次上报成功;则回调函数只返回1-50条数据;

代码示例:

 	//发送失败的数据,收集容器。(仅测试使用,避免网络异常时,大批量数据发送失败同时保存内存中,导致 OOM )
    final List<FailedData> failedDataList = new ArrayList<>();

    //参数含义:数据接收地址,是否定时上报,非定时上报阈值触发条数,内部缓存最大容量,定时刷新时间间隔,网络请求超时时间,请求失败之后异常数据回调
	//提供多重构造函数,可以根据实际去调用不同的构造函数
    final FastBatchConsumer fastBatchConsumer =
        new FastBatchConsumer("serviceUri", false, 50, 6000, 2, 3, new Callback() {
          @Override
          public void onFailed(FailedData failedData) {
            //收集发送失败的数据
            failedDataList.add(failedData);
          }
        });
    //构建 sa 实例对象
    final SensorsAnalytics sa = new SensorsAnalytics(fastBatchConsumer);

    //do something track event
    sa.track(EventRecord.builder().build());

    //异常数据的重发送设置(重发送尽量由另外一个单独的线程来处理完成,避免影响主线程处理逻辑)
    if (!failedDataList.isEmpty()) {
      for (FailedData failedData : failedDataList) {
        try {
          //返回重发送接口发送成功与否,true:发送成功;false:发送失败
          boolean b = fastBatchConsumer.resendFailedData(failedData);
        } catch (Exception e) {
          //处理重发送数据校验异常的情况
          e.printStackTrace();
        }
      }
    }
CODE

3.5. ConsoleConsumer

用于将数据输出到特定 Writer,一般用于在生产环境的 Java 程序中处理历史数据,生成日志文件并使用 Integrator Importer 使用文档 等工具导入

构造参数说明:

参数名参数类型是否必填说明

writer

Writer指定 Writer

代码示例:

// 将数据输出到标准输出
final Writer writer = new PrintWriter(System.out);

// 使用 ConsoleConsumer 初始化 SensorsAnalytics
final SensorsAnalytics sa = new SensorsAnalytics(new ConsoleConsumer(writer));

// 使用神策分析记录用户行为数据
// ...

// Flush the writer
writer.flush();
CODE

3.6. LoggingConsumer (已不推荐使用)

已不推荐在生产环境中使用,因为在多进程下文件切分可能有问题。已使用 LoggingConsumer 的客户建议按照如下步骤切换到 ConcurrentLoggingConsumer;

4. API 接口

针对 API 接口的使用文档,参照基础 API 使用文档介绍