diff --git a/app/build.gradle b/app/build.gradle index 97c481893b..074f2450bb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -126,6 +126,10 @@ android { } } + packagingOptions { + exclude 'META-INF/gradle/incremental.annotation.processors' + } + buildTypes { debug { debuggable true @@ -357,7 +361,9 @@ dependencies { implementation "com.lg:easyfloat:${easyFloat}" - implementation "com.lg:apksig:${apksig}" + implementation ("com.lg:apksig:${apksig}") { + exclude group: 'com.google.protobuf' + } implementation "com.lg:gid:${gid}" diff --git a/app/src/main/java/com/gh/common/exposure/ExposureManager.kt b/app/src/main/java/com/gh/common/exposure/ExposureManager.kt index 092b23f6da..6b5d052981 100644 --- a/app/src/main/java/com/gh/common/exposure/ExposureManager.kt +++ b/app/src/main/java/com/gh/common/exposure/ExposureManager.kt @@ -1,13 +1,13 @@ package com.gh.common.exposure -import com.aliyun.sls.android.producer.Log import com.gh.gamecenter.BuildConfig -import com.gh.gamecenter.common.loghub.LoghubHelper +import com.gh.gamecenter.common.loghub.TLogHubHelper import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet import com.gh.gamecenter.common.utils.toJson import com.gh.gamecenter.core.AppExecutor import com.gh.gamecenter.feature.exposure.ExposureEvent import com.lightgame.utils.Utils +import com.volcengine.model.tls.LogItem /** * A handful tool for committing logs to aliyun loghub. @@ -78,19 +78,20 @@ object ExposureManager { private fun uploadExposures(eventSet: HashSet, forced: Boolean) { eventSet.forEach { - LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced) + TLogHubHelper.sendLog(buildLog(it), LOG_STORE) +// LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced) // it.recycle() } } - private fun buildLog(event: ExposureEvent) = Log().apply { - putContent("id", event.id) - putContent("payload", event.payload.toJson()) - putContent("event", event.event.toString()) - putContent("source", eliminateMultipleBrackets(event.source.toJson())) - putContent("meta", event.meta.toJson()) - putContent("real_millisecond", event.timeInMillisecond.toString()) - putContent( + private fun buildLog(event: ExposureEvent) = LogItem(System.currentTimeMillis()).apply { + addContent("__id", event.id) + addContent("payload", event.payload.toJson()) + addContent("event", event.event.toString()) + addContent("source", eliminateMultipleBrackets(event.source.toJson())) + addContent("meta", event.meta.toJson()) + addContent("real_millisecond", event.timeInMillisecond.toString()) + addContent( "e-traces", if (event.eTrace != null) { eliminateMultipleBrackets(event.eTrace?.toJson() ?: "") } else "" diff --git a/dependencies.gradle b/dependencies.gradle index 657512d050..74f01f982c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -138,4 +138,6 @@ ext { acloudPush = "3.8.8.1" jpushVersion = "5.2.4" + + volcTlsVersion = "1.1.4" } \ No newline at end of file diff --git a/module_common/build.gradle b/module_common/build.gradle index 546be0463b..d3325e2151 100644 --- a/module_common/build.gradle +++ b/module_common/build.gradle @@ -84,7 +84,13 @@ dependencies { api "androidx.collection:collection-ktx:${collection}" api "androidx.activity:activity:${activity}" api "androidx.activity:activity-ktx:${activity}" - api "com.aliyun.openservices:aliyun-log-android-sdk:${aliyunLog}" + api ("com.volcengine:volc-tls-android-sdk:${volcTlsVersion}", { + exclude group: 'com.squareup.okhttp3' + exclude group: 'junit' + exclude group: 'com.google.code.gson' + exclude group: 'org.projectlombok' + exclude group: 'com.alibaba' + }) debugApi "com.lg:chucker:${chucker}" releaseApi "com.lg:chucker-no-op:${chucker}" debugApi "com.squareup.okhttp3:logging-interceptor:${okHttp}" diff --git a/module_common/proguard-rules.pro b/module_common/proguard-rules.pro index 7b37d9ccaf..03c2851a4b 100644 --- a/module_common/proguard-rules.pro +++ b/module_common/proguard-rules.pro @@ -77,4 +77,7 @@ -keep class com.gh.gamecenter.common.retrofit.* {*;} ### NonStickyMutableLiveData --keep class androidx.arch.core.internal.** {*;} \ No newline at end of file +-keep class androidx.arch.core.internal.** {*;} + +### vol log sdk + -keep class net.jpountz.** { *; } \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubHelper.kt b/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubHelper.kt index 909a65ebbb..bc87d27b9e 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubHelper.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubHelper.kt @@ -1,147 +1,147 @@ -package com.gh.gamecenter.common.loghub - -import com.aliyun.sls.android.producer.Log -import com.aliyun.sls.android.producer.LogProducerClient -import com.aliyun.sls.android.producer.LogProducerConfig -import com.aliyun.sls.android.producer.LogProducerResult -import com.gh.gamecenter.common.HaloApp -import com.gh.gamecenter.common.utils.EnvHelper -import com.gh.gamecenter.common.utils.PackageFlavorHelper -import com.gh.gamecenter.core.AppExecutor -import com.lightgame.utils.Utils - -/** - * 上传阿里云日志辅助类 - */ -object LoghubHelper { - - private const val ACCESS_KEY_ID = "LTAIV3i0sNc4TPK1" - private const val ACCESS_KEY_SECRET = "8dKtTPeE5WYA6ZCeuIBcIVp7eB0ir4" - private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com" - - private val mClientMaps by lazy { hashMapOf() } - - /** - * 上传日志至阿里云 loghub - * @param uploadImmediately 马上上传日志 - */ - fun uploadLog(log: Log, logStore: String, uploadImmediately: Boolean) { - // https://github.com/aliyun/aliyun-log-android-sdk/issues/60 - // 在主线程直接调用会有概率触发 ANR ,在工作线程调用有机率会创建多个工作线程,麻了,还是继续在工作线程上干吧 - AppExecutor.logExecutor.execute { - getClient(logStore)?.addLog(log, if (uploadImmediately) 1 else 0) - } - } - - private fun getClient(logStore: String): LogProducerClient? { - // https://jira.shanqu.cc/browse/GHZS-3815?focusedCommentId=50027&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-50027 - // - val transformedLogStore = if (EnvHelper.isGATApp) "event" else logStore - if (!mClientMaps.containsKey(transformedLogStore)) { - mClientMaps[transformedLogStore] = createClient(transformedLogStore) - } - return mClientMaps[transformedLogStore] - } - - private fun createClient(logStore: String): LogProducerClient { - - val config = LogProducerConfig( - HaloApp.getInstance().applicationContext, - ENDPOINT, - EnvHelper.logProducerProject, - logStore, - ACCESS_KEY_ID, - ACCESS_KEY_SECRET - ).apply { -// // 设置主题 -// setTopic("topic") -// // 设置tag信息,此tag会附加在每条日志上 -// addTag("key", "value") - // 每个缓存的日志包的大小上限,取值为1~5242880,单位为字节。默认为1024 * 1024 - setPacketLogBytes(1024 * 1024) - // 每个缓存的日志包中包含日志数量的最大值,取值为1~4096,默认为1024 - setPacketLogCount(1024) - // 被缓存日志的发送超时时间,如果缓存超时,则会被立即发送,单位为毫秒,默认为3000 - setPacketTimeout(3000) - // 单个Producer Client实例可以使用的内存的上限,超出缓存时add_log接口会立即返回失败 - // 默认为64 * 1024 * 1024 - setMaxBufferLimit(64 * 1024 * 1024) - // 发送线程数,默认为1 - setSendThreadCount(1) - - //网络连接超时时间,整数,单位秒,默认为10 - setConnectTimeoutSec(15) - //日志发送超时时间,整数,单位秒,默认为15 - setSendTimeoutSec(15) - //flusher线程销毁最大等待时间,整数,单位秒,默认为1 - setDestroyFlusherWaitSec(2) - //sender线程池销毁最大等待时间,整数,单位秒,默认为1 - setDestroySenderWaitSec(2) - //数据上传时的压缩类型,默认为LZ4压缩,0 不压缩,1 LZ4压缩,默认为1 - setCompressType(1) - //设备时间与标准时间之差,值为标准时间-设备时间,一般此种情况用于客户端设备时间不同步的场景 - //整数,单位秒,默认为0;比如当前设备时间为1607064208, 标准时间为1607064308,则值设置为 1607064308 - 1607064208 = 10 - setNtpTimeOffset(0) - //日志时间与本机时间之差,超过该大小后会根据 `drop_delay_log` 选项进行处理。 - //一般此种情况只会在设置persistent的情况下出现,即设备下线后,超过几天/数月启动,发送退出前未发出的日志 - //整数,单位秒,默认为7*24*3600,即7天 - setMaxLogDelayTime(7 * 24 * 3600) - //对于超过 `max_log_delay_time` 日志的处理策略 - //0 不丢弃,把日志时间修改为当前时间; 1 丢弃,默认为 1 (丢弃) - setDropDelayLog(0) - //是否丢弃鉴权失败的日志,0 不丢弃,1丢弃 - //默认为 0,即不丢弃 - setDropUnauthorizedLog(0) - // 是否使用主线程回调 - // false: 使用主线程回调。回调会在主线程上执行,且每个 client 都有自己单独的回调。 - // true: 使用 sender 线程回调。回调会在 sender 线程上执行,每次执行回调时都会 attach 一个新的 java 线程,所有 client 共用一个回调。 - // 注意:默认使用 sender 线程回调。 - setCallbackFromSenderThread(true) - - /** - * 以下为开启断点续传的配置, 按照如下配置开启断点续传功能后, 日志会先缓存到本地 - */ - // 1 开启断点续传功能, 0 关闭 - // 每次发送前会把日志保存到本地的binlog文件,只有发送成功才会删除,保证日志上传At Least Once - setPersistent(1) - // 持久化的文件名,需要保证文件所在的文件夹已创建。 - // !!!!!!!!!!!!!!!!!!!注意!!!!!!!!!!!!!!!!!!! - // 配置多个客户端时,不应设置相同文件 - setPersistentFilePath(HaloApp.getInstance().filesDir.absolutePath + "/${logStore}.dat") - // 是否每次AddLog强制刷新,高可靠性场景建议打开 - setPersistentForceFlush(1) - // 持久化文件滚动个数,建议设置成10。 - setPersistentMaxFileCount(10) - // 每个持久化文件的大小,建议设置成1-10M - setPersistentMaxFileSize(1024 * 1024) - // 本地最多缓存的日志数,不建议超过1M,通常设置为65536即可 - setPersistentMaxLogCount(65536) - } - - // 通过 LogProducerConfig 构造一个 LogProducerClient 实例 - // callback为可选配置, 如果不需要关注日志的发送成功或失败状态, 可以不注册 callback(正式环境不注册callback) - return if (!PackageFlavorHelper.IS_TEST_FLAVOR) { - LogProducerClient(config) - } else { - LogProducerClient(config) { resultCode, reqId, errorMessage, logBytes, compressedBytes -> - // resultCode 返回结果代码 - // reqId 请求id - // errorMessage 错误信息,没有为null - // logBytes 日志大小 - // compressedBytes 压缩后日志大小 - Utils.log( - "LoghubHelper -> ${ - String.format( - "%s %s %s %s %s", - LogProducerResult.fromInt(resultCode), - reqId, - errorMessage, - logBytes, - compressedBytes - ) - }" - ) - } - } - } -} +//package com.gh.gamecenter.common.loghub +// +//import com.aliyun.sls.android.producer.Log +//import com.aliyun.sls.android.producer.LogProducerClient +//import com.aliyun.sls.android.producer.LogProducerConfig +//import com.aliyun.sls.android.producer.LogProducerResult +//import com.gh.gamecenter.common.HaloApp +//import com.gh.gamecenter.common.utils.EnvHelper +//import com.gh.gamecenter.common.utils.PackageFlavorHelper +//import com.gh.gamecenter.core.AppExecutor +//import com.lightgame.utils.Utils +// +///** +// * 上传阿里云日志辅助类 +// */ +//object LoghubHelper { +// +// private const val ACCESS_KEY_ID = "LTAIV3i0sNc4TPK1" +// private const val ACCESS_KEY_SECRET = "8dKtTPeE5WYA6ZCeuIBcIVp7eB0ir4" +// private const val ENDPOINT = "cn-qingdao.log.aliyuncs.com" +// +// private val mClientMaps by lazy { hashMapOf() } +// +// /** +// * 上传日志至阿里云 loghub +// * @param uploadImmediately 马上上传日志 +// */ +// fun uploadLog(log: Log, logStore: String, uploadImmediately: Boolean) { +// // https://github.com/aliyun/aliyun-log-android-sdk/issues/60 +// // 在主线程直接调用会有概率触发 ANR ,在工作线程调用有机率会创建多个工作线程,麻了,还是继续在工作线程上干吧 +// AppExecutor.logExecutor.execute { +// getClient(logStore)?.addLog(log, if (uploadImmediately) 1 else 0) +// } +// } +// +// private fun getClient(logStore: String): LogProducerClient? { +// // https://jira.shanqu.cc/browse/GHZS-3815?focusedCommentId=50027&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-50027 +// // +// val transformedLogStore = if (EnvHelper.isGATApp) "event" else logStore +// if (!mClientMaps.containsKey(transformedLogStore)) { +// mClientMaps[transformedLogStore] = createClient(transformedLogStore) +// } +// return mClientMaps[transformedLogStore] +// } +// +// private fun createClient(logStore: String): LogProducerClient { +// +// val config = LogProducerConfig( +// HaloApp.getInstance().applicationContext, +// ENDPOINT, +// EnvHelper.logProducerProject, +// logStore, +// ACCESS_KEY_ID, +// ACCESS_KEY_SECRET +// ).apply { +//// // 设置主题 +//// setTopic("topic") +//// // 设置tag信息,此tag会附加在每条日志上 +//// addTag("key", "value") +// // 每个缓存的日志包的大小上限,取值为1~5242880,单位为字节。默认为1024 * 1024 +// setPacketLogBytes(1024 * 1024) +// // 每个缓存的日志包中包含日志数量的最大值,取值为1~4096,默认为1024 +// setPacketLogCount(1024) +// // 被缓存日志的发送超时时间,如果缓存超时,则会被立即发送,单位为毫秒,默认为3000 +// setPacketTimeout(3000) +// // 单个Producer Client实例可以使用的内存的上限,超出缓存时add_log接口会立即返回失败 +// // 默认为64 * 1024 * 1024 +// setMaxBufferLimit(64 * 1024 * 1024) +// // 发送线程数,默认为1 +// setSendThreadCount(1) +// +// //网络连接超时时间,整数,单位秒,默认为10 +// setConnectTimeoutSec(15) +// //日志发送超时时间,整数,单位秒,默认为15 +// setSendTimeoutSec(15) +// //flusher线程销毁最大等待时间,整数,单位秒,默认为1 +// setDestroyFlusherWaitSec(2) +// //sender线程池销毁最大等待时间,整数,单位秒,默认为1 +// setDestroySenderWaitSec(2) +// //数据上传时的压缩类型,默认为LZ4压缩,0 不压缩,1 LZ4压缩,默认为1 +// setCompressType(1) +// //设备时间与标准时间之差,值为标准时间-设备时间,一般此种情况用于客户端设备时间不同步的场景 +// //整数,单位秒,默认为0;比如当前设备时间为1607064208, 标准时间为1607064308,则值设置为 1607064308 - 1607064208 = 10 +// setNtpTimeOffset(0) +// //日志时间与本机时间之差,超过该大小后会根据 `drop_delay_log` 选项进行处理。 +// //一般此种情况只会在设置persistent的情况下出现,即设备下线后,超过几天/数月启动,发送退出前未发出的日志 +// //整数,单位秒,默认为7*24*3600,即7天 +// setMaxLogDelayTime(7 * 24 * 3600) +// //对于超过 `max_log_delay_time` 日志的处理策略 +// //0 不丢弃,把日志时间修改为当前时间; 1 丢弃,默认为 1 (丢弃) +// setDropDelayLog(0) +// //是否丢弃鉴权失败的日志,0 不丢弃,1丢弃 +// //默认为 0,即不丢弃 +// setDropUnauthorizedLog(0) +// // 是否使用主线程回调 +// // false: 使用主线程回调。回调会在主线程上执行,且每个 client 都有自己单独的回调。 +// // true: 使用 sender 线程回调。回调会在 sender 线程上执行,每次执行回调时都会 attach 一个新的 java 线程,所有 client 共用一个回调。 +// // 注意:默认使用 sender 线程回调。 +// setCallbackFromSenderThread(true) +// +// /** +// * 以下为开启断点续传的配置, 按照如下配置开启断点续传功能后, 日志会先缓存到本地 +// */ +// // 1 开启断点续传功能, 0 关闭 +// // 每次发送前会把日志保存到本地的binlog文件,只有发送成功才会删除,保证日志上传At Least Once +// setPersistent(1) +// // 持久化的文件名,需要保证文件所在的文件夹已创建。 +// // !!!!!!!!!!!!!!!!!!!注意!!!!!!!!!!!!!!!!!!! +// // 配置多个客户端时,不应设置相同文件 +// setPersistentFilePath(HaloApp.getInstance().filesDir.absolutePath + "/${logStore}.dat") +// // 是否每次AddLog强制刷新,高可靠性场景建议打开 +// setPersistentForceFlush(1) +// // 持久化文件滚动个数,建议设置成10。 +// setPersistentMaxFileCount(10) +// // 每个持久化文件的大小,建议设置成1-10M +// setPersistentMaxFileSize(1024 * 1024) +// // 本地最多缓存的日志数,不建议超过1M,通常设置为65536即可 +// setPersistentMaxLogCount(65536) +// } +// +// // 通过 LogProducerConfig 构造一个 LogProducerClient 实例 +// // callback为可选配置, 如果不需要关注日志的发送成功或失败状态, 可以不注册 callback(正式环境不注册callback) +// return if (!PackageFlavorHelper.IS_TEST_FLAVOR) { +// LogProducerClient(config) +// } else { +// LogProducerClient(config) { resultCode, reqId, errorMessage, logBytes, compressedBytes -> +// // resultCode 返回结果代码 +// // reqId 请求id +// // errorMessage 错误信息,没有为null +// // logBytes 日志大小 +// // compressedBytes 压缩后日志大小 +// Utils.log( +// "LoghubHelper -> ${ +// String.format( +// "%s %s %s %s %s", +// LogProducerResult.fromInt(resultCode), +// reqId, +// errorMessage, +// logBytes, +// compressedBytes +// ) +// }" +// ) +// } +// } +// } +//} diff --git a/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubUtils.kt b/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubUtils.kt index af1ef5e0b8..b8385b525d 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubUtils.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/loghub/LoghubUtils.kt @@ -1,11 +1,11 @@ package com.gh.gamecenter.common.loghub import androidx.annotation.Keep -import com.aliyun.sls.android.producer.Log import com.gh.gamecenter.common.entity.ExposureEntity import com.gh.gamecenter.common.exposure.meta.Meta import com.gh.gamecenter.core.runOnUiThread import com.google.gson.annotations.SerializedName +import com.volcengine.model.tls.LogItem import org.json.JSONObject object LoghubUtils { @@ -59,29 +59,29 @@ object LoghubUtils { private fun uploadEvents(eventList: List, forcedUpload: Boolean) { for (event in eventList) { - val log = Log() + val log = LogItem(System.currentTimeMillis()) // 特殊处理,以下logStore不需要用content包裹数据 if (event.logStore == "collection" || event.logStore == "common" || event.logStore == "halo-api-device-installed") { val contentJson = JSONObject(event.content) for (key in contentJson.keys()) { - log.putContent(key, contentJson.get(key).toString()) + log.addContent(key, contentJson.get(key).toString()) } } else { // isFlat为true代表仍需要平铺数据 if (event.isFlat) { val contentJson = JSONObject(event.content) for (key in contentJson.keys()) { - log.putContent(key, contentJson.get(key).toString()) + log.addContent(key, contentJson.get(key).toString()) } // 新数据使用timestamp字段记录时间 - log.putContent("timestamp", event.time) + log.addContent("timestamp", event.time) } else { - log.putContent("current time", event.time) - log.putContent("content", event.content) + log.addContent("current time", event.time) + log.addContent("content", event.content) } } - LoghubHelper.uploadLog(log, event.logStore, forcedUpload) + TLogHubHelper.sendLog(log, event.logStore) } } diff --git a/module_common/src/main/java/com/gh/gamecenter/common/loghub/TLogHubHelper.kt b/module_common/src/main/java/com/gh/gamecenter/common/loghub/TLogHubHelper.kt new file mode 100644 index 0000000000..2c2b87dc7b --- /dev/null +++ b/module_common/src/main/java/com/gh/gamecenter/common/loghub/TLogHubHelper.kt @@ -0,0 +1,58 @@ +package com.gh.gamecenter.common.loghub + +import com.lightgame.utils.Utils +import com.volcengine.model.tls.LogItem +import com.volcengine.model.tls.producer.CallBack +import com.volcengine.model.tls.producer.ProducerConfig +import com.volcengine.service.tls.Producer +import com.volcengine.service.tls.ProducerImpl + +object TLogHubHelper { + + private const val TAG = "TLogHubHelper" + + // 阿里云 logstore to 火山云 topicId 的 mapping + private val topicIdMapping = hashMapOf( + "appointment" to "2429e0ac-ee8b-4d2b-bab6-351d610f12df", + "bbs_community" to "6b3b32b9-6f04-4279-8117-a5f938ef7ebd", + "collection" to "77d6bd2b-c551-43d9-b36d-ae3d46b0fdbb", + "common" to "7fd7ef5e-bfa6-47e5-adc3-0bcb1f8d57bc", + "community" to "d8c296c9-ceb2-470f-8f3c-4c6e4e2f64d1", + "download_debug" to "a48acc1b-c863-459a-8681-99e25a63d19b", + "empty" to "30cf8475-81c0-42b7-8b81-19c9a731a644", + "event" to "ab6d32f5-e76f-4ebe-b484-2b456ffddfd8", + "exposure" to "3612f0f5-a5d4-4db8-91aa-8ec950107e7a", + "genshin" to "13d82937-45f2-4ee1-bd39-c17a63c570d5", + "halo-api-device-installed" to "c2a34712-8d43-4352-a3aa-7d3717b27a22", + "launch_activity" to "607dd48c-fbf9-44dc-8ebb-496bdea55447", + "score" to "af580973-ffef-4cd2-b010-f2589bc29201", + "video_streaming" to "d5efdf24-fa48-4e31-aeb6-8d961c6de51f", + ) + + private val producer: Producer by lazy { + ProducerImpl( + ProducerConfig( + "https://tls-cn-guangzhou.volces.com", + "cn-guangzhou", + "AKLTYmUwZTI0ZWM4Y2UwNDE5ZGEwYzM0YTcyMDFlZjI4NzE", + "TmpGa05EWTNOVGhpWkRSaU5EazVabUV4WmpVMVlUUTBOemswWkRGbE5qZw==", + "" + ).apply { + maxThreadCount = 5 + } + ).also { + it.start() + } + } + + fun sendLog(log: LogItem, logStore: String) { + // 如果不需要回调,callback参数传null即可 + val callBack = CallBack { result -> Utils.log(TAG, "sendLog result ${result.isSuccess}, " + "$logStore -> $log") } + val topicId = topicIdMapping[logStore] ?: return + + Utils.log(TAG, "sendLog, $logStore -> $topicId -> $log") + + producer.sendLogV2("", topicId, "android", "logFile", log, callBack) + } + +} \ No newline at end of file