Feature/update log file rotation (#1023)

* Keep up to 31 log files

On average one log file per day gets created, thus, increasing to 31 files will store log files for one month

* Decrease total log files size to 100mb

* Make log appender settings configurable
This commit is contained in:
schroda
2024-09-01 00:55:26 +02:00
committed by GitHub
parent 9a74ae5844
commit 414972d545
6 changed files with 120 additions and 7 deletions

View File

@@ -19,9 +19,25 @@ import mu.KotlinLogging
import org.slf4j.Logger
import org.slf4j.LoggerFactory
private fun fileSizeValueOfOrDefault(
fileSizeStr: String,
default: String,
): FileSize {
return try {
FileSize.valueOf(fileSizeStr)
} catch (e: IllegalArgumentException) {
FileSize.valueOf(default)
}
}
private const val FILE_APPENDER_NAME = "SuwayomiDefaultAppender"
private fun createRollingFileAppender(
logContext: LoggerContext,
logDirPath: String,
maxFiles: Int,
maxFileSize: String,
maxTotalSize: String,
): RollingFileAppender<ILoggingEvent> {
val logFilename = "application"
@@ -34,7 +50,7 @@ private fun createRollingFileAppender(
val appender =
RollingFileAppender<ILoggingEvent>().apply {
name = "FILE"
name = FILE_APPENDER_NAME
context = logContext
encoder = logEncoder
file = "$logDirPath/$logFilename.log"
@@ -45,9 +61,9 @@ private fun createRollingFileAppender(
context = logContext
setParent(appender)
fileNamePattern = "$logDirPath/${logFilename}_%d{yyyy-MM-dd}_%i.log.gz"
setMaxFileSize(FileSize.valueOf("10mb"))
maxHistory = 14
setTotalSizeCap(FileSize.valueOf("1gb"))
maxHistory = maxFiles
setMaxFileSize(fileSizeValueOfOrDefault(maxFileSize, "10mb"))
setTotalSizeCap(fileSizeValueOfOrDefault(maxTotalSize, "100mb"))
start()
}
@@ -66,16 +82,44 @@ private fun getLogger(name: String): ch.qos.logback.classic.Logger {
return context.getLogger(name)
}
fun initLoggerConfig(appRootPath: String) {
fun initLoggerConfig(
appRootPath: String,
maxFiles: Int,
maxFileSize: String,
maxTotalSize: 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"))
logger.addAppender(createRollingFileAppender(context, "$appRootPath/logs", maxFiles, maxFileSize, maxTotalSize))
// set "kotlin exposed" log level
setLogLevelFor("Exposed", Level.ERROR)
}
fun updateFileAppender(
maxFiles: Int,
maxFileSize: String,
maxTotalSize: String,
) {
val logger = getBaseLogger()
val appender = logger.getAppender(FILE_APPENDER_NAME) as RollingFileAppender<*>? ?: return
val rollingPolicy = appender.rollingPolicy as SizeAndTimeBasedRollingPolicy<*>
rollingPolicy.apply {
maxHistory = maxFiles
setMaxFileSize(FileSize.valueOf(maxFileSize))
setTotalSizeCap(FileSize.valueOf(maxTotalSize))
rollingPolicy.stop()
appender.stop()
rollingPolicy.start()
appender.start()
}
}
const val BASE_LOGGER_NAME = "_BaseLogger"
fun setLogLevelFor(

View File

@@ -9,6 +9,24 @@ import suwayomi.tachidesk.server.ServerConfig
import suwayomi.tachidesk.server.serverConfig
import xyz.nulldev.ts.config.GlobalConfigManager
private fun validateString(
value: String?,
pattern: Regex,
name: String,
) {
validateString(value, pattern, Exception("Invalid format for \"$name\" [$value]"))
}
private fun validateString(
value: String?,
pattern: Regex,
exception: Exception,
) {
if (value != null && !value.matches(pattern)) {
throw exception
}
}
class SettingsMutation {
data class SetSettingsInput(
val clientMutationId: String? = null,
@@ -20,6 +38,13 @@ class SettingsMutation {
val settings: SettingsType,
)
private fun validateSettings(settings: Settings) {
// misc
val logbackSizePattern = "^[0-9]+(|kb|KB|mb|MB|gb|GB)\$".toRegex()
validateString(settings.maxLogFileSize, logbackSizePattern, "maxLogFileSize")
validateString(settings.maxLogFolderSize, logbackSizePattern, "maxLogFolderSize")
}
private fun <SettingType : Any> updateSetting(
newSetting: SettingType?,
configSetting: MutableStateFlow<SettingType>,
@@ -82,6 +107,9 @@ class SettingsMutation {
updateSetting(settings.debugLogsEnabled, serverConfig.debugLogsEnabled)
updateSetting(settings.gqlDebugLogsEnabled, serverConfig.gqlDebugLogsEnabled)
updateSetting(settings.systemTrayEnabled, serverConfig.systemTrayEnabled)
updateSetting(settings.maxLogFiles, serverConfig.maxLogFiles)
updateSetting(settings.maxLogFileSize, serverConfig.maxLogFileSize)
updateSetting(settings.maxLogFolderSize, serverConfig.maxLogFolderSize)
// backup
updateSetting(settings.backupPath, serverConfig.backupPath)
@@ -104,6 +132,7 @@ class SettingsMutation {
fun setSettings(input: SetSettingsInput): SetSettingsPayload {
val (clientMutationId, settings) = input
validateSettings(settings)
updateSettings(settings)
return SetSettingsPayload(clientMutationId, SettingsType())

View File

@@ -73,6 +73,9 @@ interface Settings : Node {
val debugLogsEnabled: Boolean?
val gqlDebugLogsEnabled: Boolean?
val systemTrayEnabled: Boolean?
val maxLogFiles: Int?
val maxLogFileSize: String?
val maxLogFolderSize: String?
// backup
val backupPath: String?
@@ -139,6 +142,9 @@ data class PartialSettingsType(
override val debugLogsEnabled: Boolean?,
override val gqlDebugLogsEnabled: Boolean?,
override val systemTrayEnabled: Boolean?,
override val maxLogFiles: Int?,
override val maxLogFileSize: String?,
override val maxLogFolderSize: String?,
// backup
override val backupPath: String?,
override val backupTime: String?,
@@ -202,6 +208,9 @@ class SettingsType(
override val debugLogsEnabled: Boolean,
override val gqlDebugLogsEnabled: Boolean,
override val systemTrayEnabled: Boolean,
override val maxLogFiles: Int,
override val maxLogFileSize: String,
override val maxLogFolderSize: String,
// backup
override val backupPath: String,
override val backupTime: String,
@@ -260,6 +269,9 @@ class SettingsType(
config.debugLogsEnabled.value,
config.gqlDebugLogsEnabled.value,
config.systemTrayEnabled.value,
config.maxLogFiles.value,
config.maxLogFileSize.value,
config.maxLogFolderSize.value,
// backup
config.backupPath.value,
config.backupTime.value,

View File

@@ -125,6 +125,9 @@ class ServerConfig(getConfig: () -> Config, val moduleName: String = SERVER_CONF
val debugLogsEnabled: MutableStateFlow<Boolean> by OverrideConfigValue(BooleanConfigAdapter)
val gqlDebugLogsEnabled: MutableStateFlow<Boolean> by OverrideConfigValue(BooleanConfigAdapter)
val systemTrayEnabled: MutableStateFlow<Boolean> by OverrideConfigValue(BooleanConfigAdapter)
val maxLogFiles: MutableStateFlow<Int> by OverrideConfigValue(IntConfigAdapter)
val maxLogFileSize: MutableStateFlow<String> by OverrideConfigValue(StringConfigAdapter)
val maxLogFolderSize: MutableStateFlow<String> by OverrideConfigValue(StringConfigAdapter)
// backup
val backupPath: MutableStateFlow<String> by OverrideConfigValue(StringConfigAdapter)

View File

@@ -45,6 +45,7 @@ import xyz.nulldev.ts.config.ConfigKodeinModule
import xyz.nulldev.ts.config.GlobalConfigManager
import xyz.nulldev.ts.config.initLoggerConfig
import xyz.nulldev.ts.config.setLogLevelFor
import xyz.nulldev.ts.config.updateFileAppender
import java.io.File
import java.net.Authenticator
import java.net.PasswordAuthentication
@@ -97,7 +98,28 @@ fun applicationSetup() {
// Application dirs
val applicationDirs = ApplicationDirs()
initLoggerConfig(applicationDirs.dataRoot)
initLoggerConfig(
applicationDirs.dataRoot,
serverConfig.maxLogFiles.value,
serverConfig.maxLogFileSize.value,
serverConfig.maxLogFolderSize.value,
)
serverConfig.subscribeTo(
combine(
serverConfig.maxLogFiles,
serverConfig.maxLogFileSize,
serverConfig.maxLogFolderSize,
) { maxLogFiles, maxLogFileSize, maxLogFolderSize ->
Triple(maxLogFiles, maxLogFileSize, maxLogFolderSize)
}.distinctUntilChanged(),
{ (maxLogFiles, maxLogFileSize, maxLogFolderSize) ->
logger.debug {
"updateFileAppender: maxLogFiles= $maxLogFiles, maxLogFileSize= $maxLogFileSize, maxLogFolderSize= $maxLogFolderSize"
}
updateFileAppender(maxLogFiles, maxLogFileSize, maxLogFolderSize)
},
)
setupLogLevelUpdating(serverConfig.debugLogsEnabled, listOf(BASE_LOGGER_NAME))
// gql "ExecutionStrategy" spams logs with "... completing field ..."

View File

@@ -51,6 +51,9 @@ server.basicAuthPassword = ""
server.debugLogsEnabled = false
server.gqlDebugLogsEnabled = false # this includes logs with non privacy safe information
server.systemTrayEnabled = true
server.maxLogFiles = 31 # the max number of days to keep files before they get deleted
server.maxLogFileSize = "10mb" # the max size of a log file - possible values: 1 (bytes), 1KB (kilobytes), 1MB (megabytes), 1GB (gigabytes)
server.maxLogFolderSize = "100mb" # the max size of all saved log files - possible values: 1 (bytes), 1KB (kilobytes), 1MB (megabytes), 1GB (gigabytes)
# backup
server.backupPath = ""