From d4f9b0b1bc044d13dea0b80d638890dc2460a8c0 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 22 Jul 2023 01:53:41 +0200 Subject: [PATCH] Feature/log to file (#607) * Setup "logback" to write to file To be able to dynamically set the log file save location, logback has to be setup via code instead of a config file * Log OkHttp via logback Otherwise, the logs would only get written to the console and thus, not be included in the log file * Init logback Has to be done after the config was loaded, otherwise, the root directory would be unknown. Moved the log of the loaded config to the "applicationSetup" since otherwise, the log would not be included in the log file --- .../xyz/nulldev/ts/config/ConfigManager.kt | 5 -- .../java/xyz/nulldev/ts/config/Logging.kt | 55 ++++++++++++++++++- .../kanade/tachiyomi/network/NetworkHelper.kt | 9 ++- .../suwayomi/tachidesk/server/ServerSetup.kt | 12 +++- server/src/main/resources/logback.xml | 16 ------ 5 files changed, 72 insertions(+), 25 deletions(-) delete mode 100644 server/src/main/resources/logback.xml diff --git a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt b/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt index 61a0bf4e..2aeb83d8 100644 --- a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt +++ b/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/ConfigManager.kt @@ -10,7 +10,6 @@ package xyz.nulldev.ts.config import ch.qos.logback.classic.Level import com.typesafe.config.Config import com.typesafe.config.ConfigFactory -import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigValue import com.typesafe.config.ConfigValueFactory import com.typesafe.config.parser.ConfigDocument @@ -79,10 +78,6 @@ open class ConfigManager { setLogLevel(Level.DEBUG) } - logger.debug { - "Loaded config:\n" + config.root().render(ConfigRenderOptions.concise().setFormatted(true)) - } - return config } diff --git a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/Logging.kt b/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/Logging.kt index 68788252..19bfc6ba 100644 --- a/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/Logging.kt +++ b/AndroidCompat/Config/src/main/java/xyz/nulldev/ts/config/Logging.kt @@ -8,12 +8,65 @@ package xyz.nulldev.ts.config * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import ch.qos.logback.classic.Level +import ch.qos.logback.classic.LoggerContext +import ch.qos.logback.classic.encoder.PatternLayoutEncoder +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.rolling.RollingFileAppender +import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy +import ch.qos.logback.core.util.FileSize import com.typesafe.config.Config import mu.KotlinLogging import org.slf4j.Logger +import org.slf4j.LoggerFactory + +private fun createRollingFileAppender(logContext: LoggerContext, logDirPath: String): RollingFileAppender { + val logFilename = "application" + + val logEncoder = PatternLayoutEncoder().apply { + pattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n" + context = logContext + start() + } + + val appender = RollingFileAppender().apply { + name = "FILE" + context = logContext + encoder = logEncoder + file = "$logDirPath/$logFilename.log" + } + + val rollingPolicy = SizeAndTimeBasedRollingPolicy().apply { + context = logContext + setParent(appender) + fileNamePattern = "$logDirPath/${logFilename}_%d{yyyy-MM-dd}_%i.log.gz" + setMaxFileSize(FileSize.valueOf("10mb")) + maxHistory = 14 + setTotalSizeCap(FileSize.valueOf("1gb")) + start() + } + + appender.rollingPolicy = rollingPolicy + appender.start() + + return appender +} + +private fun getBaseLogger(): ch.qos.logback.classic.Logger { + return (KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger) +} + +fun initLoggerConfig(appRootPath: String) { + val context = LoggerFactory.getILoggerFactory() as LoggerContext + val logger = getBaseLogger() + // logback logs to the console by default (at least when adding a console appender logs in the console are duplicated) + logger.addAppender(createRollingFileAppender(context, "$appRootPath/logs")) + + // set "kotlin exposed" log level + context.getLogger("Exposed").level = Level.ERROR +} fun setLogLevel(level: Level) { - (KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger).level = level + getBaseLogger().level = level } fun debugLogsEnabled(config: Config) = diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt index a63a25ce..97ce5ce6 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -17,6 +17,7 @@ package eu.kanade.tachiyomi.network import android.content.Context import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor +import mu.KotlinLogging import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import suwayomi.tachidesk.server.serverConfig @@ -43,7 +44,13 @@ class NetworkHelper(context: Context) { .addInterceptor(UserAgentInterceptor()) if (serverConfig.debugLogsEnabled) { - val httpLoggingInterceptor = HttpLoggingInterceptor().apply { + val httpLoggingInterceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger { + val logger = KotlinLogging.logger { } + + override fun log(message: String) { + logger.debug { message } + } + }).apply { level = HttpLoggingInterceptor.Level.BASIC } builder.addInterceptor(httpLoggingInterceptor) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt index d8b263d4..a9b89c17 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt @@ -7,6 +7,7 @@ package suwayomi.tachidesk.server * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import com.typesafe.config.ConfigRenderOptions import eu.kanade.tachiyomi.App import eu.kanade.tachiyomi.source.local.LocalSource import io.javalin.plugin.json.JavalinJackson @@ -30,6 +31,7 @@ import xyz.nulldev.androidcompat.AndroidCompatInitializer import xyz.nulldev.ts.config.ApplicationRootDir import xyz.nulldev.ts.config.ConfigKodeinModule import xyz.nulldev.ts.config.GlobalConfigManager +import xyz.nulldev.ts.config.initLoggerConfig import java.io.File import java.security.Security import java.util.Locale @@ -58,8 +60,6 @@ val systemTrayInstance by lazy { systemTray() } val androidCompat by lazy { AndroidCompat() } fun applicationSetup() { - logger.info("Running Tachidesk ${BuildConfig.VERSION} revision ${BuildConfig.REVISION}") - // register Tachidesk's config which is dubbed "ServerConfig" GlobalConfigManager.registerModule( ServerConfig.register { GlobalConfigManager.config } @@ -68,6 +68,14 @@ fun applicationSetup() { // Application dirs val applicationDirs = ApplicationDirs() + initLoggerConfig(applicationDirs.dataRoot) + + logger.info("Running Tachidesk ${BuildConfig.VERSION} revision ${BuildConfig.REVISION}") + + logger.debug { + "Loaded config:\n" + GlobalConfigManager.config.root().render(ConfigRenderOptions.concise().setFormatted(true)) + } + val updater = Updater() DI.global.addImport( diff --git a/server/src/main/resources/logback.xml b/server/src/main/resources/logback.xml deleted file mode 100644 index 1d27933d..00000000 --- a/server/src/main/resources/logback.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - %d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %logger - %msg%n - - - - - - - - - \ No newline at end of file