[6.0.0][全量日志] 全量日志添加上传逻辑

This commit is contained in:
renwj
2023-08-22 15:54:36 +08:00
committed by zhongchao
parent e93eec8f9b
commit 04bdd9c3de
5 changed files with 275 additions and 20 deletions

View File

@@ -0,0 +1,94 @@
package com.mogo.functions.test
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
import com.mogo.eagle.core.function.main.MainLauncherActivity
import com.mogo.eagle.core.utilcode.kotlin.onClick
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.TimeUnit
@RunWith(AndroidJUnit4::class)
@LargeTest
class CrashTest {
lateinit var launch: ActivityScenario<MainLauncherActivity>
@Before
fun before() {
launch = ActivityScenario.launch(MainLauncherActivity::class.java)
}
@Test
fun testJavaCrash() = runBlocking {
val arguments = InstrumentationRegistry.getArguments()
val delay = arguments.getString("delay", "0")
val newThread = arguments.getString("new_thread", "false")
val delayLong = delay.toLong()
if (delayLong <= 0) {
throw AssertionError("illegal state ..")
}
delay(delayLong)
launch.onActivity {
CallerDevaToolsManager.logcat()?.testJavaCrash(newThread.toBoolean())
}
delay(TimeUnit.MINUTES.toMillis(10))
}
@Test
fun testANRCrash() = runBlocking {
val arguments = InstrumentationRegistry.getArguments()
val delay = arguments.getString("delay", "0")
val delayLong = delay.toLong()
if (delayLong <= 0) {
throw AssertionError("illegal state ..")
}
delay(delayLong)
launch.onActivity { itx ->
val content = (itx.findViewById<View>(android.R.id.content) as ViewGroup)
content.postDelayed({
content.addView(Button(itx).also {
it.background = ColorDrawable(Color.RED)
it.setPadding(20, 20, 20, 20)
it.textSize = 40.0f
it.text = "点我触发ANR"
it.setTextColor(Color.WHITE)
it.onClick {
CallerDevaToolsManager.logcat()?.testAnrCrash()
}
})
}, 1000)
}
delay(TimeUnit.MINUTES.toMillis(10))
}
@Test
fun testNativeCrash() = runBlocking {
val arguments = InstrumentationRegistry.getArguments()
val delay = arguments.getString("delay", "0")
val newThread = arguments.getString("new_thread", "false")
val delayLong = delay.toLong()
if (delayLong <= 0) {
throw AssertionError("illegal state ..")
}
delay(delayLong)
launch.onActivity {
CallerDevaToolsManager.logcat()?.testNativeCrash(newThread.toBoolean())
}
delay(TimeUnit.MINUTES.toMillis(10))
}
}

View File

