-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
port over Dartzee logger, gitignore some stupid stuff
- Loading branch information
1 parent
3f2db28
commit 1d79bf6
Showing
22 changed files
with
712 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,6 @@ | |
|
||
# Ignore Gradle build output directory | ||
build | ||
|
||
Replays | ||
*UsedKeys.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import logging.KEY_APP_VERSION | ||
import logging.KEY_DEVICE_ID | ||
import logging.KEY_DEV_MODE | ||
import logging.KEY_OPERATING_SYSTEM | ||
import logging.KEY_USERNAME | ||
import util.AbstractClient | ||
import util.CoreRegistry.INSTANCE_STRING_DEVICE_ID | ||
import util.CoreRegistry.instance | ||
import util.OnlineConstants | ||
import utils.InjectedThings.logger | ||
import java.util.* | ||
|
||
fun setLoggingContextFields() { | ||
logger.addToContext(KEY_USERNAME, System.getProperty("user.name")) | ||
logger.addToContext(KEY_APP_VERSION, OnlineConstants.ENTROPY_VERSION_NUMBER) | ||
logger.addToContext(KEY_OPERATING_SYSTEM, AbstractClient.operatingSystem) | ||
logger.addToContext(KEY_DEVICE_ID, getDeviceId()) | ||
logger.addToContext(KEY_DEV_MODE, AbstractClient.devMode) | ||
} | ||
|
||
fun getDeviceId() = instance.get(INSTANCE_STRING_DEVICE_ID, null) ?: setDeviceId() | ||
private fun setDeviceId(): String { | ||
val deviceId = UUID.randomUUID().toString() | ||
instance.put(INSTANCE_STRING_DEVICE_ID, deviceId) | ||
return deviceId | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package bean | ||
|
||
import logging.KEY_ACTIVE_WINDOW | ||
import utils.InjectedThings | ||
import java.awt.event.WindowEvent | ||
import java.awt.event.WindowFocusListener | ||
import javax.swing.JFrame | ||
|
||
abstract class FocusableWindow : JFrame(), WindowFocusListener { | ||
abstract val windowName: String | ||
|
||
init | ||
{ | ||
addWindowFocusListener(this) | ||
} | ||
|
||
override fun windowGainedFocus(e: WindowEvent?) { | ||
InjectedThings.logger.addToContext(KEY_ACTIVE_WINDOW, windowName) | ||
} | ||
|
||
override fun windowLostFocus(e: WindowEvent?) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package bean | ||
|
||
import java.awt.Container | ||
import java.awt.Dimension | ||
import java.awt.FlowLayout | ||
import javax.swing.JScrollPane | ||
import javax.swing.SwingUtilities | ||
|
||
/** | ||
* FlowLayout subclass that fully supports wrapping of components. | ||
*/ | ||
class WrapLayout : FlowLayout() { | ||
/** | ||
* Returns the preferred dimensions for this layout given the | ||
* *visible* components in the specified target container. | ||
* @param target the component which needs to be laid out | ||
* @return the preferred dimensions to lay out the | ||
* subcomponents of the specified container | ||
*/ | ||
override fun preferredLayoutSize(target: Container) = layoutSize(target, true) | ||
|
||
/** | ||
* Returns the minimum dimensions needed to layout the *visible* | ||
* components contained in the specified target container. | ||
* @param target the component which needs to be laid out | ||
* @return the minimum dimensions to lay out the | ||
* subcomponents of the specified container | ||
*/ | ||
override fun minimumLayoutSize(target: Container): Dimension { | ||
val minimum = layoutSize(target, false) | ||
minimum.width -= hgap + 1 | ||
return minimum | ||
} | ||
|
||
/** | ||
* Returns the minimum or preferred dimension needed to layout the target | ||
* container. | ||
* | ||
* @param target target to get layout size for | ||
* @param preferred should preferred size be calculated | ||
* @return the dimension to layout the target container | ||
*/ | ||
private fun layoutSize(target: Container, preferred: Boolean): Dimension { | ||
synchronized(target.treeLock) { | ||
// Each row must fit with the width allocated to the containter. | ||
// When the container width = 0, the preferred width of the container | ||
// has not yet been calculated so lets ask for the maximum. | ||
var container = target | ||
while (container.size.width == 0 && container.parent != null) { | ||
container = container.parent | ||
} | ||
|
||
var targetWidth = container.size.width | ||
if (targetWidth == 0) targetWidth = Int.MAX_VALUE | ||
|
||
val hgap = hgap | ||
val vgap = vgap | ||
val insets = target.insets | ||
val horizontalInsetsAndGap = insets.left + insets.right + hgap * 2 | ||
val maxWidth = targetWidth - horizontalInsetsAndGap | ||
// Fit components into the allowed width | ||
val dim = Dimension(0, 0) | ||
var rowWidth = 0 | ||
var rowHeight = 0 | ||
val nmembers = target.componentCount | ||
for (i in 0 until nmembers) { | ||
val m = target.getComponent(i) | ||
if (m.isVisible) { | ||
val d = if (preferred) m.preferredSize else m.minimumSize | ||
// Can't add the component to current row. Start a new row. | ||
if (rowWidth + d.width > maxWidth) { | ||
addRow(dim, rowWidth, rowHeight) | ||
rowWidth = 0 | ||
rowHeight = 0 | ||
} | ||
// Add a horizontal gap for all components after the first | ||
if (rowWidth != 0) { | ||
rowWidth += hgap | ||
} | ||
rowWidth += d.width | ||
rowHeight = Math.max(rowHeight, d.height) | ||
} | ||
} | ||
addRow(dim, rowWidth, rowHeight) | ||
dim.width += horizontalInsetsAndGap | ||
dim.height += insets.top + insets.bottom + vgap * 2 | ||
// When using a scroll pane or the DecoratedLookAndFeel we need to | ||
// make sure the preferred size is less than the size of the | ||
// target containter so shrinking the container size works | ||
// correctly. Removing the horizontal gap is an easy way to do this. | ||
val scrollPane = SwingUtilities.getAncestorOfClass( | ||
JScrollPane::class.java, | ||
target, | ||
) | ||
if (scrollPane != null && target.isValid) { | ||
dim.width -= hgap + 1 | ||
} | ||
return dim | ||
} | ||
} | ||
|
||
/** | ||
* A new row has been completed. Use the dimensions of this row | ||
* to update the preferred size for the container. | ||
* | ||
* @param dim update the width and height when appropriate | ||
* @param rowWidth the width of the row to add | ||
* @param rowHeight the height of the row to add | ||
*/ | ||
private fun addRow(dim: Dimension, rowWidth: Int, rowHeight: Int) { | ||
dim.width = maxOf(dim.width, rowWidth) | ||
if (dim.height > 0) { | ||
dim.height += vgap | ||
} | ||
dim.height += rowHeight | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package logging | ||
|
||
interface ILogDestination { | ||
fun log(record: LogRecord) | ||
fun contextUpdated(context: Map<String, Any?>) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package logging | ||
|
||
class LogDestinationSystemOut : ILogDestination { | ||
override fun log(record: LogRecord) { | ||
println(record) | ||
record.getThrowableStr()?.let { println(it) } | ||
record.keyValuePairs[KEY_STACK]?.let { println(it) } | ||
} | ||
|
||
override fun contextUpdated(context: Map<String, Any?>) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package logging | ||
|
||
import java.time.Instant | ||
import java.time.ZoneId | ||
import java.time.format.DateTimeFormatter | ||
import java.util.* | ||
|
||
enum class Severity { | ||
INFO, | ||
WARN, | ||
ERROR, | ||
} | ||
|
||
data class LogRecord( | ||
val timestamp: Instant, | ||
val severity: Severity, | ||
val loggingCode: LoggingCode, | ||
val message: String, | ||
val errorObject: Throwable?, | ||
val keyValuePairs: Map<String, Any?>, | ||
) { | ||
private val dateStr = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") | ||
.withLocale(Locale.UK) | ||
.withZone(ZoneId.systemDefault()) | ||
.format(timestamp) | ||
|
||
override fun toString(): String { | ||
val durationStr = keyValuePairs[KEY_DURATION]?.let { " (${it}ms) " }.orEmpty() | ||
val rowCountStr = keyValuePairs[KEY_ROW_COUNT]?.let { " ($it rows) " }.orEmpty() | ||
return "$dateStr [$loggingCode] $durationStr$rowCountStr$message" | ||
} | ||
|
||
fun getThrowableStr() = errorObject?.let { "$dateStr ${extractStackTrace(errorObject)}" } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package logging | ||
|
||
import getPercentage | ||
import utils.InjectedThings | ||
import java.util.concurrent.ConcurrentHashMap | ||
import java.util.concurrent.Executors | ||
import java.util.concurrent.ThreadFactory | ||
import java.util.concurrent.TimeUnit | ||
import kotlin.math.floor | ||
|
||
private const val LOGGER_THREAD = "Logger" | ||
|
||
class Logger(private val destinations: List<ILogDestination>) { | ||
val loggingContext = ConcurrentHashMap<String, Any?>() | ||
private val loggerFactory = ThreadFactory { r -> Thread(r, LOGGER_THREAD) } | ||
private var logService = Executors.newFixedThreadPool(1, loggerFactory) | ||
|
||
fun addToContext(loggingKey: String, value: Any?) { | ||
loggingContext[loggingKey] = value ?: "" | ||
destinations.forEach { it.contextUpdated(loggingContext.toMap()) } | ||
} | ||
|
||
fun logProgress(code: LoggingCode, workDone: Long, workToDo: Long, percentageToLogAt: Int = 10) { | ||
// Convert 1 to 0.01, 50 to 0.5, etc. | ||
val percentageAsDecimal = percentageToLogAt.toDouble() / 100 | ||
val percentageOfTotal = floor(workToDo * percentageAsDecimal) | ||
val remainder = workDone % percentageOfTotal | ||
if (remainder == 0.0) { | ||
val percentStr = getPercentage(workDone, workToDo) | ||
val logStr = "Done $workDone/$workToDo ($percentStr%)" | ||
info(code, logStr) | ||
} | ||
} | ||
|
||
fun info(code: LoggingCode, message: String, vararg keyValuePairs: Pair<String, Any?>) { | ||
log(Severity.INFO, code, message, null, mapOf(*keyValuePairs)) | ||
} | ||
|
||
fun warn(code: LoggingCode, message: String, vararg keyValuePairs: Pair<String, Any?>) { | ||
log(Severity.WARN, code, message, null, mapOf(*keyValuePairs)) | ||
} | ||
|
||
fun error(code: LoggingCode, message: String, vararg keyValuePairs: Pair<String, Any?>) { | ||
error(code, message, Throwable(message), keyValuePairs = keyValuePairs) | ||
} | ||
|
||
fun error(code: LoggingCode, message: String, errorObject: Throwable = Throwable(message), vararg keyValuePairs: Pair<String, Any?>) { | ||
log(Severity.ERROR, code, message, errorObject, mapOf(*keyValuePairs, KEY_EXCEPTION_MESSAGE to errorObject.message)) | ||
} | ||
|
||
private fun log(severity: Severity, code: LoggingCode, message: String, errorObject: Throwable?, keyValuePairs: Map<String, Any?>) { | ||
val timestamp = InjectedThings.clock.instant() | ||
val logRecord = LogRecord(timestamp, severity, code, message, errorObject, loggingContext + keyValuePairs) | ||
|
||
val runnable = Runnable { destinations.forEach { it.log(logRecord) } } | ||
if (Thread.currentThread().name != LOGGER_THREAD && !logService.isShutdown && !logService.isTerminated) { | ||
logService.execute(runnable) | ||
} else { | ||
runnable.run() | ||
} | ||
} | ||
|
||
fun waitUntilLoggingFinished() { | ||
try { | ||
logService.shutdown() | ||
logService.awaitTermination(30, TimeUnit.SECONDS) | ||
} catch (_: InterruptedException) { } finally | ||
{ | ||
logService = Executors.newFixedThreadPool(1, loggerFactory) | ||
} | ||
} | ||
} |
Oops, something went wrong.