From 2b8cf723f64839105b693189bbd7e20d41e3ac41 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Sun, 15 Dec 2024 19:16:43 +0100 Subject: [PATCH] Add crash handler and add various optimizations --- .../engine/logging/CrashHandler.kt | 134 ++++++++++++++++++ .../staropensource/engine/logging/Logger.kt | 61 ++++---- .../engine/logging/LoggerConfiguration.kt | 81 +++++++---- .../engine/logging/Processor.kt | 24 ++-- .../logging/implementable/CrashCategory.kt | 72 ++++++++++ .../logging/implementable/ShutdownHandler.kt | 36 +++++ .../implementation/KotlinShutdownHandler.kt | 51 +++++++ .../crashcategory/InfoCrashCategory.kt | 76 ++++++++++ .../crashcategory/package-info.kt | 28 ++++ .../engine/logging/type/ChannelSettings.kt | 45 ++++-- 10 files changed, 536 insertions(+), 72 deletions(-) create mode 100644 logging/src/main/kotlin/de/staropensource/engine/logging/CrashHandler.kt create mode 100644 logging/src/main/kotlin/de/staropensource/engine/logging/implementable/CrashCategory.kt create mode 100644 logging/src/main/kotlin/de/staropensource/engine/logging/implementable/ShutdownHandler.kt create mode 100644 logging/src/main/kotlin/de/staropensource/engine/logging/implementation/KotlinShutdownHandler.kt create mode 100644 logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/InfoCrashCategory.kt create mode 100644 logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/package-info.kt diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/CrashHandler.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/CrashHandler.kt new file mode 100644 index 000000000..1583606dd --- /dev/null +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/CrashHandler.kt @@ -0,0 +1,134 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Authors + * Licensed under the GNU Affero General Public License v3 + * with an exception allowing classpath linking. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.engine.logging + +import de.staropensource.engine.logging.implementable.Adapter +import de.staropensource.engine.logging.implementable.CrashCategory +import de.staropensource.engine.logging.implementable.Formatter +import de.staropensource.engine.logging.implementation.KotlinShutdownHandler +import de.staropensource.engine.logging.type.Call +import de.staropensource.engine.logging.type.ChannelSettings + +/** + * Handles crashes. + * + * @since v1-alpha10 + */ +class CrashHandler private constructor() { + /** + * Companion object of [CrashHandler]. + * + * @since v1-alpha10 + */ + companion object { + /** + * Handles crashes. + * + * @param call [Call] metadata + * @param throwable the [Throwable] which caused the crash + * @param fatal terminates the engine and application if `true` + * @since v1-alpha10 + */ + internal fun handle(call: Call, throwable: Throwable? = null, fatal: Boolean = true) { + val format: StringBuilder = StringBuilder() + var formatFinalized: String? = null + val channelconf: ChannelSettings? = LoggerConfiguration.channelSettings[call.channel] + + if (ChannelSettings.getSetting(channelconf, "permitFormatting") as Boolean) + format.append("") + + format + .append("--------------------\nOh no! ") + .append(ChannelSettings.getSetting(channelconf, "applicationName")) + .append(" crashed!\nIf you're a user of this application, then please report this crash to the developer.") + + for (category: CrashCategory in LoggerConfiguration.crashCategories) + if (category.check()) + format + .append("\n\n${category.getName()}") + .append(compileCategory(category.execute(call, channelconf, throwable, fatal))) + + format + .append("\n\n... ") + .append(ChannelSettings.getSetting(channelconf, "applicationName")) + .append(" unfortunately crashed.\nIf you're a user of this application, then please ") + .append("report this crash to the developer.\n--------------------") + + // Format format + formatFinalized = if (ChannelSettings.getSetting(channelconf, "permitFormatting") as Boolean) + (ChannelSettings.getSetting(channelconf, "formatter") as Formatter).formatString(format.toString()) + else + format.toString() + + // Pass format to adapter + (ChannelSettings.getSetting(channelconf, "adapter") as Adapter).handle(call, formatFinalized) + + if (fatal) + (LoggerConfiguration.shutdownHandler ?: KotlinShutdownHandler.instance).exit(exitcode = 69) + } + + /** + * Compiles a [CrashCategory]. + * + * @param category [CrashCategory] to compile + * @return compiled output + * @since v1-alpha10 + */ + private fun compileCategory(map: LinkedHashMap<*, *>, indent: Int = 1): String { + val builder: StringBuilder = StringBuilder() + var entryString: String? = null + + // Iterate over all entries + for (entry in map.keys) { + // Check if key is a string + if (entry !is String) + continue + + builder.append("\n${" ".repeat(indent)}-> ${entry}") + + if (map[entry] is LinkedHashMap<*, *>) // Value is a map + builder.append( + compileCategory( + map[entry] as LinkedHashMap<*, *>, + indent = indent + 3 // increase the 2nd addend to change the indent size during recursion + ) + ) + else { + entryString = map[entry].toString() + + // Put on separate line if contains newline + if (entryString.contains("\n")) + builder + .append("\n${entryString}" + .replace( + "\n", + "\n ${" ".repeat(indent)}" + ) + ) + else + builder.append(": ${entryString}") + } + } + + return builder.toString() + } + } +} diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/Logger.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/Logger.kt index f32ae51cf..c1e5173e5 100644 --- a/logging/src/main/kotlin/de/staropensource/engine/logging/Logger.kt +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/Logger.kt @@ -61,6 +61,7 @@ class Logger { * @since v1-alpha10 */ @JvmStatic + @Suppress("unused") val instance = Logger() } @@ -90,34 +91,41 @@ class Logger { /** * Logs a message. * - * @param level level to use - * @param message message to log - * @param stackTraceDistance determines which [StackTraceElement] will - * be used as the call's origin. Just fiddle - * with this number until it's correct. + * Using this method is highly discouraged as it is + * considered internal and should only be accessed + * if necessary. It provides direct access to the + * internal logging facility and can cause breakage + * if used improperly. + * + * @param level level to use + * @param message message to log + * @param levelData data specific to a [Level] + * @param stackTraceDistance determines which [StackTraceElement] will be used as the call's origin. Just fiddle with this number until it's correct. * @since v1-alpha10 */ - @Suppress("JoinDeclarationAndAssignment") - fun log(level: Level, message: String, stackTraceDistance: Int = 0) { + fun log(level: Level, message: String, levelData: Map = emptyMap(), stackTraceDistance: Int = 0) { val origin: StackTraceElement - var call: Call // Set 'origin' try { origin = Throwable().stackTrace[1 + stackTraceDistance] - } catch (exception: IndexOutOfBoundsException) { + } catch (_: IndexOutOfBoundsException) { return } - // Set 'call' - call = Call(origin, level, message, channel) + // Create 'Call' instance + var call: Call = Call(origin, level, message, channel) // Run processing - if (Processor.check(call)) - return + if (level == Level.CRASH) + CrashHandler.handle(call, levelData["throwable"] as Throwable?, levelData.getOrDefault("fatal", true) as Boolean) + else { + if (Processor.check(call)) + return - if (LoggerConfiguration.threadingHandler?.queue(call) == null) - Processor.process(call) + if (LoggerConfiguration.threadingHandler?.queue(call) == null) + Processor.process(call) + } } /** @@ -127,7 +135,7 @@ class Logger { * @since v1-alpha10 */ fun diag(message: String) { - log(Level.DIAGNOSTIC, message, 1) + log(Level.DIAGNOSTIC, message, stackTraceDistance = 1) } /** @@ -137,7 +145,7 @@ class Logger { * @since v1-alpha10 */ fun verb(message: String) { - log(Level.VERBOSE, message, 1) + log(Level.VERBOSE, message, stackTraceDistance = 1) } /** @@ -147,7 +155,7 @@ class Logger { * @since v1-alpha10 */ fun sarn(message: String) { - log(Level.SILENT_WARNING, message, 1) + log(Level.SILENT_WARNING, message, stackTraceDistance = 1) } /** @@ -157,7 +165,7 @@ class Logger { * @since v1-alpha10 */ fun info(message: String) { - log(Level.INFORMATIONAL, message, 1) + log(Level.INFORMATIONAL, message, stackTraceDistance = 1) } /** @@ -167,7 +175,7 @@ class Logger { * @since v1-alpha10 */ fun warn(message: String) { - log(Level.WARNING, message, 1) + log(Level.WARNING, message, stackTraceDistance = 1) } /** @@ -177,17 +185,22 @@ class Logger { * @since v1-alpha10 */ fun error(message: String) { - log(Level.ERROR, message, 1) + log(Level.ERROR, message, stackTraceDistance = 1) } /** * Logs a fatal error. * - * @param message message + * @param error the error which caused the crash + * @param throwable the [Throwable] which caused the crash + * @param fatal terminates the engine and application if `true` * @since v1-alpha10 */ - fun crash(message: String) { - log(Level.CRASH, message, 1) + fun crash(error: String, throwable: Throwable? = null, fatal: Boolean = true) { + log(Level.CRASH, error, levelData = mapOf( + Pair("throwable", throwable as Object?), + Pair("fatal", fatal as Object?) + ), stackTraceDistance = 1) } diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/LoggerConfiguration.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/LoggerConfiguration.kt index 92216a920..be5fe375f 100644 --- a/logging/src/main/kotlin/de/staropensource/engine/logging/LoggerConfiguration.kt +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/LoggerConfiguration.kt @@ -20,10 +20,13 @@ package de.staropensource.engine.logging +import de.staropensource.engine.logging.implementable.CrashCategory import de.staropensource.engine.logging.implementation.SOSLSv2FormatBuilder import de.staropensource.engine.logging.type.ChannelSettings import de.staropensource.engine.logging.type.Feature import de.staropensource.engine.logging.implementable.FormatBuilder +import de.staropensource.engine.logging.implementable.ShutdownHandler +import de.staropensource.engine.logging.implementation.crashcategory.InfoCrashCategory import de.staropensource.engine.logging.type.Level import de.staropensource.engine.logging.type.OperationMode import kotlinx.datetime.TimeZone @@ -79,32 +82,6 @@ class LoggerConfiguration private constructor() { Feature.LINE_NUMBER, ) - /** - * Controls the [ThreadingHandler] to use. - * - * This determines how multithreading - * shall be performed. Set to `null` for - * a single-threaded logger. - * - * @see ThreadingHandler - * @since v1-alpha10 - */ - @JvmStatic - val threadingHandler: ThreadingHandler? = null - - /** - * Controls the [FormatBuilder] to use. - * - * This determines how formats are built - * and how the final log output looks like. - * Set to `null` to default to [SOSLSv2FormatBuilder]. - * - * @see FormatBuilder - * @since v1-alpha10 - */ - @JvmStatic - val formatBuilder: KClass? = null - /** * Controls how fast the logging thread * shall wait until processing the log @@ -125,7 +102,57 @@ class LoggerConfiguration private constructor() { * * @since v1-alpha10 */ - val channelSettings: MutableMap = mutableMapOf() + @JvmStatic + var channelSettings: MutableMap = mutableMapOf() + + /** + * Contains all registered [CrashCategory]s. + * + * @since v1-alpha10 + */ + @JvmStatic + var crashCategories: LinkedHashSet = linkedSetOf( + InfoCrashCategory.instance + ) + + /** + * Controls the [ThreadingHandler] to use. + * + * This determines how multithreading + * shall be performed. Set to `null` for + * a single-threaded logger. + * + * @see ThreadingHandler + * @since v1-alpha10 + */ + @JvmStatic + var threadingHandler: ThreadingHandler? = null + + /** + * Controls the [FormatBuilder] to use. + * + * This determines how formats are built + * and how the final log output looks like. + * Set to `null` to default to [SOSLSv2FormatBuilder]. + * + * @see FormatBuilder + * @since v1-alpha10 + */ + @JvmStatic + var formatBuilder: KClass? = null + + /** + * Controls the [ShutdownHandler] to use. + * + * This determines how the + * application is shut down + * after crashing fatally. + * + * @see ShutdownHandler + * @since v1-alpha10 + */ + @JvmStatic + var shutdownHandler: ShutdownHandler? = null // -----> Feature settings diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/Processor.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/Processor.kt index 4c6f0b6a0..584fa1bf9 100644 --- a/logging/src/main/kotlin/de/staropensource/engine/logging/Processor.kt +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/Processor.kt @@ -20,13 +20,13 @@ package de.staropensource.engine.logging -import de.staropensource.engine.logging.implementation.NoOperationFormatter -import de.staropensource.engine.logging.implementation.PrintlnAdapter +import de.staropensource.engine.logging.implementable.Adapter +import de.staropensource.engine.logging.implementable.FormatBuilder +import de.staropensource.engine.logging.implementable.Formatter import de.staropensource.engine.logging.implementation.SOSLSv2FormatBuilder import de.staropensource.engine.logging.type.Call import de.staropensource.engine.logging.type.ChannelSettings import de.staropensource.engine.logging.type.Feature -import de.staropensource.engine.logging.implementable.FormatBuilder import de.staropensource.engine.logging.type.OperationMode import kotlin.reflect.full.primaryConstructor @@ -51,6 +51,7 @@ class Processor private constructor() { * * Invoked by [Logger.log]. * + * @param call [Call] metadata * @return terminate processing? * @since v1-alpha10 */ @@ -81,6 +82,7 @@ class Processor private constructor() { * Invoked by the configured * [ThreadingHandler]. * + * @param call [Call] metadata * @see LoggerConfiguration.threadingHandler * @see ChannelSettings.formatter * @see ChannelSettings.adapter @@ -91,7 +93,7 @@ class Processor private constructor() { fun process(call: Call) { val format: FormatBuilder var formatFinalized: String = "" - val channelconf: ChannelSettings = LoggerConfiguration.channelSettings[call.channel] ?: ChannelSettings.global + val channelconf: ChannelSettings? = LoggerConfiguration.channelSettings[call.channel] var message: String = call.message // Set 'format' @@ -103,7 +105,7 @@ class Processor private constructor() { } // Stop if channel does not permit execution - if ((channelconf.enable ?: ChannelSettings.global.enable) == false) + if (!(ChannelSettings.getSetting(channelconf, "enable") as Boolean)) return // Build format @@ -113,11 +115,11 @@ class Processor private constructor() { // Update message if ( - (channelconf.sanitizeMessage ?: ChannelSettings.global.sanitizeMessage) != false - && (channelconf.permitFormatting ?: ChannelSettings.global.permitFormatting) != false + ChannelSettings.getSetting(channelconf, "sanitizeMessage") as Boolean + && ChannelSettings.getSetting(channelconf, "permitFormatting") as Boolean ) message = message.replace("<", "\\<") if ( - ((channelconf.permitFormatting ?: ChannelSettings.global.permitFormatting) != false) + ChannelSettings.getSetting(channelconf, "permitFormatting") as Boolean && LoggerConfiguration.features.contains(Feature.FORMATTING) ) format.addFeature(Feature.FORMATTING) @@ -125,13 +127,13 @@ class Processor private constructor() { format.message = message // Format format - formatFinalized = if ((channelconf.permitFormatting ?: ChannelSettings.global.permitFormatting) != false) - (channelconf.formatter ?: ChannelSettings.global.formatter ?: NoOperationFormatter.instance).formatString(format.toString()) + formatFinalized = if (ChannelSettings.getSetting(channelconf, "permitFormatting") as Boolean) + (ChannelSettings.getSetting(channelconf, "formatter") as Formatter).formatString(format.toString()) else format.toString() // Pass format to adapter - (channelconf.adapter ?: ChannelSettings.global.adapter ?: PrintlnAdapter.instance).handle(call, formatFinalized) + (ChannelSettings.getSetting(channelconf, "adapter") as Adapter).handle(call, formatFinalized) } } } diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/implementable/CrashCategory.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/implementable/CrashCategory.kt new file mode 100644 index 000000000..cd7b8e368 --- /dev/null +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/implementable/CrashCategory.kt @@ -0,0 +1,72 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Authors + * Licensed under the GNU Affero General Public License v3 + * with an exception allowing classpath linking. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.engine.logging.implementable + +import de.staropensource.engine.logging.CrashHandler +import de.staropensource.engine.logging.type.Call +import de.staropensource.engine.logging.type.ChannelSettings + +/** + * Used by the [CrashHandler] to + * print useful information. + * + * @since v1-alpha10 + */ +interface CrashCategory { + /** + * Checks if this category + * shall be executed. + * + * @return execute? + * @since v1-alpha10 + */ + fun check(): Boolean + + /** + * Returns the name of this crash category. + * + * @return category name + * @since v1-alpha10 + */ + fun getName(): String + + /** + * Executes this crash category. + * + * The value of this map can either + * be a [String] or recurse downwards + * with `Map`. Any other + * values will be ignored. + * + * @param call [Call] metadata + * @param channelconf [ChannelSettings] instance or `null`. Use this to access [ChannelSettings.getSetting] + * @param throwable the [Throwable] which caused the crash + * @param fatal terminates the engine and application if `true` + * @return crash category items + * @since v1-alpha10 + */ + fun execute( + call: Call, + channelconf: ChannelSettings?, + throwable: Throwable?, + fatal: Boolean, + ): LinkedHashMap +} diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/implementable/ShutdownHandler.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/implementable/ShutdownHandler.kt new file mode 100644 index 000000000..8d1ff288f --- /dev/null +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/implementable/ShutdownHandler.kt @@ -0,0 +1,36 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Authors + * Licensed under the GNU Affero General Public License v3 + * with an exception allowing classpath linking. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.engine.logging.implementable + +/** + * Handles shutdowns. + * + * @since v1-alpha10 + */ +interface ShutdownHandler { + /** + * Shuts everything down. + * + * @param exitcode the code to exit with + * @since v1-alpha10 + */ + fun exit(exitcode: Byte = 0) +} diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/KotlinShutdownHandler.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/KotlinShutdownHandler.kt new file mode 100644 index 000000000..992f416d6 --- /dev/null +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/KotlinShutdownHandler.kt @@ -0,0 +1,51 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Authors + * Licensed under the GNU Affero General Public License v3 + * with an exception allowing classpath linking. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.engine.logging.implementation + +import de.staropensource.engine.logging.implementable.ShutdownHandler +import kotlin.system.exitProcess + +/** + * [ShutdownHandler] implementation using + * Kotlin's [kotlin.system.exitProcess] method. + * + * @since v1-alpha10 + */ +class KotlinShutdownHandler private constructor() : ShutdownHandler { + /** + * Companion object of [KotlinShutdownHandler]. + * + * @since v1-alpha10 + */ + companion object { + /** + * Global instance of [KotlinShutdownHandler]. + * + * @since v1-alpha10 + */ + @JvmStatic + val instance: KotlinShutdownHandler = KotlinShutdownHandler() + } + + override fun exit(exitcode: Byte) { + exitProcess(exitcode.toInt()) + } +} diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/InfoCrashCategory.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/InfoCrashCategory.kt new file mode 100644 index 000000000..5a79930ab --- /dev/null +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/InfoCrashCategory.kt @@ -0,0 +1,76 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Authors + * Licensed under the GNU Affero General Public License v3 + * with an exception allowing classpath linking. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.engine.logging.implementation.crashcategory + +import de.staropensource.engine.logging.implementable.CrashCategory +import de.staropensource.engine.logging.type.Call +import de.staropensource.engine.logging.type.ChannelSettings + +/** + * [CrashCategory] implementation + * providing insight into a crash. + * + * @since v1-alpha10 + */ +class InfoCrashCategory private constructor() : CrashCategory { + /** + * Companion object of [InfoCrashCategory]. + * + * @since v1-alpha10 + */ + companion object { + /** + * Global instance of [InfoCrashCategory]. + * + * @since v1-alpha10 + */ + @JvmStatic + val instance: InfoCrashCategory = InfoCrashCategory() + } + + override fun check(): Boolean { + return true + } + + override fun getName(): String { + return "Crash" + } + + override fun execute( + call: Call, + channelconf: ChannelSettings?, + throwable: Throwable?, + fatal: Boolean, + ): LinkedHashMap { + return linkedMapOf( + Pair("Origin", linkedMapOf( + Pair("Class", call.origin.className), + Pair("Method", call.origin.methodName), + Pair("Line", call.origin.lineNumber), + Pair("Native", if (call.origin.isNativeMethod) "yes" else "false") + )), + Pair("Channel", call.channel), + Pair("Fatal", if (fatal) "yes" else "no"), + Pair("Message", call.message), + Pair("Stacktrace", throwable?.toString() ?: "Not available."), // TODO report correct stacktrace + ) + } +} diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/package-info.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/package-info.kt new file mode 100644 index 000000000..57d2b4c8b --- /dev/null +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/implementation/crashcategory/package-info.kt @@ -0,0 +1,28 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Authors + * Licensed under the GNU Affero General Public License v3 + * with an exception allowing classpath linking. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * Implementations of the [CrashCategory] interface. + * + * @since v1-alpha10 + */ +package de.staropensource.engine.logging.implementation.crashcategory + +import de.staropensource.engine.logging.implementable.CrashCategory diff --git a/logging/src/main/kotlin/de/staropensource/engine/logging/type/ChannelSettings.kt b/logging/src/main/kotlin/de/staropensource/engine/logging/type/ChannelSettings.kt index 469cbd981..73c3b620b 100644 --- a/logging/src/main/kotlin/de/staropensource/engine/logging/type/ChannelSettings.kt +++ b/logging/src/main/kotlin/de/staropensource/engine/logging/type/ChannelSettings.kt @@ -12,16 +12,18 @@ import de.staropensource.engine.logging.implementation.PrintlnAdapter * @param enable enables or disables all log messages utilising this channel. Defaults to the global value or `true` if set to `null` * @param sanitizeMessage if message sanitization (escaping `<`) should be performed. Defaults to the global value or `true` if set to `null` * @param permitFormatting if formatting shall be permitted for the entire format. For disallowing formatting for the message only, see [sanitizeMessage]. Defaults to the global value or `true` if set to `null` + * @param applicationName name of the application. Used in crash reports. Defaults to the global value or `"This application"` if `null` * @param formatter determines how messages are formatted and stylized. Defaults to the global value or [NoOperationFormatter] if set to `null` * @param adapter used for printing the finalized log format somewhere. Defaults to the global value [PrintlnAdapter] if set to `null` * @since v1-alpha10 */ data class ChannelSettings( - val enable: Boolean? = null, - val sanitizeMessage: Boolean? = null, - val permitFormatting: Boolean? = null, - val formatter: Formatter? = null, - val adapter: Adapter? = null, + private val enable: Boolean? = null, + private val sanitizeMessage: Boolean? = null, + private val permitFormatting: Boolean? = null, + private val applicationName: String? = null, + private val formatter: Formatter? = null, + private val adapter: Adapter? = null, ) { /** * Companion object of [ChannelSettings]. @@ -47,11 +49,34 @@ data class ChannelSettings( */ @JvmStatic val global: ChannelSettings = ChannelSettings( - true, - true, - true, - null, - null + enable = null, + sanitizeMessage = null, + permitFormatting = null, + applicationName = null, + formatter = null, + adapter = null, ) + + /** + * Returns a setting's value. + * + * @param settings [ChannelSettings] instance to access. Set to `null` to only access the global settings + * @param setting setting to get + * @return setting value or `null` + * @since v1-alpha10 + */ + @JvmStatic + @Suppress("CyclomaticComplexMethod") + fun getSetting(settings: ChannelSettings?, setting: String): Any? { + return when (setting) { + "enable" -> (settings?.enable ?: global.enable) != false + "sanitizeMessage" -> (settings?.sanitizeMessage ?: global.sanitizeMessage) != false + "permitFormatting" -> (settings?.permitFormatting ?: global.permitFormatting) != false + "applicationName" -> settings?.applicationName ?: global.applicationName ?: "This application" + "formatter" -> settings?.formatter ?: global.formatter ?: NoOperationFormatter.instance + "adapter" -> settings?.adapter ?: global.adapter ?: PrintlnAdapter.instance + else -> null + } + } } }