Skip to content

Commit

Permalink
Reorganized logging package
Browse files Browse the repository at this point in the history
  • Loading branch information
Shengaero committed May 14, 2018
1 parent b97a2a9 commit 6a3b50a
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 24 deletions.
35 changes: 35 additions & 0 deletions commons/src/main/kotlin/xyz/laxus/logging/filters/BooleanFilter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2018 Kaidan Gustave
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.laxus.logging.filters

import ch.qos.logback.core.filter.Filter
import ch.qos.logback.core.spi.FilterReply

/**
* @author Kaidan Gustave
*/
abstract class BooleanFilter<E>: Filter<E>() {
final override fun decide(event: E): FilterReply {
val decision = filter(event)
return when(decision) {
null -> FilterReply.NEUTRAL
true -> FilterReply.ACCEPT
false -> FilterReply.DENY
}
}

protected abstract fun filter(event: E): Boolean?
}
100 changes: 100 additions & 0 deletions commons/src/main/kotlin/xyz/laxus/logging/filters/LoggerNameFilter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2018 Kaidan Gustave
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("MemberVisibilityCanBePrivate", "unused")
package xyz.laxus.logging.filters

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.filter.Filter
import ch.qos.logback.core.spi.FilterReply
import ch.qos.logback.core.spi.FilterReply.NEUTRAL
import xyz.laxus.util.collections.FixedSizeCache
import xyz.laxus.util.regexpFromGlob
import java.util.*
import java.util.function.Function
import java.util.regex.PatternSyntaxException

