Android 应用接入¶
观测云应用监测能够通过收集各个 Android 应用的指标数据,以可视化的方式分析各个 Android 应用端的性能。
前置条件¶
- 安装 DataKit;
- 配置 RUM 采集器;
- DataKit 配置为公网可访问,并且安装 IP 地理信息库。
应用接入¶
登录观测云控制台,进入用户访问监测页面,点击左上角 新建应用,即可开始创建一个新的应用。
安装¶
源码地址:https://github.com/GuanceCloud/datakit-android
Demo:https://github.com/GuanceDemo/guance-app-demo
Gradle 配置¶
在项目的根目录的 build.gradle
文件中添加 SDK
的远程仓库地址
buildscript {
//...
repositories {
//...
//添加 SDK 的远程仓库地址
maven {
url 'https://mvnrepo.jiagouyun.com/repository/maven-releases'
}
}
dependencies {
//...
//添加 Plugin 的插件,依赖 AGP 7.4.2 以上,Gradle 7.2.0 以上
classpath 'com.cloudcare.ft.mobile.sdk.tracker.plugin:ft-plugin:[latest_version]'
// AGP 7.4.2 以下版本,请使用 ft-plugin-legacy
//classpath 'com.cloudcare.ft.mobile.sdk.tracker.plugin:ft-plugin-legacy:[latest_version]'
}
}
allprojects {
repositories {
//...
//添加 SDK 的远程仓库地址
maven {
url 'https://mvnrepo.jiagouyun.com/repository/maven-releases'
}
}
}
//setting.gradle
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
//添加 SDK 的远程仓库地址
maven {
url('https://mvnrepo.jiagouyun.com/repository/maven-releases')
}
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
//添加 SDK 的远程仓库地址
maven {
url('https://mvnrepo.jiagouyun.com/repository/maven-releases')
}
}
}
//build.gradle
plugins{
//添加 Plugin 的插件,依赖 AGP 7.4.2 以上,Gradle 7.2.0 以上
id 'com.cloudcare.ft.mobile.sdk.tracker.plugin' version '[lastest_version]' apply false
// AGP 7.4.2 以下版本,请使用 ft-plugin-legacy
//id 'com.cloudcare.ft.mobile.sdk.tracker.plugin.legacy' version '[lastest_version]' apply false
}
在项目主模块 app
的 build.gradle
文件中添加 SDK
的依赖及 Plugin
的使用 和 Java 8 的支持
dependencies {
//添加 SDK 的依赖
implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-sdk:[latest_version]'
//捕获 native 层崩溃信息的依赖,需要配合 ft-sdk 使用不能单独使用
implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-native:[latest_version]'
//推荐使用这个版本,其他版本未做过充分兼容测试
implementation 'com.google.code.gson:gson:2.8.5'
}
//应用插件
apply plugin: 'ft-plugin'
//配置插件使用参数
FTExt {
//是否显示 Plugin 日志,默认为 false
showLog = true
}
android{
//...省略部分代码
defaultConfig {
//...省略部分代码
ndk {
//当使用 ft-native 捕获 native 层的崩溃信息时,应该根据应用适配的不同的平台
//来选择支持的 abi 架构,目前 ft-native 中包含的 abi 架构有 'arm64-v8a',
// 'armeabi-v7a', 'x86', 'x86_64'
abiFilters 'armeabi-v7a'
}
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}
最新的版本请看上方的 Agent 和 Plugin 的版本名
SDK 初始化¶
基础配置¶
理论上最佳初始化 SDK 的位置在 Application
的 onCreate
方法中,如果您的应用还没有创建 Application
,您需要创建一个,并且在 AndroidManifest.xml
中 Application
中声明,示例请参考这里
方法名 | 类型 | 必须 | 含义 | 注意 |
---|---|---|---|---|
metricsUrl | String | 是 | Datakit 安装地址 | datakit 安装地址 URL 地址,例子:http://10.0.0.1:9529,端口默认 9529,。注意:安装 SDK 设备需能访问这地址 |
setDebug | String | 否 | 是否开启调试模式 | 默认为 false ,开启后方可打印 SDK 运行日志 |
setEnv | EnvType | 否 | 设置采集环境 | 默认为 EnvType.PROD |
setEnv | String | 否 | 设置采集环境 | 默认为 prod |
setOnlySupportMainProcess | Boolean | 否 | 是否只支持在主进程运行 | 默认为 true ,如果需要在其他进程中执行需要将该字段设置为 false |
setEnableAccessAndroidID | Boolean | 否 | 开启获取 Android ID |
默认,为 true ,设置为 false ,则 device_uuid 字段数据将不进行采集,市场隐私审核相关查看这里 |
addGlobalContext | Dictionary | 否 | 添加 SDK 全局属性 | 添加规则请查阅此处 |
setServiceName | String | 否 | 设置服务名 | 影响 Log 和 RUM 中 service 字段数据,默认为 df_rum_android |
RUM 配置¶
FTSdk.initRUMWithConfig(
new FTRUMConfig()
.setRumAppId(RUM_APP_ID)
.setEnableTraceUserAction(true)
.setEnableTraceUserView(true)
.setEnableTraceUserResource(true)
.setSamplingRate(0.8f)
.setExtraMonitorTypeWithError(ErrorMonitorType.ALL.getValue())
.setDeviceMetricsMonitorType(DeviceMetricsMonitorType.ALL.getValue())
.setEnableTrackAppUIBlock(true)
.setEnableTrackAppCrash(true)
.setEnableTrackAppANR(true)
);
FTSdk.initRUMWithConfig(
FTRUMConfig()
.setRumAppId(RUM_APP_ID)
.setEnableTraceUserAction(true)
.setEnableTraceUserView(true)
.setEnableTraceUserResource(true)
.setSamplingRate(0.8f)
.setExtraMonitorTypeWithError(ErrorMonitorType.ALL.getValue())
.setDeviceMetricsMonitorType(DeviceMetricsMonitorType.ALL.getValue())
.setEnableTrackAppUIBlock(true)
.setEnableTrackAppCrash(true)
.setEnableTrackAppANR(true)
)
方法名 | 类型 | 必须 | 含义 | 注意 |
---|---|---|---|---|
setRumAppId | String | 是 | 设置Rum AppId |
对应设置 RUM appid ,才会开启RUM 的采集功能,获取 appid 方法 |
setSampleRate | Boolean | 否 | 设置采集率 | 采集率的值范围为>= 0、<= 1,默认值为 1 |
setEnableTrackAppCrash | Boolean | 否 | 是否上报 App 崩溃日志 | 默认为 false ,开启后会在错误分析中显示错误堆栈数据。关于崩溃日志中混淆内容转换的问题 |
setExtraMonitorTypeWithError | Array | 否 | 设置辅助监控信息 | 添加附加监控数据到 Rum 崩溃数据中,ErrorMonitorType.BATTERY 为电池余量,ErrorMonitorType.MEMORY 为内存用量,ErrorMonitorType.CPU 为 CPU 占有率 |
setDeviceMetricsMonitorType | Array | 否 | 设置 View 监控信息 | 在 View 周期中,添加监控数据,DeviceMetricsMonitorType.BATTERY 监控当前页的最高输出电流输出情况,DeviceMetricsMonitorType.MEMORY 监控当前应用使用内存情况,DeviceMetricsMonitorType.CPU 监控 CPU 跳动次数 ,DeviceMetricsMonitorType.FPS 监控屏幕帧率 |
setEnableTrackAppANR | Boolean | 否 | 是否开启 ANR 检测 | 默认为 false |
setEnableTrackAppUIBlock | Boolean | 否 | 是否开启 UI 卡顿检测 | 默认为 false |
setEnableTraceUserAction | Boolean | 否 | 是否自动追踪用户操作 | 目前只支持用户启动和点击操作,默认为 false |
setEnableTraceUserView | Boolean | 否 | 是否自动追踪用户页面操作 | 默认为 false |
setEnableTraceUserResource | Boolean | 否 | 是否自动追动用户网络请求 | 仅支持 Okhttp ,默认为 false |
setResourceUrlHandler | callback | 否 | 设置需要过滤的 Resource 条件 | 默认不过滤 |
addGlobalContext | Dictionary | 否 | 添加自定义标签 | 添加标签数据,用于用户监测数据源区分,如果需要使用追踪功能,则参数 key 为 track_id ,value 为任意数值,添加规则注意事项请查阅此处 |
添加自定义标签¶
静态使用¶
1.在 build.gradle
中创建多个 productFlavors
来做区分区分标签
android{
//…
productFlavors {
prodTest {
buildConfigField "String", "CUSTOM_VALUE", "\"Custom Test Value\""
//…
}
prodPublish {
buildConfigField "String", "CUSTOM_VALUE", "\"Custom Publish Value\""
//…
}
}
}
2.在 RUM
配置中添加对应 BuildConfig
常量
动态使用¶
1.通过存文件类型数据,例如 SharedPreferences
,配置使用 SDK
,在配置处添加获取标签数据的代码。
2.在任意处添加改变文件数据的方法。
3.最后重启应用,详细细节请见 SDK Demo
Log 配置¶
方法名 | 类型 | 必须 | 含义 | 注意 |
---|---|---|---|---|
setSampleRate | Boolean | 否 | 设置采集率 | 采集率的值范围为>= 0、<= 1,默认值为 1 |
setEnableConsoleLog | Boolean | 否 | 是否上报控制台日志 | 日志等级对应关系 Log.v -> ok; Log.i、Log.d -> info; Log.e -> error; Log.w -> warning, prefix 为控制前缀过滤参数,默认不设置过滤 |
setEnableLinkRUMData | Boolean | 否 | 是否与 RUM 数据关联 | 默认为 false |
setLogCacheDiscardStrategy | LogCacheDiscard | 否 | 设置频繁日志丢弃规则 | 默认为 LogCacheDiscard.DISCARD ,DISCARD 为丢弃追加数据,DISCARD_OLDEST 丢弃老数据 |
setEnableCustomLog | Boolean | 否 | 是否上传自定义日志 | 默认为 false |
setLogLevelFilters | Array | 否 | 设置日志等级过滤 | 设置等级日志过滤,默认不设置 |
addGlobalContext | Dictionary | 否 | 添加 log 全局属性 | 添加规则请查阅此处 |
Trace 配置¶
方法名 | 类型 | 必须 | 含义 | 注意 |
---|---|---|---|---|
setSampleRate | Boolean | 否 | 设置采集率 | 采集率的值范围为>= 0、<= 1,默认值为 1 |
setTraceType | TraceType | 否 | 设置链路追踪的类型 | 默认为 DDTrace ,目前支持 Zipkin , Jaeger , DDTrace ,Skywalking (8.0+),TraceParent (W3C),如果接入 OpenTelemetry 选择对应链路类型时,请注意查阅支持类型及 agent 相关配置 |
setEnableLinkRUMData | Boolean | 否 | 是否与 RUM 数据关联 | 默认为 false |
setEnableAutoTrace | Boolean | 否 | 设置是否开启自动 http trace | 目前只支持 OKhttp 的自动追踪,默认为 false |
setEnableWebTrace | Boolean | 否 | 设置 webview 是否开启链路追踪 | alpha 功能,有一部分场景可能会有部分 js 加载问题,默认为 false |
RUM 用户数据追踪¶
FTRUMConfig
配置 enableTraceUserAction
, enableTraceUserView
, enableTraceUserResource
来实现自动获取数据的效果或手动使用 FTRUMGlobalManager
来实现添加这些数据,示例如下:
Action¶
使用方法¶
/**
* 添加 action
*
* @param actionName action 名称
* @param actionType action 类型
*/
public void startAction(String actionName, String actionType)
/**
* 添加 action
*
* @param actionName action 名称
* @param actionType action 类型
* @param property 附加属性参数
*/
public void startAction(String actionName, String actionType, HashMap<String, Object> property)
/**
* 添加 action
*
* @param actionName action 名称
* @param actionType action 类型
*/
fun startAction(actionName: String, actionType: String)
/**
* 添加 action
*
* @param actionName action 名称
* @param actionType action 类型
* @param property 附加属性参数
*/
fun startAction(actionName: String, actionType: String, property: HashMap<String, Any>)
代码示例¶
View¶
使用方法¶
/**
* view 起始
*
* @param viewName 当前页面名称
*/
public void startView(String viewName)
/**
* view 起始
*
* @param viewName 当前页面名称
* @param property 附加属性参数
*/
public void startView(String viewName, HashMap<String, Object> property)
/**
* view 结束
*/
public void stopView()
/**
* view 结束
*
* @param property 附加属性参数
*/
public void stopView(HashMap<String, Object> property)
/**
* view 起始
*
* @param viewName 当前页面名称
*/
fun startView(viewName: String)
/**
* view 起始
*
* @param viewName 当前页面名称
* @param property 附加属性参数
*/
fun startView(viewName: String, property: HashMap<String, Any>)
/**
* view 结束
*/
fun stopView()
/**
* view 结束
*
* @param property 附加属性参数
*/
fun stopView(property: HashMap<String, Any>)
代码示例¶
@Override
protected void onResume() {
super.onResume();
// 场景 1
FTRUMGlobalManager.get().startView("Current Page Name");
// 场景 2: 动态参数
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
map.put("ft_key_will_change", "ft_value");
FTRUMGlobalManager.get().startView("Current Page Name", map);
}
@Override
protected void onPause() {
super.onPause();
// 场景 1
FTRUMGlobalManager.get().stopView();
// 场景 2 : 动态参数
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key_will_change", "ft_value_change"); //ft_key_will_change 这个数值,会在 stopView 时候被修改为 ft_value_change
FTRUMGlobalManager.get().startView("Current Page Name", map);
}
override fun onResume() {
super.onResume()
// 场景 1
FTRUMGlobalManager.get().startView("Current Page Name")
// 场景 2: 动态参数
val map = HashMap<String, Any>()
map["ft_key"] = "ft_value"
map["ft_key_will_change"] = "ft_value"
FTRUMGlobalManager.get().startView("Current Page Name", map)
}
override fun onPause() {
super.onPause()
// 场景 1
FTRUMGlobalManager.get().stopView()
// 场景 2 : 动态参数
val map = HashMap<String, Any>()
map["ft_key_will_change"] = "ft_value_change" //ft_key_will_change 这个数值,会在 stopView 时候被修改为 ft_value_change
FTRUMGlobalManager.get().startView("Current Page Name", map)
}
Error¶
使用方法¶
/**
* 添加错误信息
*
* @param log 日志
* @param message 消息
* @param errorType 错误类型
* @param state 程序运行状态
*/
public void addError(String log, String message, ErrorType errorType, AppState state)
/**
* 添加错误
*
* @param log 日志
* @param message 消息
* @param errorType 错误类型
* @param state 程序运行状态
* @param dateline 发生时间,纳秒
*/
public void addError(String log, String message, long dateline, ErrorType errorType, AppState state)
/**
* 添加错误信息
*
* @param log
* @param message
* @param errorType
* @param state
* @param property
*/
public void addError(String log, String message, ErrorType errorType, AppState state, HashMap<String, Object> property)
/**
* 添加错误
*
* @param log 日志
* @param message 消息
* @param errorType 错误类型
* @param state 程序运行状态
* @param dateline 发生时间,纳秒
*/
public void addError(String log, String message, long dateline, ErrorType errorType,
AppState state, HashMap<String, Object> property)
/**
* 添加错误信息
*
* @param log 日志
* @param message 消息
* @param errorType 错误类型
* @param state 程序运行状态
*/
fun addError(log: String, message: String, errorType: ErrorType, state: AppState)
/**
* 添加错误
*
* @param log 日志
* @param message 消息
* @param errorType 错误类型
* @param state 程序运行状态
* @param dateline 发生时间,纳秒
*/
fun addError(log: String, message: String, dateline: Long, errorType: ErrorType, state: AppState)
/**
* 添加错误信息
*
* @param log
* @param message
* @param errorType
* @param state
* @param property
*/
fun addError(log: String, message: String, errorType: ErrorType, state: AppState, property: HashMap<String, Any>)
/**
* 添加错误
*
* @param log 日志
* @param message 消息
* @param errorType 错误类型
* @param state 程序运行状态
* @param dateline 发生时间,纳秒
*/
fun addError(log: String, message: String, dateline: Long, errorType: ErrorType,state: AppState, property: HashMap<String, Any>)
代码示例¶
// 场景 1:
FTRUMGlobalManager.get().addError("error log", "error msg", ErrorType.JAVA, AppState.RUN);
// 场景 2:延迟记录发生的错误,这里的时间一般为错误发生的时间
FTRUMGlobalManager.get().addError("error log", "error msg", 16789000000000000000L, ErrorType.JAVA, AppState.RUN);
// 场景 3:动态参数
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
FTRUMGlobalManager.get().addError("error log", "error msg", ErrorType.JAVA, AppState.RUN, map);
// 场景 1:
FTRUMGlobalManager.get().addError("error log", "error msg", ErrorType.JAVA, AppState.RUN)
// 场景 2:延迟记录发生的错误,这里的时间一般为错误发生的时间
FTRUMGlobalManager.get().addError("error log", "error msg", 16789000000000000000, ErrorType.JAVA, AppState.RUN)
// 场景 3:动态参数
val map = HashMap<String, Any>()
map["ft_key"] = "ft_value"
FTRUMGlobalManager.get().addError("error log", "error msg",ErrorType.JAVA,AppState.RUN,map)
LongTask¶
使用方法¶
代码示例¶
Resource¶
使用方法¶
/**
* resource 起始
*
* @param resourceId 资源 Id
*/
public void startResource(String resourceId)
/**
* resource 起始
*
* @param resourceId 资源 Id
*/
public void startResource(String resourceId, HashMap<String, Object> property)
/**
* resource 终止
*
* @param resourceId 资源 Id
*/
public void stopResource(String resourceId)
/**
* resource 终止
*
* @param resourceId 资源 Id
* @param property 附加属性参数
*/
public void stopResource(final String resourceId, HashMap<String, Object> property)
/**
* 设置网络传输内容
*
* @param resourceId
* @param params
* @param netStatusBean
*/
public void addResource(String resourceId, ResourceParams params, NetStatusBean netStatusBean)
/**
* resource 起始
*
* @param resourceId 资源 Id
*/
fun startResource(resourceId: String)
/**
* resource 起始
*
* @param resourceId 资源 Id
*/
fun startResource(resourceId: String, property: HashMap<String, Any>)
/**
* resource 终止
*
* @param resourceId 资源 Id
*/
fun stopResource(resourceId: String)
/**
* resource 终止
*
* @param resourceId 资源 Id
* @param property 附加属性参数
*/
fun stopResource(resourceId: String, property: HashMap<String, Any>)
/**
* 设置网络传输内容
*
* @param resourceId
* @param params
* @param netStatusBean
*/
fun addResource(resourceId: String, params: ResourceParams, netStatusBean: NetStatusBean)
代码示例¶
// 场景 1
// 请求开始
FTRUMGlobalManager.get().startResource("resourceId");
//...
// 请求结束
FTRUMGlobalManager.get().stopResource("resourceId");
// 最后,在请求结束之后,发送请求相关的数据指标
ResourceParams params = new ResourceParams();
params.setUrl("https://www.guance.com");
params.setResponseContentType(response.header("Content-Type"));
params.setResponseConnection(response.header("Connection"));
params.setResponseContentEncoding(response.header("Content-Encoding"));
params.setResponseHeader(response.headers().toString());
params.setRequestHeader(request.headers().toString());
params.setResourceStatus(response.code());
params.setResourceMethod(request.method());
NetStatusBean bean = new NetStatusBean();
bean.setTcpStartTime(60000000);
//...
FTRUMGlobalManager.get().addResource("resourceId", params, bean);
// 场景 2 :动态参数使用
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
map.put("ft_key_will_change", "ft_value");
FTRUMGlobalManager.get().startResource("resourceId",map);
//...
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key_will_change", "ft_value_change"); //ft_key_will_change 这个数值,会在 stopResource 时候被修改为 ft_value_change
FTRUMGlobalManager.get().stopResource(uuid,map);
// 场景 1
//请求开始
FTRUMGlobalManager.get().startResource("resourceId")
//请求结束
FTRUMGlobalManager.get().stopResource("resourceId")
//最后,在请求结束之后,发送请求相关的数据指标
val params = ResourceParams()
params.url = "https://www.guance.com"
params.responseContentType = response.header("Content-Type")
arams.responseConnection = response.header("Connection")
params.responseContentEncoding = response.header("Content-Encoding")
params.responseHeader = response.headers.toString()
params.requestHeader = request.headers.toString()
params.resourceStatus = response.code
params.resourceMethod = request.method
val bean = NetStatusBean()
bean.tcpStartTime = 60000000
//...
FTRUMGlobalManager.get().addResource("resourceId",params,bean)
// 场景 2 :动态参数使用
val map = hashMapOf<String, Any>(
"ft_key" to "ft_value",
"ft_key_will_change" to "ft_value"
)
FTRUMGlobalManager.get().startResource("resourceId", map)
//...
val map = hashMapOf<String, Any>(
"ft_key_will_change" to "ft_value_change"
)
// ft_key_will_change 这个数值,会在 stopResource 时候被修改为 ft_value_change
FTRUMGlobalManager.get().stopResource(uuid, map)
方法名 | 含义 | 必须 | 说明 |
---|---|---|---|
NetStatusBean.fetchStartTime | 请求开始时间 | 否 | |
NetStatusBean.tcpStartTime | tcp 连接时间 | 否 | |
NetStatusBean.tcpEndTime | tcp 结束时间 | 否 | |
NetStatusBean.dnsStartTime | dns 开始时间 | 否 | |
NetStatusBean.dnsEndTime | dns 结束时间 | 否 | |
NetStatusBean.responseStartTime | 响应开始时间 | 否 | |
NetStatusBean.responseEndTime | 响应结束时间 | 否 | |
NetStatusBean.sslStartTime | ssl 开始时间 | 否 | |
NetStatusBean.sslEndTime | ssl 结束时间 | 否 | |
ResourceParams.url | url 地址 | 是 | |
ResourceParams.requestHeader | 请求头参数 | 否 | |
ResourceParams.responseHeader | 响应头参数 | 否 | |
ResourceParams.responseConnection | 响应 connection | 否 | |
ResourceParams.responseContentType | 响应 ContentType | 否 | |
ResourceParams.responseContentEncoding | 响应 ContentEncoding | 否 | |
ResourceParams.resourceMethod | 请求方法 | 否 | GET,POST 等 |
ResourceParams.responseBody | 返回 body 内容 | 否 |
Logger 日志打印¶
使用 FTLogger
进行日志输出
使用方法¶
/**
* 将单条日志数据存入本地同步
*
* @param content 日志内容
* @param status 日志等级
*/
public void logBackground(String content, Status status)
/**
* 将单条日志数据存入本地同步
*
* @param content 日志内容
* @param status 日志等级
*/
public void logBackground(String content, Status status, HashMap<String, Object> property)
/**
* 将多条日志数据存入本地同步
*
* @param logDataList {@link LogData} 列表
*/
public void logBackground(List<LogData> logDataList)
/**
* 将单条日志数据存入本地同步
*
* @param content 日志内容
* @param status 日志等级
*/
fun logBackground(content: String, status: Status)
/**
* 将单条日志数据存入本地同步
*
* @param content 日志内容
* @param status 日志等级
* @param property 日志属性
*/
fun logBackground(content: String, status: Status, property: HashMap<String, Any>)
/**
* 将多条日志数据存入本地同步
*
* @param logDataList 日志数据列表
*/
fun logBackground(logDataList: List<LogData>)
日志等级¶
方法名 | 含义 |
---|---|
Status.INFO | 提示 |
Status.WARNING | 警告 |
Status.ERROR | 错误 |
Status.CRITICAL | 严重 |
Status.OK | 恢复 |
代码示例¶
// 上传单个日志
FTLogger.getInstance().logBackground("test", Status.INFO);
// 传递参数到 HashMap
HashMap<String, Object> map = new HashMap<>();
map.put("ft_key", "ft_value");
FTLogger.getInstance().logBackground("test", Status.INFO, map);
// 批量上传日志
List<LogData> logList = new ArrayList<>();
logList.add(new LogData("test", Status.INFO));
FTLogger.getInstance().logBackground(logList);
Tracer 网络链路追踪¶
FTTraceConfig
配置开启enableAutoTrace
自动添加链路数据,或手动使用 FTTraceManager
在 Http 请求中 Propagation Header
,示例如下:
String url = "https://www.guance.com";
String uuid = "uuid";
// 获取链路头参数
Map<String, String> headers = FTTraceManager.get().getTraceHeader(uuid, url);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder();
// 在请求中,添加链路头参数
for (String key : headers.keySet()) {
requestBuilder.header(key, headers.get(key));
}
Request request = requestBuilder.build();
Response response = chain.proceed(request);
if (response != null) {
Map<String, String> requestHeaderMap = new HashMap<>();
Map<String, String> responseHeaderMap = new HashMap<>();
for (Pair<String, String> header : response.request().headers()) {
requestHeaderMap.put(header.first, header.second);
}
for (Pair<String, String> header : response.headers()) {
responseHeaderMap.put(header.first, header.second);
}
}
return response;
}).build();
Request.Builder builder = new Request.Builder().url(url).method(RequestMethod.GET.name(), null);
client.newCall(builder.build()).execute();
val url = "https://www.guance.com"
val uuid ="uuid"
//获取链路头参数
val headers = FTTraceManager.get().getTraceHeader(uuid, url)
val client: OkHttpClient = OkHttpClient.Builder().addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
//在请求中,添加链路头参数
for (key in headers.keys) {
requestBuilder.header(key!!, headers[key]!!)
}
val request = requestBuilder.build()
response = chain.proceed(request)
if (response != null) {
val requestHeaderMap = HashMap<String, String>()
val responseHeaderMap = HashMap<String, String>()
request.headers.forEach {
requestHeaderMap[it.first] = it.second
}
response!!.headers.forEach {
responseHeaderMap[it.first] = it.second
}
}
response!!
}.build()
val builder: Request.Builder = Request.Builder().url(url).method(RequestMethod.GET.name, null)
client.newCall(builder.build()).execute()
用户信息绑定与解绑¶
使用 FTSdk
进行用户的绑定和解绑
使用方法¶
UserData¶
方法名 | 含义 | 必须 | 说明 |
---|---|---|---|
setId | 设置用户 ID | 否 | |
setName | 设置用户名 | 否 | |
setEmail | 设置邮箱 | 否 | |
setExts | 设置用户扩展 | 否 | 添加规则请查阅此处 |
代码示例¶
// 可以在用户登录成功后调用此方法用来绑定用户信息
FTSdk.bindRumUserData("001");
UserData userData = new UserData();
userData.setName("test.user");
userData.setId("test.id");
userData.setEmail("test@mail.com");
Map<String, String> extMap = new HashMap<>();
extMap.put("ft_key", "ft_value");
userData.setExts(extMap);
FTSdk.bindRumUserData(userData);
// 可以在用户退出登录后调用此方法来解绑用户信息
FTSdk.unbindRumUserData();
//可以在用户登录成功后调用此方法用来绑定用户信息
FTSdk.bindRumUserData("001")
//绑定用户更多数据
val userData = UserData()
userData.name = "test.user"
userData.id = "test.id"
userData("test@mail.com")
val extMap = HashMap<String, String>()
extMap["ft_key"] = "ft_value"
userData.setExts(extMap)
FTSdk.bindRumUserData(userData)
//可以在用户退出登录后调用此方法来解绑用户信息
FTSdk.unbindRumUserData()
关闭 SDK¶
使用 FTSdk
关闭 SDK
使用方法¶
代码示例¶
动态开启和关闭获取 AndroidID¶
使用 FTSdk
设置是否在 SDK中获取 android ID
使用方法¶
代码示例¶
R8 / Proguard 混淆配置¶
-dontwarn com.ft.sdk.**
-keep class com.ft.sdk.**{*;}
-keep class ftnative.*{*;}
### 防止获取时 ActionName 被混淆###
-keepnames class * extends android.view.View
-keepnames class * extends android.view.MenuItem
符号文件上传¶
plugin 上传¶
ft-plugin
版本需要 1.1.2
以上版本支持符号文件上传,支持 productFlavor
多版本区分管理,plugin 会在 gradle task assembleRelease
之后执行上传符号文件,详细配置可以参考 SDK Demo
FTExt {
//...
autoUploadMap = true
autoUploadNativeDebugSymbol = true
datakitDCAUrl = 'https://datakit.url:9531'//datakit 安装地址,默认 9531
appId = "appid_xxxxx"// appid
env = 'common'
prodFlavors { //prodFlavors 配置会覆盖外层设置
prodTest {
autoUploadMap = false
autoUploadNativeDebugSymbol = false
datakitDCAUrl = 'https://datakit.test.url:9531'
appId = "appid_prodTest"
env = "gray"
}
prodPublish {
autoUploadMap = true
autoUploadNativeDebugSymbol = true
datakitDCAUrl = 'https://datakit.publish.url:9531'
appId = "appid_prodPublish"
env = "prod"
}
}
}
手动上传¶
需要开发者将符号文件自行打包成 zip
文件,然后自行上传至 datakit
,推荐使用 zip
命令行进行打包,避免将一些系统隐藏文件打入 zip
包中,符号上传请参考 sourcemap 上传
权限配置说明¶
名称 | 使用原因 |
---|---|
READ_PHONE_STATE |
用于获取手机的设备信息,便于精准分析数据信息 |
关于如何申请动态权限,具体详情参考 Android Developer
Plugin AOP 忽略¶
通过 Plugin AOP 覆盖方法中添加 @IngoreAOP
来忽略 ASM 插入
常见问题¶
添加局变量避免冲突字段¶
为了避免自定义字段与 SDK 数据冲突,建议标签命名添加 项目缩写 的前缀,例如 df_tag_name
,项目中使用 key
值可查询源码。SDK 全局变量中出现与 RUM、Log 相同变量时,RUM、Log 会覆盖 SDK 中的全局变量。
应对市场隐私审核¶
隐私声明¶
SDK AndroidID 配置¶
SDK 为更好关联相同用户数据,会使用 Android ID。如果需要在应用市场上架,需要通过如下方式对应市场隐私审核。
public class DemoApplication extends Application {
@Override
public void onCreate() {
// 在初始化设置时将 setEnableAccessAndroidID 设置为 false
FTSDKConfig config = new FTSDKConfig.Builder(DATAKIT_URL)
.setEnableAccessAndroidID(false)
.build();
FTSdk.install(config);
// ...
}
}
// 用户同意隐私协议后再开启
FTSdk.setEnableAccessAndroidID(true);
延迟初始化 SDK¶
如果需要在应用中延迟加载 SDK,建议使用如下方式初始化。
// Application
public class DemoApplication extends Application {
@Override
public void onCreate() {
//如果已经同意协议,在 Application 中初始化
if(agreeProtocol){
FTSdk.init();
}
}
}
// 隐私声明 Activity 页面
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//未阅读隐私声明
if ( notReadProtocol ) {
//隐私声明弹出弹窗
showProtocolView();
//如果同意隐私声明
if( agreeProtocol ){
FTSdk.init();
}
}
}
}
// Application
class DemoApplication : Application() {
override fun onCreate() {
// 如果已经同意协议,在 Application 中初始化
if (agreeProtocol) {
FTSdk.init()
}
}
}
// 隐私声明 Activity 页面
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 未阅读隐私声明
if (notReadProtocol) {
// 隐私声明弹出弹窗
showProtocolView()
// 如果同意隐私声明
if (agreeProtocol) {
FTSdk.init()
}
}
}
}
无法使用 ft-plugin 情况下如何接入 SDK¶
观测云使用的 Androig Grale Plugin Transformation 实现的代码注入,从而实现数据自动收集。但是由于一些兼容性问题,可能存在无法使用 ft-plugin
的问题。受影响包括 RUM Action
,Resource
,和 android.util.Log
,Java 与 Kotlinprintln
控制台日志自动抓取,以及符号文件的自动上传。
目前针对这种情况,我们有另外一种集成方案,应对方案如下:
- Application 应用启动事件, 源码示例参考DemoForManualSet.kt
- 按键等事件需要在触发处自行添加,例如,Button onClick 事件为例,源码示例参考ManualActivity.kt:
OKhttp
通过addInterceptor
,eventListener
方式接入Resource
,Trace
,示例如下,源码示例参考ManualActivity.kt:
- 其他网络框架需要自行实现使用
FTRUMGlobalManager
中startResource
,stopResource
,addResource
,FTTraceManager.getTraceHeader
。具体实现方式,请参考源码示例ManualActivity.kt