Add crash handler and add various optimizations
This commit is contained in:
parent
2cfc8cad9d
commit
2b8cf723f6
10 changed files with 536 additions and 72 deletions
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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("<red>")
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,6 +61,7 @@ class Logger {
|
|||
* @since v1-alpha10
|
||||
*/
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
val instance = Logger()
|
||||
}
|
||||
|
||||
|
@ -90,35 +91,42 @@ class Logger {
|
|||
/**
|
||||
* Logs a message.
|
||||
*
|
||||
* 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 stackTraceDistance determines which [StackTraceElement] will
|
||||
* be used as the call's origin. Just fiddle
|
||||
* with this number until it's correct.
|
||||
* @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<String, Object?> = 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 (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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a diagnostic message.
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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<FormatBuilder>? = 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<String, ChannelSettings> = mutableMapOf()
|
||||
@JvmStatic
|
||||
var channelSettings: MutableMap<String, ChannelSettings> = mutableMapOf()
|
||||
|
||||
/**
|
||||
* Contains all registered [CrashCategory]s.
|
||||
*
|
||||
* @since v1-alpha10
|
||||
*/
|
||||
@JvmStatic
|
||||
var crashCategories: LinkedHashSet<CrashCategory> = 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<FormatBuilder>? = 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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<String, Any>`. 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<String, Any>
|
||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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)
|
||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<String, Any> {
|
||||
return linkedMapOf(
|
||||
Pair("Origin", linkedMapOf<String, Any>(
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementations of the [CrashCategory] interface.
|
||||
*
|
||||
* @since v1-alpha10
|
||||
*/
|
||||
package de.staropensource.engine.logging.implementation.crashcategory
|
||||
|
||||
import de.staropensource.engine.logging.implementable.CrashCategory
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue