From 989a0cc1bea686de198a742a7913ea0375c66c29 Mon Sep 17 00:00:00 2001 From: pacien Date: Wed, 14 Mar 2018 17:19:00 +0100 Subject: Implement dual logging for application context --- .../main/java/org/pacien/tincapp/context/App.kt | 18 ++++++++- .../java/org/pacien/tincapp/context/AppLogger.kt | 45 ++++++++++++++++++++++ .../java/org/pacien/tincapp/context/AppPaths.kt | 24 ++++++------ 3 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/org/pacien/tincapp/context/AppLogger.kt (limited to 'app/src/main/java/org/pacien/tincapp/context') diff --git a/app/src/main/java/org/pacien/tincapp/context/App.kt b/app/src/main/java/org/pacien/tincapp/context/App.kt index d79ae3e..53049f3 100644 --- a/app/src/main/java/org/pacien/tincapp/context/App.kt +++ b/app/src/main/java/org/pacien/tincapp/context/App.kt @@ -9,15 +9,31 @@ import android.support.annotation.StringRes import android.support.v7.app.AlertDialog import android.view.WindowManager import org.pacien.tincapp.R +import org.slf4j.Logger +import org.slf4j.LoggerFactory /** * @author pacien */ -class App : Application() { +class App : Application(), Thread.UncaughtExceptionHandler { + private var logger: Logger? = null + private var systemCrashHandler: Thread.UncaughtExceptionHandler? = null + override fun onCreate() { super.onCreate() appContext = applicationContext handler = Handler() + + AppLogger.configure() + logger = LoggerFactory.getLogger(this.javaClass) + + systemCrashHandler = Thread.getDefaultUncaughtExceptionHandler() + Thread.setDefaultUncaughtExceptionHandler(this) + } + + override fun uncaughtException(thread: Thread, throwable: Throwable) { + logger?.error("Fatal application error.", throwable) + systemCrashHandler?.uncaughtException(thread, throwable) } companion object { diff --git a/app/src/main/java/org/pacien/tincapp/context/AppLogger.kt b/app/src/main/java/org/pacien/tincapp/context/AppLogger.kt new file mode 100644 index 0000000..e240e70 --- /dev/null +++ b/app/src/main/java/org/pacien/tincapp/context/AppLogger.kt @@ -0,0 +1,45 @@ +package org.pacien.tincapp.context + +import ch.qos.logback.classic.Logger +import ch.qos.logback.classic.LoggerContext +import ch.qos.logback.classic.android.LogcatAppender +import ch.qos.logback.classic.encoder.PatternLayoutEncoder +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.Context +import ch.qos.logback.core.FileAppender +import org.slf4j.LoggerFactory + +/** + * @author pacien + */ +object AppLogger { + private const val LOGCAT_PATTERN = "[%thread] %msg%n%rEx" + private const val LOGFILE_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%rEx" + + fun configure() { + (LoggerFactory.getILoggerFactory() as LoggerContext) + .apply { reset() } + .let { loggerContext -> + (LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as Logger) + .apply { + addAppender(LogcatAppender() + .apply { context = loggerContext } + .apply { encoder = patternEncoder(loggerContext, LOGCAT_PATTERN) } + .apply { start() }) + } + .apply { + addAppender(FileAppender() + .apply { context = loggerContext } + .apply { encoder = patternEncoder(loggerContext, LOGFILE_PATTERN) } + .apply { file = AppPaths.appLogFile().absolutePath } + .apply { start() }) + } + } + } + + private fun patternEncoder(ctx: Context, pat: String) = + PatternLayoutEncoder() + .apply { context = ctx } + .apply { pattern = pat } + .apply { start() } +} diff --git a/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt b/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt index 9315060..4b36dfe 100644 --- a/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt +++ b/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt @@ -10,21 +10,22 @@ import java.io.FileNotFoundException * @implNote Logs and PID files are stored in the cache directory for easy clean up. */ object AppPaths { - private val TINCD_BIN = "libtincd.so" - private val TINC_BIN = "libtinc.so" + private const val TINCD_BIN = "libtincd.so" + private const val TINC_BIN = "libtinc.so" - private val LOGFILE_FORMAT = "tinc.%s.log" - private val PIDFILE_FORMAT = "tinc.%s.pid" + private const val APPLOG_FILE = "tincapp.log" + private const val LOGFILE_FORMAT = "tinc.%s.log" + private const val PIDFILE_FORMAT = "tinc.%s.pid" - private val NET_CONF_FILE = "network.conf" - private val NET_TINC_CONF_FILE = "tinc.conf" - private val NET_HOSTS_DIR = "hosts" - private val NET_INVITATION_FILE = "invitation-data" - private val NET_DEFAULT_ED25519_PRIVATE_KEY_FILE = "ed25519_key.priv" - private val NET_DEFAULT_RSA_PRIVATE_KEY_FILE = "rsa_key.priv" + private const val NET_CONF_FILE = "network.conf" + private const val NET_TINC_CONF_FILE = "tinc.conf" + private const val NET_HOSTS_DIR = "hosts" + private const val NET_INVITATION_FILE = "invitation-data" + private const val NET_DEFAULT_ED25519_PRIVATE_KEY_FILE = "ed25519_key.priv" + private const val NET_DEFAULT_RSA_PRIVATE_KEY_FILE = "rsa_key.priv" fun storageAvailable() = - Environment.getExternalStorageState().let { it == Environment.MEDIA_MOUNTED && it != Environment.MEDIA_MOUNTED_READ_ONLY } + Environment.getExternalStorageState().let { it == Environment.MEDIA_MOUNTED && it != Environment.MEDIA_MOUNTED_READ_ONLY } fun cacheDir() = App.getContext().externalCacheDir fun confDir() = App.getContext().getExternalFilesDir(null) @@ -37,6 +38,7 @@ object AppPaths { fun invitationFile(netName: String) = File(confDir(netName), NET_INVITATION_FILE) fun logFile(netName: String) = File(cacheDir(), String.format(LOGFILE_FORMAT, netName)) fun pidFile(netName: String) = File(App.getContext().cacheDir, String.format(PIDFILE_FORMAT, netName)) + fun appLogFile() = File(cacheDir(), APPLOG_FILE) fun existing(f: File) = f.apply { if (!exists()) throw FileNotFoundException(f.absolutePath) } -- cgit v1.2.3