Skip to content

Commit

Permalink
port over Dartzee logger, gitignore some stupid stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
alyssaruth committed Nov 21, 2023
1 parent 3f2db28 commit 1d79bf6
Show file tree
Hide file tree
Showing 22 changed files with 712 additions and 29 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@

# Ignore Gradle build output directory
build

Replays
*UsedKeys.txt
22 changes: 5 additions & 17 deletions client/src/main/java/EntropyMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,11 @@
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.WindowConstants;

import object.EntropyClientDebugExtension;
import logging.LoggerUncaughtExceptionHandler;
import online.util.DesktopEntropyClient;
import screen.MainScreen;
import screen.ScreenCache;
import util.AbstractClient;
import util.Debug;
import util.DebugUncaughtExceptionHandler;
import util.DialogUtil;
import util.EncryptionUtil;
import util.OnlineConstants;
import util.Registry;
import util.*;

public class EntropyMain implements Registry
{
Expand All @@ -27,17 +21,13 @@ public static void main(String[] args)
try
{
//Initialise interfaces etc
Debug.initialise(ScreenCache.getDebugConsole());
Thread.setDefaultUncaughtExceptionHandler(new LoggerUncaughtExceptionHandler());
MainUtilKt.setLoggingContextFields();
AbstractClient.setInstance(new DesktopEntropyClient());

//Dev mode
AbstractClient.parseProgramArguments(args);

//Set Debug variables
Debug.setProductDesc("Entropy " + OnlineConstants.ENTROPY_VERSION_NUMBER);
Debug.setDebugExtension(new EntropyClientDebugExtension());
Debug.setLogToSystemOut(AbstractClient.devMode);

setLookAndFeel();

if (AbstractClient.devMode)
Expand All @@ -62,16 +52,14 @@ else if (!bindOnPort(BIND_PORT_NUMBER))
application.setVisible(true);
application.setLocationRelativeTo(null);
application.setResizable(false);

Thread.setDefaultUncaughtExceptionHandler(new DebugUncaughtExceptionHandler());
application.onStart();
}
catch (Throwable t)
{
Debug.stackTrace(t);
}
}

private static void setLookAndFeel()
{
AbstractClient.setOs();
Expand Down
12 changes: 0 additions & 12 deletions client/src/main/java/util/MainUtil.java

This file was deleted.

26 changes: 26 additions & 0 deletions client/src/main/kotlin/MainUtil.kt
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
}
1 change: 1 addition & 0 deletions core/src/main/java/util/CoreRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ public interface CoreRegistry
public static final String INSTANCE_STRING_USER_NAME = "userName";
public static final String INSTANCE_BOOLEAN_ENABLE_EMAILS = "enableEmails";
public static final String INSTANCE_INT_REPLAY_CONVERSION = "replayConversion";
public static final String INSTANCE_STRING_DEVICE_ID = "deviceId";
}
22 changes: 22 additions & 0 deletions core/src/main/kotlin/bean/FocusableWindow.kt
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?) {}
}
117 changes: 117 additions & 0 deletions core/src/main/kotlin/bean/WrapLayout.kt
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
}
}
6 changes: 6 additions & 0 deletions core/src/main/kotlin/logging/ILogDestination.kt
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?>)
}
11 changes: 11 additions & 0 deletions core/src/main/kotlin/logging/LogDestinationSystemOut.kt
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?>) {}
}
34 changes: 34 additions & 0 deletions core/src/main/kotlin/logging/LogRecord.kt
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)}" }
}
72 changes: 72 additions & 0 deletions core/src/main/kotlin/logging/Logger.kt
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)
}
}
}
Loading

0 comments on commit 1d79bf6

Please sign in to comment.