Skip to content

Commit

Permalink
Vela lib-log
Browse files Browse the repository at this point in the history
  • Loading branch information
Menkalian committed Sep 1, 2022
1 parent edcb325 commit 7f92fb1
Show file tree
Hide file tree
Showing 32 changed files with 1,445 additions and 0 deletions.
31 changes: 31 additions & 0 deletions lib-log/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# lib-log

Simple logger library for the JVM built with Kotlin. For most people [https://github.com/qos-ch/slf4j](SLF4J) (and it's implementation) will probably be the right choice.

Some things this library provides are:

- Easy setup of well-defined loggers (instead of having one Log-Label per class)
- Built-in easy support for multiple log outputs
- Programmatic control of the configuration
- Usage of custom tags for formatting. These can be implemented by you
- Built-in support for gathering logfiles, that compile filtered information for other logfiles in one place
- multithreading support

## Custom formatter tags provided by the library

| Placeholder | meaning | example input | example output |
|-------------|------------------------------------------------|------------------------|-------------------------------------|
| %q %lq | Insert the quoted string value of the argument | "Vela" | "\"Vela\"" |
| %lx | Insert the stacktrace of a Throwable | new RuntimeException() | "java.lang.RuntimeException at ..." |

## Example usage

````kotlin
fun main() {
LoggerFactory.getInstance().configure {
addColoredStdoutLogWriter()
}
val log = LoggerFactory.getInstance().getLogger("DEFAULT")
log.info("Hello Logger!")
}
````
41 changes: 41 additions & 0 deletions lib-log/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
plugins {
java
`maven-publish`
jacoco

kotlin("jvm")
kotlin("plugin.serialization")

id("org.jetbrains.dokka")
}

publishing {
publications {
create<MavenPublication>("default") {
from(components["java"])
dependencies {
// SLF4J NOOP
implementation("org.slf4j:slf4j-nop:2.0.0")
}
}
create<MavenPublication>("slf4jcompatible") {
this.artifactId += "-slf4j-s2s"
from(components["java"])
}
}
}

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")

implementation("org.jetbrains.exposed:exposed-core:0.39.2")
implementation("org.jetbrains.exposed:exposed-dao:0.39.2")
implementation("org.jetbrains.exposed:exposed-jdbc:0.39.2")

// Database Drivers
runtimeOnly("org.xerial:sqlite-jdbc:3.39.2.0")

// SLF4J NOOP
implementation("org.slf4j:slf4j-nop:2.0.0")
}
38 changes: 38 additions & 0 deletions lib-log/src/main/kotlin/de/menkalian/vela/loglib/CustomLogTag.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package de.menkalian.vela.loglib

import java.util.Locale

/**
* Interface for a custom Formatter-Tag, usable in Log-Messages.
*
* The following Formatter-Tags are already provided by the library:
* - "%q"/"%lq": Inserts the `String`-Value of the argument, surrounded by quotes
* - "%lx": Inserts the Message and StackTrace of the argument, if it is a `Throwable`
*/
interface CustomLogTag {
/**
* Regex to match a placeholder handled by this LogTag.
* You may use placeholders of any form, but they must not collide with existing LogTags.
* The library uses the prefix "%l" for provided LogTags, but the prefix "%ll" is reserved for Placeholders implemented by users of the library.
*/
val tagRegex: String

/**
* Amount of arguments this LogTag uses from the argument list.
* The given amount will be skipped after invoking this LogTag.
*/
val argCount: Int
get() = 1

/**
* Generates the replacement string for `matchedTag`.
*
* @param locale Optional `Locale` to use for formatting.
* @param matchedTag Matched placeholder. Advanced LogTags may process args in their placeholders.
* @param argIndex Index of the first argument associated with this LogTag
* @param args Input Arguments of the format-call
*
* @return Replacement to put in the formatted string.
*/
fun format(locale: Locale?, matchedTag: String, argIndex: Int, args: MutableList<Any>): String
}
28 changes: 28 additions & 0 deletions lib-log/src/main/kotlin/de/menkalian/vela/loglib/LogEntry.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package de.menkalian.vela.loglib

import java.util.Locale

/**
* Class representing a single logging message (entry)
*
* @property logger LogSpec this entry is associated with
* @property logLevel Importance of this entry
* @property threadName Name of the thread this entry was logged from
* @property threadId Identifier of the thread this entry was logged from
* @property origin JVM-Class, Method and Linenumber this entry was logged from (is not filled if [LoggerConfiguration.determineLogOrigin] is not set `true`)
* @property timestampMs Unix-Timestamp (Milliseconds) when this entry was logged at
* @property msgLocale Optional [Locale] to use for formatting the message of this entry
* @property msgFormat Format-String to create the message of this entry
* @property msgArgs Arguments for formatting the message of this entry
*/
data class LogEntry(
val logger: LoggerConfiguration.LogSpec,
val logLevel: LogLevel,
val threadName: String,
val threadId: Long,
val origin: String,
val timestampMs: Long,
val msgLocale: Locale?,
val msgFormat: String,
val msgArgs: List<Any>,
)
14 changes: 14 additions & 0 deletions lib-log/src/main/kotlin/de/menkalian/vela/loglib/LogLevel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package de.menkalian.vela.loglib

