Add seperate root log level config property

Adjust logging behaviour of Gameyfin
This commit is contained in:
grimsi
2025-05-11 13:57:03 +02:00
parent ee9af0533f
commit 180242fdf3
14 changed files with 58 additions and 45 deletions
@@ -46,7 +46,8 @@ function LogManagementLayout({getConfig, formik}: any) {
<div className="flex flex-row gap-4">
<ConfigFormField configElement={getConfig("logs.folder")}/>
<ConfigFormField configElement={getConfig("logs.max-history-days")}/>
<ConfigFormField configElement={getConfig("logs.level")}/>
<ConfigFormField configElement={getConfig("logs.level.gameyfin")}/>
<ConfigFormField configElement={getConfig("logs.level.root")}/>
</div>
<div className="flex flex-col">
@@ -86,7 +87,10 @@ const validationSchema = Yup.object({
logs: Yup.object({
folder: Yup.string().required("Required"),
"max-history-days": Yup.number().required("Required"),
level: Yup.string().required("Required")
level: Yup.object({
gameyfin: Yup.string().required("Required"),
root: Yup.string().required("Required")
})
})
});
@@ -224,13 +224,23 @@ sealed class ConfigProperties<T : Serializable>(
30
)
data object Level : ConfigProperties<LogLevel>(
LogLevel::class,
"logs.level",
"Log level",
LogLevel.INFO,
LogLevel.entries
)
sealed class Level {
data object Gameyfin : ConfigProperties<LogLevel>(
LogLevel::class,
"logs.level.gameyfin",
"Log level (Gameyfin)",
LogLevel.INFO,
LogLevel.entries
)
data object Root : ConfigProperties<LogLevel>(
LogLevel::class,
"logs.level.root",
"Log level (Root)",
LogLevel.INFO,
LogLevel.entries
)
}
}
}
@@ -58,7 +58,7 @@ class ConfigService(
*/
fun getAll(prefix: String?): List<ConfigEntryDto> {
log.info { "Getting all config values for prefix '$prefix'" }
log.debug { "Getting all config values for prefix '$prefix'" }
var configProperties = ConfigProperties::class.sealedSubclasses.flatMap { subclass ->
subclass.objectInstance?.let { listOf(it) } ?: listOf()
@@ -91,7 +91,7 @@ class ConfigService(
*/
@Suppress("UNCHECKED_CAST")
fun <T : Serializable> set(key: String, value: T) {
log.info { "Set config value '$key'" }
log.debug { "Set config value '$key'" }
val configProperty = findConfigProperty(key)
@@ -143,7 +143,7 @@ class ConfigService(
*/
fun deleteConfig(key: String) {
log.info { "Delete config value '$key'" }
log.debug { "Delete config value '$key'" }
val configKey = findConfigProperty(key)
appConfigRepository.deleteById(configKey.key)
@@ -1,4 +1,4 @@
package de.grimsi.gameyfin.logs
package de.grimsi.gameyfin.core.logging
import com.vaadin.flow.server.auth.AnonymousAllowed
import com.vaadin.hilla.Endpoint
@@ -1,10 +1,10 @@
package de.grimsi.gameyfin.logs
package de.grimsi.gameyfin.core.logging
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.joran.JoranConfigurator
import de.grimsi.gameyfin.config.ConfigProperties
import de.grimsi.gameyfin.config.ConfigService
import de.grimsi.gameyfin.logs.util.AsyncFileTailer
import de.grimsi.gameyfin.core.logging.util.AsyncFileTailer
import io.github.oshai.kotlinlogging.KotlinLogging
import org.slf4j.LoggerFactory
import org.springframework.boot.context.event.ApplicationStartedEvent
@@ -41,18 +41,20 @@ class LogService(
return configureFileLogging(
config.get(ConfigProperties.Logs.Folder)!!,
config.get(ConfigProperties.Logs.MaxHistoryDays)!!,
config.get(ConfigProperties.Logs.Level)!!
config.get(ConfigProperties.Logs.Level.Gameyfin)!!,
config.get(ConfigProperties.Logs.Level.Root)!!
)
}
fun configureFileLogging(folder: String, maxHistoryDays: Int, level: LogLevel) {
fun configureFileLogging(folder: String, maxHistoryDays: Int, levelGameyfin: LogLevel, levelRoot: LogLevel) {
val context = LoggerFactory.getILoggerFactory() as LoggerContext
val configurator = JoranConfigurator()
configurator.context = context
context.reset()
generateLogConfigXml(folder.removeSuffix("/"), maxHistoryDays, level).use {
log.info { "Setting log level to $level" }
generateLogConfigXml(folder.removeSuffix("/"), maxHistoryDays, levelGameyfin, levelRoot).use {
log.info { "Setting log level for Gameyfin to $levelGameyfin" }
log.info { "Setting log level for Root to $levelRoot" }
log.info { "Setting log retention to $maxHistoryDays days" }
configurator.doConfigure(it)
@@ -74,7 +76,8 @@ class LogService(
private fun generateLogConfigXml(
folder: String,
maxHistoryDays: Int,
level: LogLevel
levelGameyfin: LogLevel,
levelRoot: LogLevel
): InputStream {
val template = javaClass.classLoader.getResourceAsStream(LOG_CONFIG_TEMPLATE)
?: throw IllegalStateException("Log config template not found")
@@ -84,7 +87,8 @@ class LogService(
.replace("{LOG_FOLDER}", folder)
.replace("{LOG_FILE_NAME}", LOG_FILE_NAME)
.replace("{LOG_MAX_HISTORY_DAYS}", maxHistoryDays.toString())
.replace("{LOG_LEVEL}", level.toString())
.replace("{LOG_LEVEL_GAMEYFIN}", levelGameyfin.toString())
.replace("{LOG_LEVEL_ROOT}", levelRoot.toString())
.byteInputStream()
}
}
@@ -1,4 +1,4 @@
package de.grimsi.gameyfin.logs.dto
package de.grimsi.gameyfin.core.logging.dto
import org.springframework.boot.logging.LogLevel
@@ -1,4 +1,4 @@
package de.grimsi.gameyfin.logs.util
package de.grimsi.gameyfin.core.logging.util
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.coroutines.CoroutineScope
@@ -15,7 +15,7 @@ class PluginConfigService(
private val log = KotlinLogging.logger {}
fun getConfigMetadata(pluginId: String): List<PluginConfigElement> {
log.info { "Getting config metadata for plugin $pluginId" }
log.debug { "Getting config metadata for plugin $pluginId" }
val plugin = try {
pluginManager.getPlugin(pluginId).plugin
@@ -29,19 +29,19 @@ class PluginConfigService(
}
fun getConfig(pluginId: String): Map<String, String?> {
log.info { "Getting config for plugin $pluginId" }
log.debug { "Getting config for plugin $pluginId" }
return pluginConfigRepository.findAllById_PluginId(pluginId).associate { it.id.key to it.value }
}
fun setConfigEntries(pluginId: String, config: Map<String, String>) {
log.info { "Setting config entries for plugin $pluginId" }
log.debug { "Setting config entries for plugin $pluginId" }
val entries = config.map { PluginConfigEntry(PluginConfigEntryKey(pluginId, it.key), it.value) }
pluginConfigRepository.saveAll(entries)
pluginManager.restart(pluginId)
}
fun setConfigEntry(pluginId: String, key: String, value: String) {
log.info { "Setting config entry $key for plugin $pluginId" }
log.debug { "Setting config entry $key for plugin $pluginId" }
val entry = PluginConfigEntry(PluginConfigEntryKey(pluginId, key), value)
pluginConfigRepository.save(entry)
pluginManager.restart(pluginId)
@@ -149,7 +149,7 @@ class GameService(
val bestMatchingTitle = FuzzySearch.extractOne(originalQuery, providerToTitle.values).string
log.info {
log.debug {
"Best matching title: '$bestMatchingTitle' (${
providerToTitle.count { it.value.fuzzyMatchTitle(bestMatchingTitle) }
}/${providerToTitle.size} matches) for '$originalQuery' determined from $providerToTitle"
@@ -186,7 +186,7 @@ class LibraryService(
}
val progress = completedMetadata.incrementAndGet()
log.info { "${progress}/${totalPaths} metadata matched" }
log.debug { "${progress}/${totalPaths} metadata matched" }
return@Callable game
} catch (e: Exception) {
@@ -225,7 +225,7 @@ class LibraryService(
completedImageDownload.andIncrement
}
log.info { "${completedImageDownload}/${totalImages} images downloaded" }
log.debug { "${completedImageDownload}/${totalImages} images downloaded" }
game
} catch (e: Exception) {
@@ -239,7 +239,7 @@ class LibraryService(
// 3. Persist new games
val persistedGames = gameService.create(gamesWithImages)
log.info { "${persistedGames.size}/${totalPaths} saved to database" }
log.debug { "${persistedGames.size}/${totalPaths} saved to database" }
// 4. Add new games to library
addGamesToLibrary(persistedGames, library)
@@ -20,7 +20,7 @@ class MessageTemplateService {
private val log = KotlinLogging.logger {}
fun getMessageTemplates(): List<MessageTemplateDto> {
log.info { "Getting all message templates" }
log.debug { "Getting all message templates" }
val messageTemplates = MessageTemplates::class.sealedSubclasses.flatMap { subclass ->
subclass.objectInstance?.let { listOf(it) } ?: listOf()
}
@@ -35,7 +35,7 @@ class MessageTemplateService {
}
fun getMessageTemplateContent(key: String, type: TemplateType): String {
log.info { "Reading message template content for '$key.${type.extension}'" }
log.debug { "Reading message template content for '$key.${type.extension}'" }
return getTemplateFile(key, type).readText()
}
@@ -53,7 +53,7 @@ class MessageTemplateService {
}
fun setMessageTemplateContent(key: String, type: TemplateType, content: String) {
log.info { "Saving message template content for key '$key'" }
log.debug { "Saving message template content for key '$key'" }
getOrCreateTemplateFile(key, type).writeText(content)
}
@@ -80,7 +80,7 @@ class MessageTemplateService {
}
private fun getDefaultTemplateFile(key: String, type: TemplateType): Path {
log.info { "No custom message template found for '$key.${type.extension}', returning default" }
log.debug { "No custom message template found for '$key.${type.extension}', returning default" }
val resourceUrl = javaClass.classLoader.getResource("$DEFAULT_TEMPLATE_PATH/$key.${type.extension}")
?: throw IllegalStateException("Default template file not found for '$key.${type.extension}'")
return Paths.get(resourceUrl.toURI())
@@ -21,7 +21,7 @@ class UserPreferencesService(
* @return The current value if set or the default value or null if no value is set and no default value exists
*/
fun <T : Serializable> get(userPreference: UserPreferences<T>): T? {
log.info { "Getting user preference '${userPreference.key}'" }
log.debug { "Getting user preference '${userPreference.key}'" }
val id = id(userPreference.key)
val appConfig = userPreferenceRepository.findById(id).orElse(null)
@@ -42,7 +42,7 @@ class UserPreferencesService(
*/
fun get(key: String): String? {
log.info { "Getting user preference '$key'" }
log.debug { "Getting user preference '$key'" }
val userPreference = findUserPreference(key)
val id = id(key)
@@ -75,7 +75,7 @@ class UserPreferencesService(
* @throws IllegalArgumentException if the value can't be cast to the type defined for the user preference
*/
fun <T : Serializable> set(key: String, value: T) {
log.info { "Set user preference '$key'" }
log.debug { "Set user preference '$key'" }
val userPreferenceKey = findUserPreference(key)
@@ -1,7 +1,3 @@
logging.level.de.grimsi.gameyfin: DEBUG
logging.level.org.hibernate.SQL: DEBUG
logging.level.org.hibernate.type: TRACE
spring:
datasource:
url: jdbc:h2:file:./db/${spring.datasource.db-name};AUTO_SERVER=TRUE
@@ -15,10 +15,9 @@
</encoder>
</appender>
<!-- Spams the logs on DEBUG due to a loop (log -> push to client -> log the push -> repeat) -->
<logger name="com.vaadin.hilla.push.PushEndpoint" level="INFO"/>
<logger name="de.grimsi.gameyfin" level="{LOG_LEVEL_GAMEYFIN}"/>
<root level="{LOG_LEVEL}">
<root level="{LOG_LEVEL_ROOT}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>