こちらと同じことを行いました。
Androidアプリにログファイル出力機能を実装する方法
環境
AndroidManifest.xml
(省略)
<application
android:name=".LoggingApp"
(省略)
app/build.gradle.kts
(省略)
dependencies {
implementation("com.jakewharton.timber:timber:5.0.1")
(省略)
プログラム
MainActivity.kt
package org.ekzemplaro
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import timber.log.Timber
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Timber.d("*** onCreate ***")
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
Timber.d("*** onStart ***")
super.onStart()
}
override fun onResume() {
Timber.d("*** onResume ***")
super.onResume()
}
override fun onPause() {
Timber.d("*** onPause ***")
super.onPause()
}
override fun onStop() {
Timber.d("*** onStop ***")
super.onStop()
}
override fun onDestroy() {
Timber.d("*** onDestroy ***")
super.onDestroy()
}
}
LoggingApp.kt
package org.ekzemplaro
import android.app.Application
import android.content.Context
import timber.log.Timber
class LoggingApp: Application() {
override fun onCreate() {
super.onCreate()
Timber.plant(LogTree(context = this))
}
class LogTree(private val context: Context): Timber.DebugTree() {
// 以下については後のステップで説明します。
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
LogFile().postLog(context, message)
}
}
}
LogFile.kt
package org.ekzemplaro
import android.content.Context
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class LogFile {
companion object {
private val executor: ExecutorService = Executors.newSingleThreadExecutor()
const val LOG_EXPIRED_DAY = 13
}
fun postLog(context: Context, message: String) {
createLogLine(message).let {
executor.takeUnless { it.isShutdown }?.execute{
flush(context, it)
}
}
}
private fun createLogLine(
message: String,
date: LocalDateTime = LocalDateTime.now()
): String {
return "${date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"))} $message"
}
private fun flush(context: Context, log: String) {
val today = LocalDateTime.now()
val fileName =
"${today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))}.log"
val file = File(context.filesDir, fileName)
// まだ当日分のファイルが作成されていなかったら
// 14日前までに作成されたファイルを削除する
if (!file.exists()) deleteExpiredFiles(context)
BufferedWriter(FileWriter(file, true)).use { writer ->
writer.write(log)
writer.newLine()
writer.flush()
}
}
private fun deleteExpiredFiles(context: Context) {
context.filesDir
.listFiles()
?.toList()
?.filter { file -> file.name.endsWith(".log") }
?.let { fileList ->
fileList.map { file ->
if (expired(file) && file.exists()) file.delete()
}
}
}
private fun expired(file: File): Boolean {
return toLocalDate(file.lastModified())
.isBefore(LocalDate.now().minusDays(LOG_EXPIRED_DAY.toLong()))
}
private fun toLocalDate(lastModified: Long): LocalDate {
return Instant
.ofEpochMilli(lastModified)
.atZone(ZoneId.systemDefault())
.toLocalDate()
}
}
実行結果
確認方法
adb -s emulator-5554 shell
$ adb -s emulator-5554 shell
emu64xa:/ $ su
emu64xa:/ # cd data/data/org.ekzemplaro/files
emu64xa:/data/data/org.ekzemplaro/files # ls
2023-11-23.log profileInstalled
emu64xa:/data/data/org.ekzemplaro/files # cat 2023-11-23.log
作成されたファイル
2023-11-23.log
2023/11/23 17:15:57 *** onCreate ***
2023/11/23 17:15:57 *** onStart ***
2023/11/23 17:15:57 *** onResume ***
2023/11/23 17:16:31 *** onCreate ***
2023/11/23 17:16:32 *** onStart ***
2023/11/23 17:16:32 *** onResume ***
実機でテストした場合
実機を開発者モードにして、USBケーブルで接続します。
$ adb devices
List of devices attached
123456789A device
emulator-5554 device
$ adb -s 123456789A shell
rk322x_box:/ $ su
rk322x_box:/ # cd data/data/org.ekzemplaro/files
rk322x_box:/data/data/org.ekzemplaro/files # ls
2023-12-05.log