@@ -2,24 +2,39 @@ package com.zhjt.mogo_core_function_devatools.logcat
import android.content.*
import android.os.Process
import android.util.*
import android.os.SystemClock
import android.util.Log
import com.mogo.aicloud.services.socket.IMogoOnMessageListener
import com.mogo.aicloud.services.socket.MogoAiCloudSocketManager
import com.mogo.commons.AbsMogoApplication
import com.mogo.core.log.record.*
import com.mogo.core.log.record.config.*
import com.mogo.core.log.record.config.crash.*
import com.mogo.eagle.core.function.api.devatools.logcat.*
import com.mogo.eagle.core.utilcode.util.*
import com.zhidao.loglib.bean.RemoteLogPushContent
import com.zhjt.mogo_core_function_devatools.logcat.config.LogRecordConfig
import com.zhjt.mogo_core_function_devatools.logcat.uploader.*
import kotlinx.coroutines.*
import java.io.*
import java.util.concurrent.TimeUnit.MINUTES
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong
internal class MoGoLogRecordProviderImpl: IMoGoLogRecordProvider {
internal class MoGoLogRecordProviderImpl: IMoGoLogRecordProvider,
IMogoOnMessageListener<RemoteLogPushContent> {
companion object {
private const val TAG = "MoGoLogRecordProviderImpl"
}
private val flag by lazy { AtomicBoolean(false) }
private val scope by lazy { CoroutineScope(Dispatchers.IO + SupervisorJob()) }
private val uploadThreshold by lazy { MINUTES.toMillis(1) } //全量日志的上传的安全时间,在此时间内,上传任务只会触发一次
private val lastUploadTime by lazy { AtomicLong(0) }
override fun init(context: Context) {
val zipDir = File(context.getExternalFilesDir(null), "logcat/zip")
LogcatManager.init(LogcatConfig.Builder().context(context)
@@ -33,27 +48,60 @@ internal class MoGoLogRecordProviderImpl: IMoGoLogRecordProvider {
.crashDir(File(context.getExternalFilesDir(null), "logcat/crash"))
.javaCrash(true)
.anr(true)
.nativeCrash(true)
.build())
.uploader(LogRecordUploader()))
scope.launch {
try {
if (zipDir.exists()) {
zipDir.listFiles()?.forEach {
it.delete()
}
}
zipDir.takeIf { it.exists() }?.deleteRecursively()
} catch (t: Throwable) {
t.printStackTrace()
}
}
}
override fun target(): Class<RemoteLogPushContent> {
return RemoteLogPushContent::class.java
}
override fun onMsgReceived(obj: RemoteLogPushContent?) {
Log.d(TAG, "--- onMsgReceived --: $obj")
if (obj == null) return
val endTime = System.currentTimeMillis()
val startTime = when(obj.type) {
LogRecordConfig.ALL_LOG_15_MINUTES -> endTime - MINUTES.toMillis(15)
LogRecordConfig.ALL_LOG_30_MINUTES -> endTime - MINUTES.toMillis(30)
LogRecordConfig.ALL_LOG_45_MINUTES -> endTime - MINUTES.toMillis(45)
LogRecordConfig.ALL_LOG_60_MINUTES -> endTime - MINUTES.toMillis(60)
LogRecordConfig.ALL_LOG_120_MINUTES -> endTime - MINUTES.toMillis(120)
LogRecordConfig.ALL_LOG_SAME_DAY -> endTime - (endTime % 86400000)
LogRecordConfig.ALL_LOG -> 0
else -> endTime
}
Log.d(TAG, "--- onMsgReceived -- 1: $startTime, $endTime")
if (startTime < endTime) {
val now = System.currentTimeMillis()
val last = lastUploadTime.get()
if (last <= 0) {
lastUploadTime.set(System.currentTimeMillis())
}
if (last > 0 && (now - last) <= uploadThreshold) {
return
}
lastUploadTime.set(System.currentTimeMillis())
scope.launch {
LogcatManager.upload(startTime, endTime)
}
}
}
override fun start() {
if (flag.get()) {
return
}
flag.set(true)
MogoAiCloudSocketManager.getInstance(AbsMogoApplication.getApp().applicationContext)
.registerOnMessageListener(LogRecordConfig.LOG_RECORD_TYPE, this)
LogcatManager.start()
}
@@ -61,18 +109,25 @@ internal class MoGoLogRecordProviderImpl: IMoGoLogRecordProvider {
if (!flag.get()) {
return
}
MogoAiCloudSocketManager.getInstance(AbsMogoApplication.getApp().applicationContext)
.unregisterOnMessageListener(LogRecordConfig.LOG_RECORD_TYPE, this)
flag.set(false)
LogcatManager.stop()
}
override fun upload(startTime: Long, endTime: Long) {
scope.launch {
val result = LogcatManager.upload(startTime, endTime)
Log.d(TAG, "上传日志:[startTime:$startTime, endTime: $endTime], 结果: $result")
}
}
override fun export(): File? {
return LogcatManager.export()
}
override fun testJavaCrash(runOnNewThread: Boolean) {
LogcatManager.testJavaCrash(runOnNewThread)
}
override fun testNativeCrash(runOnNewThread: Boolean) {
LogcatManager.testNativeCrash(runOnNewThread)
}
override fun testAnrCrash() {
SystemClock.sleep(15000)
}
}

View File

@@ -0,0 +1,48 @@
package com.zhjt.mogo_core_function_devatools.logcat.config
internal class LogRecordConfig {
companion object{
/**
* 长链下行数据的消息类型
*/
const val LOG_RECORD_TYPE = 500002
/**
* 全量日志抓取: 上传从收到抓取指令往前15分钟的日志
*/
const val ALL_LOG_15_MINUTES = 1
/**
* 全量日志抓取: 上传从收到抓取指令往前30分钟的日志
*/
const val ALL_LOG_30_MINUTES = 2
/**
* 全量日志抓取: 上传从收到抓取指令往前45分钟的日志
*/
const val ALL_LOG_45_MINUTES = 3
/**
* 全量日志抓取: 上传从收到抓取指令往前60分钟的日志
*/
const val ALL_LOG_60_MINUTES = 4
/**
* 全量日志抓取: 上传从收到抓取指令往前120分钟的日志
*/
const val ALL_LOG_120_MINUTES = 5
/**
* 全量日志抓取: 上传从收到抓取指令往前当天的日志
*/
const val ALL_LOG_SAME_DAY = 6
/**
* 全量日志抓取: 上传从收到抓取指令之前所有的日志
*/
const val ALL_LOG = 7
}
}

View File

@@ -1,11 +1,65 @@
package com.zhjt.mogo_core_function_devatools.logcat.uploader
import android.util.Log
import com.mogo.core.log.record.config.uploader.*
import com.mogo.core.log.record.model.*
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.zhidao.cosupload.callback.CosStatusCallback
import com.zhidao.cosupload.callback.CosStatusCallbackManager
import com.zhidao.cosupload.model.CallbackData
import com.zhidao.loglib.upload.UploadManager
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flowOn
internal class LogRecordUploader: ILogcatUploader {
internal class LogRecordUploader : ILogcatUploader {
override suspend fun upload(startTime: Long, endTime: Long, generatedZipPath: String): UploadState {
throw AssertionError("Not Implementation")
companion object {
private const val TAG = "LogRecordUploader"
}
@OptIn(ExperimentalCoroutinesApi::class)
override suspend fun upload(startTime: Long, endTime: Long, generatedZipPath: String): UploadState =
channelFlow {
Log.d(TAG, "---- 开始上传 --- 1 ---")
CosStatusCallbackManager.getInstance().register(object : CosStatusCallback {
override fun onStartUpload(data: CallbackData?) {
if (data?.localPath == generatedZipPath) {
Log.d(TAG, "---- onStartUpload ---: $data")
}
}
override fun uploadCosCompleted(data: CallbackData?) {
if (data?.localPath == generatedZipPath) {
Log.d(TAG, "---- uploadCosCompleted ---: $data")
trySend(UploadSuccess)
CosStatusCallbackManager.getInstance().unregister(this)
}
}
override fun uploadCosFailed(data: CallbackData?) {
if (data?.localPath == generatedZipPath) {
Log.d(TAG, "---- uploadCosFailed ---: $data")
trySend(UploadError(Reason(data.exception)))
CosStatusCallbackManager.getInstance().unregister(this)
}
}
override fun onProgress(data: CallbackData?) {
if (data?.localPath == generatedZipPath) {
Log.d(TAG, "---- onProgress ---: $data")
}
}
})
try {
UploadManager.getInstance().uploadSingleFile(generatedZipPath)
} catch (t: Throwable) {
Log.d(TAG, "---- 上传失败 ---: ${t.message}")
trySend(UploadError(Reason(t.message ?: "")))
}
}.flowOn(ThreadUtils.getIoPool().asCoroutineDispatcher()).firstOrNull() ?: UploadError(Reason("UnKnown reason"))
}

View File

@@ -11,7 +11,11 @@ interface IMoGoLogRecordProvider {
fun stop()
fun upload(startTime: Long, endTime: Long)
fun export(): File?
fun testJavaCrash(runOnNewThread: Boolean)
fun testNativeCrash(runOnNewThread: Boolean)
fun testAnrCrash()
}