/**
* @author Kaidan Gustave
*/
class LoggerNameFilter: Filter<ILoggingEvent>() {
private lateinit var cache: FixedSizeCache<String, FilterReply>
private val matchers = LinkedList<(String) -> Boolean>()

// Reuse the same function, even if it has very
//little to no affect on overhead
private val computeIfAbsent = Function<String, FilterReply> reply@ {
for(matcher in matchers) {
if(matcher(it)) {
return@reply onMatch
}
}
return@reply onMismatch
}

private var _level: Level? = null


var level: String?
get() = _level?.levelStr
set(value) { _level = Level.toLevel(value) }
var cacheSize = 50
var onMatch = NEUTRAL
var onMismatch = NEUTRAL

fun addPattern(glob: String) {
addInfo("Parsing Glob to RegExp: $glob")
val regexp = regexpFromGlob(glob)
addInfo("Parsed: $regexp")

// Nothing changed, our function
//will compare for equality
if(regexp == glob) {
matchers += { it == glob }
return
}

val regex = try { Regex(regexp, RegexOption.DOT_MATCHES_ALL) } catch(e: PatternSyntaxException) {
addError("Glob pattern not valid: $glob (index: ${e.index})")
return
}

matchers += { it matches regex }
}

override fun start() {
super.start()
addInfo("Creating result cache (size: $cacheSize)")
this.cache = FixedSizeCache(cacheSize)
}

override fun decide(event: ILoggingEvent?): FilterReply {
_level?.let { filterLevel ->
event?.level?.let { eventLevel ->
if(filterLevel != eventLevel) {
return NEUTRAL
}
}
}
val loggerName = event?.loggerName
if(loggerName === null) return NEUTRAL
return cache.computeIfAbsent(loggerName, computeIfAbsent)
}

interface Matcher {
fun match()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.laxus.logging
@file:Suppress("LiftReturnOrAssignment")
package xyz.laxus.logging.filters

import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.filter.Filter
import ch.qos.logback.core.spi.FilterReply
import xyz.laxus.logging.LogLevel

class NormalFilter: Filter<ILoggingEvent>() {
class NormalFilter: BooleanFilter<ILoggingEvent>() {
companion object {
var level = LogLevel.INFO
}

override fun decide(event: ILoggingEvent): FilterReply {
return if(level.covers(LogLevel.byLevel(event.level))) FilterReply.ACCEPT else FilterReply.DENY
override fun filter(event: ILoggingEvent): Boolean? {
return Companion.level.covers(LogLevel.byLevel(event.level)).takeUnless { it }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2018 Kaidan Gustave
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.laxus.logging.filters

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.turbo.TurboFilter
import ch.qos.logback.core.spi.FilterReply
import org.slf4j.Marker

/**
* @author Kaidan Gustave
*/
abstract class TurboBooleanFilter: TurboFilter() {
final override fun decide(
marker: Marker?, logger: Logger, level: Level,
format: String?, params: Array<out Any>?, t: Throwable?
): FilterReply {
val decision = filter(marker, logger, level, format, params, t)
return when(decision) {
null -> FilterReply.NEUTRAL
true -> FilterReply.ACCEPT
false -> FilterReply.DENY
}
}

protected abstract fun filter(
marker: Marker?, logger: Logger, level: Level,
format: String?, params: Array<out Any>?, t: Throwable?
): Boolean?
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
@file:Suppress("UNCHECKED_CAST")
package xyz.laxus.util.collections

import java.util.function.BiConsumer

/**
* @author Kaidan Gustave
*/
Expand All @@ -33,11 +31,7 @@ class ConcurrentFixedSizeCache<K: Any, V: Any>(size: Int): MutableMap<K, V> {
override val entries get() = map.entries
override val keys get() = map.keys
override val values get() = map.values
override val size get() = backingKeys.count { it !== null }

operator fun set(key: K, value: V) {
put(key, value)
}
override val size get() = map.size

override fun clear() {
map.clear()
Expand All @@ -48,28 +42,21 @@ class ConcurrentFixedSizeCache<K: Any, V: Any>(size: Int): MutableMap<K, V> {
}

override fun put(key: K, value: V): V? {
val v = if(backingKeys[currIndex] !== null) {
map.remove(backingKeys[currIndex])
} else map.put(key, value)

backingKeys[currIndex]?.let { map -= it }
backingKeys[currIndex] = key
currIndex = (currIndex + 1) % backingKeys.size
return v
return map.put(key, value)
}

override fun putAll(from: Map<out K, V>) = from.forEach { k, v -> put(k,v) }

override fun remove(key: K): V? = map.remove(key)

override fun isEmpty(): Boolean = size == 0
override fun isEmpty(): Boolean = map.isEmpty()

override fun get(key: K): V? = map[key]

override fun getOrDefault(key: K, defaultValue: V): V = map[key] ?: defaultValue

override fun containsKey(key: K): Boolean = map.containsKey(key)

override fun containsValue(value: V): Boolean = map.containsValue(value)

override fun forEach(action: BiConsumer<in K, in V>) = map.forEach(action)
}
86 changes: 86 additions & 0 deletions commons/src/main/kotlin/xyz/laxus/util/strings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,89 @@ package xyz.laxus.util
* @return `false` if the receiver does not match the [regex].
*/
infix fun String.doesNotMatch(regex: Regex): Boolean = !(this matches regex)

/**
* Converts a [Text Glob](https://metacpan.org/pod/Text::Glob)
* pattern to a [RegExp][Regex] equivalent.
*
* @param glob The Text Glob to convert.
*
* @return A RegExp equivalent.
*/
fun regexpFromGlob(glob: String): String {
var g = glob
if(g.startsWith('*')) {
g = g.substring(1)
}
if(g.endsWith('*')) {
g = g.substring(0, g.length - 1)
}
return buildString(glob.length) {
var escaping = false
var level = 0
for(c in g) when(c) {
'*' -> {
append(if(escaping) "\\*" else ".*")
escaping = false
}
'?' -> {
append(if(escaping) "\\?" else ".")
escaping = false
}
'.', '(', ')',
'+', '|', '^',
'$', '@', '%' -> {
append('\\')
append(c)
escaping = false
}

'\\' -> {
if(escaping) {
append("\\\\")
escaping = false
} else {
escaping = true
}
}

'{' -> {
if(escaping) {
append("\\{")
} else {
append('(')
level++
}
escaping = false
}

'}' -> {
if(level > 0 && !escaping) {
append(')')
level--
} else if(escaping) {
append("\\}")
} else {
append("}")
}
escaping = false
}

',' -> {
if(level > 0 && !escaping) {
append('|')
} else if(escaping) {
append("\\,")
} else {
append(',')
}
escaping = false
}

else -> {
append(c)
escaping = false
}
}
}
}
2 changes: 1 addition & 1 deletion core/src/main/kotlin/xyz/laxus/bot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import xyz.laxus.entities.tagMethods
import xyz.laxus.jda.listeners.SuspendedListener
import xyz.laxus.jda.util.listeningTo
import xyz.laxus.logging.LogLevel
import xyz.laxus.logging.NormalFilter
import xyz.laxus.logging.filters.NormalFilter
import xyz.laxus.util.*
import xyz.laxus.util.collections.CaseInsensitiveHashMap
import xyz.laxus.util.collections.FixedSizeCache
Expand Down

0 comments on commit 6a3b50a

Please sign in to comment.