Skip to content

Commit

Permalink
#43: combines timestamp filter with text filters
Browse files Browse the repository at this point in the history
  • Loading branch information
rladstaetter committed Aug 12, 2024
1 parent bdc88c9 commit 8f9c6bc
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 84 deletions.
61 changes: 54 additions & 7 deletions app/src/main/scala/app/logorrr/conf/mut/MutLogFileSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package app.logorrr.conf.mut

import app.logorrr.conf.BlockSettings
import app.logorrr.io.FileId
import app.logorrr.model.{LogFileSettings, TimestampSettings}
import app.logorrr.model.{LogEntry, LogFileSettings, TimestampSettings}
import app.logorrr.util.LogoRRRFonts
import app.logorrr.views.search.Filter
import app.logorrr.views.search.{AnyFilter, Filter, FilterButton, Fltr}
import javafx.beans.binding.{BooleanBinding, StringBinding}
import javafx.beans.property._
import javafx.collections.transformation.FilteredList
import javafx.collections.{FXCollections, ObservableList}

import java.time.format.DateTimeFormatter
Expand All @@ -29,13 +30,46 @@ object MutLogFileSettings {
case None =>
}
s.setAutoScroll(logFileSettings.autoScroll)
s.setLowerTimestamp(logFileSettings.lowerTimestamp)
s.setUpperTimestamp(logFileSettings.upperTimestamp)
s
}
}