enum class LogLevel(internal val priority: Int) {
ESSENTIAL(100),
FATAL(80),
ERROR(60),
WARN(40),
INFO(30),
DEBUG(20),
TRACE(10),
SILENT(0);

infix fun shows(other: LogLevel) = this.priority <= other.priority
}
8 changes: 8 additions & 0 deletions lib-log/src/main/kotlin/de/menkalian/vela/loglib/LogWriter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package de.menkalian.vela.loglib

import de.menkalian.vela.loglib.logger.distributor.LogEventListener

interface LogWriter : LogEventListener {
val minimumLoggerLevel: LogLevel
get() = LogLevel.SILENT
}
160 changes: 160 additions & 0 deletions lib-log/src/main/kotlin/de/menkalian/vela/loglib/Logger.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package de.menkalian.vela.loglib

import java.util.Locale

/**
* Interface for an individual [Logger].
* To obtain an instance, use [LoggerFactory.getLogger].
*
* @property enabled Whether this logger is enabled or not
* @property name Unique name of this logger
* @property minLogLevel Minimum importance handled by this logger
*/
interface Logger {
val enabled: Boolean
val name: String
val minLogLevel: LogLevel

/**
* Log a message to the [LogLevel.ESSENTIAL] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun essential(msgFormat: String, vararg args: Any) = log(LogLevel.ESSENTIAL, msgFormat, *args)

/**
* Log a message to the [LogLevel.ESSENTIAL] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun essential(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.ESSENTIAL, locale, msgFormat, *args)

/**
* Log a message to the [LogLevel.FATAL] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun fatal(msgFormat: String, vararg args: Any) = log(LogLevel.FATAL, msgFormat, *args)

/**
* Log a message to the [LogLevel.FATAL] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun fatal(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.FATAL, locale, msgFormat, *args)

/**
* Log a message to the [LogLevel.ERROR] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun error(msgFormat: String, vararg args: Any) = log(LogLevel.ERROR, msgFormat, *args)

/**
* Log a message to the [LogLevel.ERROR] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun error(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.ERROR, locale, msgFormat, *args)

/**
* Log a message to the [LogLevel.WARN] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun warn(msgFormat: String, vararg args: Any) = log(LogLevel.WARN, msgFormat, *args)

/**
* Log a message to the [LogLevel.WARN] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun warn(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.WARN, locale, msgFormat, *args)

/**
* Log a message to the [LogLevel.INFO] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun info(msgFormat: String, vararg args: Any) = log(LogLevel.INFO, msgFormat, *args)

/**
* Log a message to the [LogLevel.INFO] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun info(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.INFO, locale, msgFormat, *args)

/**
* Log a message to the [LogLevel.DEBUG] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun debug(msgFormat: String, vararg args: Any) = log(LogLevel.DEBUG, msgFormat, *args)

/**
* Log a message to the [LogLevel.DEBUG] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun debug(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.DEBUG, locale, msgFormat, *args)

/**
* Log a message to the [LogLevel.TRACE] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun trace(msgFormat: String, vararg args: Any) = log(LogLevel.TRACE, msgFormat, *args)

/**
* Log a message to the [LogLevel.TRACE] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun trace(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.TRACE, locale, msgFormat, *args)

/**
* Log a message to the [LogLevel.SILENT] level.
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun silent(msgFormat: String, vararg args: Any) = log(LogLevel.SILENT, msgFormat, *args)

/**
* Log a message to the [LogLevel.SILENT] level.
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun silent(locale: Locale?, msgFormat: String, vararg args: Any) = log(LogLevel.SILENT, locale, msgFormat, *args)

/**
* Log a message to any level.
* @param level [LogLevel] to use
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun log(level: LogLevel, msgFormat: String, vararg args: Any)

/**
* Log a message to any level.
* @param level [LogLevel] to use
* @param locale Optional locale to use for formatting
* @param msgFormat Format string to create the message
* @param args Arguments for formatting the given template
*/
fun log(level: LogLevel, locale: Locale?, msgFormat: String, vararg args: Any)

/**
* Forward a [LogEntry] received from any other logger and write it to this logger as well.
* @param entry [LogEntry] to log
*/
fun logCollected(entry: LogEntry)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package de.menkalian.vela.loglib

interface LoggerConfiguration {
interface LogSpec {
val enabled: Boolean

val name: String
val minLogLevel: LogLevel

val nameMatchRegex: String
val classMatchRegex: String

val collectLogs: Boolean
val collectedLoggersRegex: String

val maxLogFiles: Int
val maxLogFileSizeKb: Int
val compressRotatedFiles: Boolean
}

val customLogTags: List<CustomLogTag>
val defaultLogSpec: LogSpec
val logSpecs: List<LogSpec>
val logWriterCreators: List<(LogSpec) -> LogWriter>
val globalLogLevel: LogLevel

val enableMultithreadLogging: Boolean
val determineLogOrigin: Boolean
}
Loading

0 comments on commit 7f92fb1

Please sign in to comment.