Skip to content

Commit

Permalink
#81: parallelizes loading of log entries
Browse files Browse the repository at this point in the history
  • Loading branch information
rladstaetter committed May 1, 2022
1 parent 50d4a3e commit 0564e2d
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 111 deletions.
11 changes: 8 additions & 3 deletions app/src/main/scala/app/logorrr/conf/LogoRRRGlobals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import scala.jdk.CollectionConverters._
* The user can change certain values via interacting or explicitly setting values in the preferences dialog.
*/
object LogoRRRGlobals extends CanLog {

def persist(): Unit = write(LogoRRRGlobals.getSettings())

def allLogs(): Seq[LogFileSettings] = {
settings.logFileSettingsProperty.get().values.asScala.toSeq.sortWith((lt, gt) => lt.getFirstOpened() < gt.getFirstOpened()).map(_.petrify())
}


def bindWindow(window: Window): Unit = {
window.setX(LogoRRRGlobals.getStageX())
window.setY(LogoRRRGlobals.getStageY())
Expand Down Expand Up @@ -53,7 +55,7 @@ object LogoRRRGlobals extends CanLog {

def getStageY(): Double = settings.stageSettings.yProperty.get()

private val settings = new MutSettings
val settings = new MutSettings
private val hostServicesProperty = new SimpleObjectProperty[HostServices]()

def setHostServices(hostServices: HostServices): Unit = hostServicesProperty.set(hostServices)
Expand Down Expand Up @@ -93,6 +95,9 @@ object LogoRRRGlobals extends CanLog {
settings.setSomeActive(None)
}

def getLogFileSettings(pathAsString: String): MutLogFileSettings = {
settings.getLogFileSetting(pathAsString)
}

def mupdate(t: MutLogFileSettings => Unit)(pathAsString: String): Unit =
Option(settings.getLogFileSetting(pathAsString)) match {
Expand All @@ -111,10 +116,10 @@ object LogoRRRGlobals extends CanLog {

def updateDividerPosition(pathAsString: String, dividerPosition: Double): Unit = {
settings.getLogFileSetting(pathAsString).setDividerPosition(dividerPosition)
// mupdate({ lfs: MutLogFileSettings => lfs.setDividerPosition(dividerPosition) })(pathAsString)
// mupdate({ lfs: MutLogFileSettings => lfs.setDividerPosition(dividerPosition) })(pathAsString)
}

def updateLogFile( fs: LogFileSettings): Unit = {
def updateLogFile(fs: LogFileSettings): Unit = {
settings.putLogFileSetting(fs)
}

Expand Down
16 changes: 8 additions & 8 deletions app/src/main/scala/app/logorrr/conf/mut/MutLogFileSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ object MutLogFileSettings {

class MutLogFileSettings extends Petrify[LogFileSettings] {

private val pathAsStringProperty = new SimpleStringProperty()
private val firstOpenedProperty = new SimpleLongProperty()
val dividerPositionProperty = new SimpleDoubleProperty()
val filtersProperty = new SimpleListProperty[Filter](FXCollections.observableArrayList())
val someLogEntrySettings = new SimpleObjectProperty[Option[LogEntryInstantFormat]]()
val blockWidthSettingsProperty = new SimpleIntegerProperty()

def setBlockSettings(bs: BlockSettings): Unit = blockWidthSettingsProperty.set(bs.width)

def setDividerPosition(dividerPosition: Double): Unit = dividerPositionProperty.set(dividerPosition)

def getFirstOpened() : Long = firstOpenedProperty.get()

private val pathAsStringProperty = new SimpleStringProperty()
private val firstOpenedProperty = new SimpleLongProperty()
private val dividerPositionProperty = new SimpleDoubleProperty()
private val filtersProperty = new SimpleListProperty[Filter](FXCollections.observableArrayList())
private val someLogEntrySettings = new SimpleObjectProperty[Option[LogEntryInstantFormat]]()
private val blockWidthSettingsProperty = new SimpleIntegerProperty()
def getFirstOpened(): Long = firstOpenedProperty.get()

override def petrify(): LogFileSettings = LogFileSettings(pathAsStringProperty.get()
, firstOpenedProperty.get()
Expand Down
27 changes: 25 additions & 2 deletions app/src/main/scala/app/logorrr/model/LogFileSettings.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package app.logorrr.model

import app.logorrr.conf.BlockSettings
import app.logorrr.util.CanLog
import app.logorrr.views.{Filter, Fltr}
import javafx.collections.{FXCollections, ObservableList}
import javafx.scene.paint.Color
import pureconfig.generic.semiauto.{deriveReader, deriveWriter}

import java.nio.file.{Files, Path, Paths}
import java.time.Instant
import scala.util.{Failure, Success, Try}

object LogFileSettings {

Expand Down Expand Up @@ -52,10 +55,30 @@ case class LogFileSettings(pathAsString: String
, dividerPosition: Double
, filters: Seq[Filter]
, blockSettings: BlockSettings
, someLogEntrySetting: Option[LogEntryInstantFormat]) {

, someLogEntrySetting: Option[LogEntryInstantFormat]) extends CanLog {

val path: Path = Paths.get(pathAsString)

val isPathValid = Files.isReadable(path) && Files.isRegularFile(path)

def readEntries(): ObservableList[LogEntry] = {
if (isPathValid) {
Try(someLogEntrySetting match {
case Some(value) => LogEntryFileReader.from(path, filters, value)
case None => LogEntryFileReader.from(path, filters)
}) match {
case Success(logEntries) =>
logInfo(s"Opening ${pathAsString} ... ")
logEntries
case Failure(ex) =>
val msg = s"Could not import file ${pathAsString}"
logException(msg, ex)
FXCollections.observableArrayList()
}
} else {
logWarn(s"Could not read ${pathAsString} - does it exist?")
FXCollections.observableArrayList()
}
}

}
64 changes: 26 additions & 38 deletions app/src/main/scala/app/logorrr/views/LogFileTab.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,25 @@ import javafx.scene.control._
import javafx.scene.layout._
import org.apache.commons.io.input.Tailer

import java.nio.file.Paths
import java.time.Instant
import java.util.function.UnaryOperator
import java.util.stream.Collectors
import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.jdk.CollectionConverters._

object LogFileTab {

case class TimeRange(startTime: Instant, endTime: Instant)

def apply(logViewTabPane: LogoRRRMainTabPane
, logEntries: ObservableList[LogEntry]
, logFileSettings: LogFileSettings
, initFileMenu: => Unit): LogFileTab = {
val logFileTab = new LogFileTab(
logEntries
, logViewTabPane.sceneWidthProperty.get()
, logFileSettings
, initFileMenu)
def apply(pathAsString: String, logEntries: ObservableList[LogEntry], initFileMenu: => Unit): LogFileTab = {
val logFileTab = new LogFileTab(pathAsString, logEntries, initFileMenu)


/** activate invalidation listener on filtered list */
logFileTab.init()
logFileTab.sceneWidthProperty.bind(logViewTabPane.sceneWidthProperty)
logFileTab
}

Expand All @@ -63,9 +58,8 @@ trait LogTailer {
*
* @param logEntries report instance holding information of log file to be analyzed
* */
class LogFileTab(val logEntries: ObservableList[LogEntry]
, val initialSceneWidth: Int
, val initialLogFileSettings: LogFileSettings
class LogFileTab(val pathAsString: String
, val logEntries: ObservableList[LogEntry]
, initFileMenu: => Unit)
extends Tab
with LogTailer
Expand All @@ -87,13 +81,11 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]
}
}

val tailer = new Tailer(initialLogFileSettings.path.toFile, new LogEntryListener(logEntries), 1000, true)
val tailer = new Tailer(Paths.get(pathAsString).toFile, new LogEntryListener(logEntries), 1000, true)

/** list of search filters to be applied */
val filtersListProperty = new SimpleListProperty[Filter](CollectionUtils.mkEmptyObservableList())

/** bound to sceneWidthProperty of parent LogViewTabPane */
val sceneWidthProperty = new SimpleIntegerProperty(initialSceneWidth)

/** split visual view and text view */
val splitPane = new SplitPane()
Expand All @@ -109,18 +101,19 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]
fbtb
}

val settingsToolBar = new SettingsToolBar(initialLogFileSettings)
val settingsToolBar = new SettingsToolBar(pathAsString)

val opsBorderPane: OpsBorderPane = {
val op = new OpsBorderPane(searchToolBar, filtersToolBar, settingsToolBar)
op.blockSizeProperty.set(initialLogFileSettings.blockSettings.width)
op.blockSizeProperty.set(LogoRRRGlobals.getLogFileSettings(pathAsString).blockWidthSettingsProperty.get())
op
}

val initialWidth = (sceneWidth * initialLogFileSettings.dividerPosition).toInt
val initialWidth = (Bindings.multiply(LogoRRRGlobals.settings.stageSettings.widthProperty, LogoRRRGlobals.getLogFileSettings(pathAsString).dividerPositionProperty))
//val initialWidth = (sceneWidth * initialLogFileSettings.dividerPosition).toInt

private lazy val logVisualView = {
val lvv = new LogVisualView(filteredList, initialWidth)
val lvv = new LogVisualView(filteredList, initialWidth.intValue())
lvv.blockViewPane.visibleProperty().bind(selectedProperty())
// lvv.blockViewPane.blockSizeProperty.set(initialLogFileSettings.blockSettings.width)
// lvv.sisp.filtersListProperty.bind(filtersListProperty)
Expand All @@ -130,11 +123,11 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]
lazy val timings: Map[Int, Instant] =
logEntries.stream().collect(Collectors.toMap((le: LogEntry) => le.lineNumber, (le: LogEntry) => le.someInstant.getOrElse(Instant.now()))).asScala.toMap

private val logTextView = new LogTextView(filteredList, timings )
private val logTextView = new LogTextView(filteredList, timings)

val entryLabel = {
val l = new Label("")
l.prefWidthProperty.bind(sceneWidthProperty)
l.prefWidthProperty.bind(LogoRRRGlobals.settings.stageSettings.widthProperty)
l.setStyle(LogoRRRFonts.jetBrainsMono(20))
l
}
Expand All @@ -159,18 +152,15 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]

private def handleFilterChange(change: ListChangeListener.Change[_ <: Fltr]): Unit = {
while (change.next()) {
updateSettingsFile()
Future {
LogoRRRGlobals.persist()
}
updateLogEntryColors()
}
}

private def updateSettingsFile(): Unit = {
val logFileSettings = initialLogFileSettings.copy(filters = filtersListProperty.asScala.toSeq)
LogoRRRGlobals.updateLogFile(logFileSettings)
}

def init(): Unit = {
initialLogFileSettings.filters.foreach(addFilter)
filtersListProperty.bind(LogoRRRGlobals.getLogFileSettings(pathAsString).filtersProperty)

/** top component for log view */
val borderPane = new BorderPane()
Expand All @@ -181,13 +171,14 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]

logVisualView.blockViewPane.blockSizeProperty.bind(opsBorderPane.blockSizeProperty)
logVisualView.blockViewPane.blockSizeProperty.addListener(JfxUtils.onNew[Number](n => {
LogoRRRGlobals.updateBlockSettings(initialLogFileSettings.pathAsString, BlockSettings(n.intValue()))
LogoRRRGlobals.updateBlockSettings(pathAsString, BlockSettings(n.intValue()))
}))

/* change active text field depending on visible tab */
selectedProperty().addListener(JfxUtils.onNew[java.lang.Boolean](b => {
if (b) {
LogoRRRAccelerators.setActiveSearchTextField(searchToolBar.searchTextField)
JfxUtils.execOnUiThread(repaint())
} else {
}
}))
Expand All @@ -210,18 +201,18 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]
* update logVisualView
* */
splitPane.getDividers.get(0).positionProperty().addListener(JfxUtils.onNew {
t1: Number => LogoRRRGlobals.updateDividerPosition(initialLogFileSettings.pathAsString, t1.doubleValue())
t1: Number => LogoRRRGlobals.updateDividerPosition(pathAsString, t1.doubleValue())
})

startTailer()

setDivider(initialLogFileSettings.dividerPosition)
setDivider(LogoRRRGlobals.getLogFileSettings(pathAsString).dividerPositionProperty.get())
initFiltersPropertyListChangeListener()
}

/** compute title of tab */
private def computeTabTitle: StringExpression = {
Bindings.concat(initialLogFileSettings.pathAsString, " (", Bindings.size(logEntries).asString, " lines)")
Bindings.concat(pathAsString, " (", Bindings.size(logEntries).asString, " lines)")
}

/**
Expand All @@ -238,13 +229,10 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]
}

def shutdown(): Unit = {
LogoRRRGlobals.removeLogFile(initialLogFileSettings.pathAsString)
LogoRRRGlobals.removeLogFile(pathAsString)
stopTailer()
}

def sceneWidth = sceneWidthProperty.get()


def updateEntryLabel(logEntry: LogEntry): Unit = {
Option(logEntry) match {
case Some(entry) =>
Expand All @@ -271,7 +259,7 @@ class LogFileTab(val logEntries: ObservableList[LogEntry]
if (w != 0.0) {
w
} else {
initialWidth
initialWidth.doubleValue()
}
}

Expand Down
32 changes: 7 additions & 25 deletions app/src/main/scala/app/logorrr/views/LogoRRRMainTabPane.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import javafx.beans.property.SimpleIntegerProperty
import javafx.collections.ObservableList
import javafx.scene.control.{Tab, TabPane}

import java.nio.file.Path
import java.nio.file.{Files, Path, Paths}
import scala.collection.mutable
import scala.jdk.CollectionConverters._
import scala.util.{Failure, Success, Try}
Expand Down Expand Up @@ -52,8 +52,8 @@ class LogoRRRMainTabPane(initFileMenu: => Unit)
t1: Tab =>
t1 match {
case logFileTab: LogFileTab =>
logTrace("Selected: " + logFileTab.initialLogFileSettings.path)
LogoRRRGlobals.setSomeActive(Option(logFileTab.initialLogFileSettings.pathAsString))
logTrace("Selected: " + logFileTab.pathAsString)
LogoRRRGlobals.setSomeActive(Option(logFileTab.pathAsString))
// to set 'selected' property in Tab and to trigger repaint correctly (see issue #9)
getSelectionModel.select(logFileTab)
logFileTab.repaint()
Expand All @@ -62,13 +62,12 @@ class LogoRRRMainTabPane(initFileMenu: => Unit)
})
}

def add(logEntries: ObservableList[LogEntry]
, logFileSettings: LogFileSettings): Unit = {
val tab = LogFileTab(this, logEntries, logFileSettings, initFileMenu)
def add(pathAsString: String, logEntries: ObservableList[LogEntry]): Unit = {
val tab = LogFileTab(pathAsString, logEntries, initFileMenu)
getTabs.add(tab)
}

def contains(p: String): Boolean = getLogFileTabs.exists(lr => lr.initialLogFileSettings.pathAsString == p)
def contains(p: String): Boolean = getLogFileTabs.exists(lr => lr.pathAsString == p)

private def getLogFileTabs: mutable.Seq[LogFileTab] = getTabs.asScala.flatMap {
t =>
Expand All @@ -85,7 +84,7 @@ class LogoRRRMainTabPane(initFileMenu: => Unit)
}

def selectLog(pathAsString: String): Unit = {
getLogFileTabs.find(_.initialLogFileSettings.pathAsString == pathAsString) match {
getLogFileTabs.find(_.pathAsString == pathAsString) match {
case Some(value) =>
logTrace(s"Selects tab view with path ${pathAsString}.")
getSelectionModel.select(value)
Expand All @@ -97,21 +96,4 @@ class LogoRRRMainTabPane(initFileMenu: => Unit)

def selectLastLogFile(): Unit = getSelectionModel.selectLast() // select last added file repaint it on selection

def addLogFile(logFileSettings: LogFileSettings): Unit = {
if (logFileSettings.isPathValid) {
Try(logFileSettings.someLogEntrySetting match {
case Some(value) => LogEntryFileReader.from(logFileSettings.path, logFileSettings.filters, value)
case None => LogEntryFileReader.from(logFileSettings.path, logFileSettings.filters)
}) match {
case Success(logEntries) =>
logInfo(s"Opening ${logFileSettings.path.toAbsolutePath.toString} ... ")
add(logEntries, logFileSettings)
case Failure(ex) =>
val msg = s"Could not import file ${logFileSettings.path.toAbsolutePath}"
logException(msg, ex)
}
} else {
logWarn(s"Could not read ${logFileSettings.path.toAbsolutePath} - does it exist?")
}
}
}
3 changes: 2 additions & 1 deletion app/src/main/scala/app/logorrr/views/OpsBorderPane.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class OpsBorderPane(searchToolBar: SearchToolBar

val stepSize = 4

override val blockSizeProperty: SimpleIntegerProperty = new SimpleIntegerProperty(stepSize)
override val blockSizeProperty: SimpleIntegerProperty = new SimpleIntegerProperty()

val items: Seq[Control] = {
val smallerBtn =
new RectButton(2 * stepSize, 2 * stepSize, Color.GRAY,
Expand Down
Loading

0 comments on commit 0564e2d

Please sign in to comment.