class MutLogFileSettings {

var someUnclassifiedFilter: Option[(Filter, FilterButton)] = None
var filterButtons: Map[Filter, FilterButton] = Map[Filter, FilterButton]()

/**
* Filters are only active if selected.
*
* UnclassifiedFilter gets an extra handling since it depends on other filters
*
* @return
*/
def computeCurrentFilter(): Fltr = {
new AnyFilter(someUnclassifiedFilter.map(fst => if (fst._2.isSelected) Set(fst._1) else Set()).getOrElse(Set()) ++
filterButtons.filter(fst => fst._2.isSelected).keySet)
}

/**
* Reduce current displayed log entries by applying text filters and consider also the time stamp range.
*
* @param filteredList list to filter
*/
def updateActiveFilter(filteredList: FilteredList[LogEntry]): Unit = {
filteredList.setPredicate((entry: LogEntry) =>
(entry.someInstant match {
case None => true // if instant is not set, return true
case Some(value) =>
val asMilli = value.toEpochMilli
getLowTimestampBoundary <= asMilli && asMilli <= getHighTimestampBoundary
}) && computeCurrentFilter().matches(entry.value))
}


private val fileIdProperty = new SimpleObjectProperty[FileId]()
private val firstOpenedProperty = new SimpleLongProperty()
private val someTimestampSettings = new SimpleObjectProperty[Option[TimestampSettings]](None)
Expand All @@ -46,21 +80,32 @@ class MutLogFileSettings {
val selectedLineNumberProperty = new SimpleIntegerProperty()
val firstVisibleTextCellIndexProperty = new SimpleIntegerProperty()
val lastVisibleTextCellIndexProperty = new SimpleIntegerProperty()
private val lowerTimestampProperty = new SimpleLongProperty(LogFileSettings.DefaultLowerTimestamp)
private val upperTimestampProperty = new SimpleLongProperty(LogFileSettings.DefaultUpperTimestamp)

def setLowerTimestamp(lowerValue: Long): Unit = lowerTimestampProperty.set(lowerValue)

def getLowTimestampBoundary: Long = lowerTimestampProperty.get()

def setUpperTimestamp(upperValue: Long): Unit = upperTimestampProperty.set(upperValue)

def getHighTimestampBoundary: Long = upperTimestampProperty.get()

val dividerPositionProperty = new SimpleDoubleProperty()
val autoScrollActiveProperty = new SimpleBooleanProperty()
val filtersProperty = new SimpleListProperty[Filter](FXCollections.observableArrayList())

def getSomeTimestampSettings(): Option[TimestampSettings] = someTimestampSettings.get()
def getSomeTimestampSettings: Option[TimestampSettings] = someTimestampSettings.get()

def getDateTimeFormatter(): DateTimeFormatter = dateTimeFormatterProperty.get()
def getDateTimeFormatter: DateTimeFormatter = dateTimeFormatterProperty.get()

def setDateTimeFormatter(dateTimeFormatter: DateTimeFormatter): Unit = dateTimeFormatterProperty.set(dateTimeFormatter)

def setFilters(filters: Seq[Filter]): Unit = {
filtersProperty.setAll(filters.asJava)
}

def getFilters(): ObservableList[Filter] = filtersProperty.get()
def getFilters: ObservableList[Filter] = filtersProperty.get()


val hasLogEntrySettingBinding: BooleanBinding = new BooleanBinding {
Expand Down Expand Up @@ -120,12 +165,14 @@ class MutLogFileSettings {
, firstOpenedProperty.get()
, dividerPositionProperty.get()
, fontSizeProperty.get()
, getFilters().asScala.toSeq
, getFilters.asScala.toSeq
, BlockSettings(blockSizeProperty.get())
, someTimestampSettings.get()
, autoScrollActiveProperty.get()
, firstVisibleTextCellIndexProperty.get()
, lastVisibleTextCellIndexProperty.get())
, lastVisibleTextCellIndexProperty.get()
, lowerTimestampProperty.get()
, upperTimestampProperty.get())
lfs
}
}
Expand Down
12 changes: 9 additions & 3 deletions app/src/main/scala/app/logorrr/model/LogFileSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ object LogFileSettings {
private val DefaultAutoScroll = false
private val DefaultFirstViewIndex = -1
private val DefaultLastViewIndex = -1
val DefaultLowerTimestamp: Int = 0
val DefaultUpperTimestamp: Long = Instant.now().toEpochMilli
private val FinestFilter: Filter = new Filter("FINEST", Color.GREY, true)
private val InfoFilter: Filter = new Filter("INFO", Color.GREEN, true)
private val WarningFilter: Filter = new Filter("WARNING", Color.ORANGE, true)
Expand All @@ -41,7 +43,9 @@ object LogFileSettings {
, DefaultLogFormat
, DefaultAutoScroll
, DefaultFirstViewIndex
, DefaultLastViewIndex)
, DefaultLastViewIndex
, DefaultLowerTimestamp
, Instant.now().toEpochMilli)
}

}
Expand All @@ -62,7 +66,7 @@ object LogFileSettings {
* @param fontSize font size to use
* @param filters filters which should be applied
* @param blockSettings settings for the left view
* @param someTimestampSettings used timestamp format
* @param someTimestampSettings used timestamp format
* @param autoScroll true if 'follow mode' is active
* @param firstVisibleTextCellIndex which index is the first visible on the screen (depending on resolution, window size ...)
* @param lastVisibleTextCellIndex which index is the last visible on the screen (depending on resolution, window size ...)
Expand All @@ -77,7 +81,9 @@ case class LogFileSettings(fileId: FileId
, someTimestampSettings: Option[TimestampSettings]
, autoScroll: Boolean
, firstVisibleTextCellIndex: Int
, lastVisibleTextCellIndex: Int) {
, lastVisibleTextCellIndex: Int
, lowerTimestamp: Long
, upperTimestamp: Long) {

val path: Path = fileId.asPath.toAbsolutePath

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import scala.util.{Failure, Success, Try}

object TimestampSettings extends CanLog {

val DefaultPattern = "yyyy-MM-dd HH:mm:ss.nnnnnnnnn"
val DefaultPattern = "yyyy-MM-dd HH:mm:ss.SSS"
/** just my preferred time format */
val Default: TimestampSettings = TimestampSettings(SimpleRange(1, 24), DefaultPattern)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class LogFileTab(val fileId: FileId

private lazy val logTailer = LogTailer(fileId, entries)

val logFileTabContent = new LogFileTabContent(fileId, mutLogFileSettings, entries)
val logFileTabContent = new LogFileTabContent(mutLogFileSettings, entries)

private def startTailer(): Unit = {
logFileTabContent.addTailerListener()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package app.logorrr.views.logfiletab

import app.logorrr.conf.mut.MutLogFileSettings
import app.logorrr.io.FileId
import app.logorrr.model.LogEntry
import app.logorrr.views.block.ChunkListView
import app.logorrr.views.ops.OpsRegion
Expand All @@ -15,8 +14,7 @@ import javafx.scene.control.SplitPane
import javafx.scene.layout.{BorderPane, VBox}


class LogFileTabContent(fileId: FileId
, mutLogFileSettings: MutLogFileSettings
class LogFileTabContent(mutLogFileSettings: MutLogFileSettings
, val entries: ObservableList[LogEntry]) extends BorderPane {

// make sure we have a white background for our tabs - see https://github.com/rladstaetter/LogoRRR/issues/188
Expand Down Expand Up @@ -64,7 +62,7 @@ class LogFileTabContent(fileId: FileId
, mutLogFileSettings.blockSizeProperty)

private val filtersToolBar = {
val fbtb = new FiltersToolBar(fileId, filteredList, removeFilter)
val fbtb = new FiltersToolBar(mutLogFileSettings, filteredList, removeFilter)
fbtb.filtersProperty.bind(mutLogFileSettings.filtersProperty)
fbtb
}
Expand Down
35 changes: 14 additions & 21 deletions app/src/main/scala/app/logorrr/views/ops/time/TimeOpsToolBar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,6 @@ import javafx.collections.ObservableList
import javafx.collections.transformation.FilteredList
import javafx.scene.control.ToolBar

object TimeOpsToolBar {
private def updateFilteredList(mutLogFileSettings: MutLogFileSettings, filteredList: FilteredList[LogEntry], lower: Long, higher: Long): Unit = {
//mutLogFileSettings.filtersProperty
// use filters and also this filter
mutLogFileSettings == mutLogFileSettings
filteredList.setPredicate((t: LogEntry) => {
t.someInstant match {
case Some(value) =>
val asMilli = value.toEpochMilli
lower <= asMilli && asMilli <= higher
case None => false
}
})
}
}


class TimeOpsToolBar(mutLogFileSettings: MutLogFileSettings
, chunkListView: ChunkListView
Expand All @@ -40,26 +24,35 @@ class TimeOpsToolBar(mutLogFileSettings: MutLogFileSettings
/**
* To configure the logformat of the timestamp used in a logfile
*/
private val timestampSettingsButton = new TimestampSettingsButton(mutLogFileSettings, chunkListView, logEntries)
private val timestampSettingsButton = new TimestampSettingsButton(mutLogFileSettings, chunkListView, logEntries, this)

lowSlider.setValue(lowSlider.getMin)
highSlider.setValue(highSlider.getMax)

lowSlider.valueProperty.addListener((_, _, newValue) => {
if (newValue.doubleValue > highSlider.getValue) lowSlider.setValue(highSlider.getValue)
TimeOpsToolBar.updateFilteredList(mutLogFileSettings, filteredList, newValue.longValue(), highSlider.getValue.longValue)
val lowValue = newValue.longValue()
val highValue = highSlider.getValue.longValue
mutLogFileSettings.setLowerTimestamp(lowValue)
mutLogFileSettings.setUpperTimestamp(highValue)
mutLogFileSettings.updateActiveFilter(filteredList)
// TimeOpsToolBar.updateFilteredList(mutLogFileSettings, filteredList, lowValue, highValue)
})

highSlider.valueProperty.addListener((_, _, newValue) => {
if (newValue.doubleValue < lowSlider.getValue) highSlider.setValue(lowSlider.getValue)
TimeOpsToolBar.updateFilteredList(mutLogFileSettings, filteredList, lowSlider.getValue.longValue, newValue.longValue())
val lowValue = lowSlider.getValue.longValue
val highValue = newValue.longValue()
mutLogFileSettings.setLowerTimestamp(lowValue)
mutLogFileSettings.setUpperTimestamp(highValue)
mutLogFileSettings.updateActiveFilter(filteredList)
})

getItems.addAll(Seq(timestampSettingsButton, leftLabel, lowSlider, highSlider, rightLabel): _*)

updateSliderBoundaries()

private def updateSliderBoundaries(): Unit = {
def updateSliderBoundaries(): Unit = {
TimerSlider.calculateBoundaries(filteredList) match {
case Some((minInstant, maxInstant)) =>
lowSlider.setMin(minInstant.toEpochMilli.doubleValue())
Expand All @@ -68,7 +61,7 @@ class TimeOpsToolBar(mutLogFileSettings: MutLogFileSettings
highSlider.setMax(maxInstant.toEpochMilli.doubleValue())
lowSlider.setValue(lowSlider.getMin)
highSlider.setValue(highSlider.getMax)
//println("set" + minInstant + "/" + maxInstant)
println("set" + minInstant + "/" + maxInstant)
case None => //println("none")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import org.kordamp.ikonli.javafx.FontIcon
*/
class TimestampSettingsButton(settings: MutLogFileSettings
, chunkListView: ChunkListView
, logEntries: ObservableList[LogEntry]) extends StackPane {
, logEntries: ObservableList[LogEntry]
, timeOpsToolBar: TimeOpsToolBar) extends StackPane {

// since timerbutton is a stackpane, this css commands are necessary to have the same effect as
// defined in primer-light.css
Expand All @@ -36,7 +37,7 @@ class TimestampSettingsButton(settings: MutLogFileSettings
|""".stripMargin)
btn.setGraphic(new FontIcon(FontAwesomeRegular.CLOCK))
btn.setTooltip(new Tooltip("configure time format"))
btn.setOnAction(_ => new TimestampSettingStage(settings, chunkListView, logEntries).showAndWait())
btn.setOnAction(_ => new TimestampSettingStage(settings, chunkListView, logEntries, timeOpsToolBar).showAndWait())
btn
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import javafx.scene.control.{Label, Slider}
class TimestampSliderLabel(mutLogFileSettings: MutLogFileSettings
, slider: Slider) extends Label {
textProperty().bind(Bindings.createStringBinding(() => {
TimerSlider.format(slider.getValue.longValue(), mutLogFileSettings.getDateTimeFormatter())
TimerSlider.format(slider.getValue.longValue(), mutLogFileSettings.getDateTimeFormatter)
}, slider.valueProperty))
visibleProperty().bind(mutLogFileSettings.hasLogEntrySettingBinding)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ object FilterButton extends UiNodeFilterAware {
class FilterButton(val fileId: FileId
, val filter: Filter
, i: Int
, updateActiveFilter: () => Unit
, updateActiveFilter: => Unit
, removeFilter: Filter => Unit) extends ToggleButton(filter.pattern) with CanLog {

setId(FilterButton.uiNode(fileId, filter).value)
Expand All @@ -33,9 +33,8 @@ class FilterButton(val fileId: FileId
selectedProperty().addListener(new InvalidationListener {
// if any of the buttons changes its selected value, reevaluate predicate
// and thus change contents of all views which display filtered List
override def invalidated(observable: Observable): Unit = {
updateActiveFilter()
}
override def invalidated(observable: Observable): Unit = updateActiveFilter

})

def isUnclassified: Boolean = filter.isInstanceOf[UnclassifiedFilter]
Expand Down
Loading

0 comments on commit 8f9c6bc

Please sign in to comment.