Swing Log Appender

时间:2013-04-10 12:41:29

标签: java swing logging slf4j logback

我正在尝试按需向我的Swing应用程序的用户显示日志内容。显示日志事件列表,可能允许他们查看有关日志消息的详细信息,理想情况下与日食“错误日志”视图显示的内容类似。

是否有任何预制的日志显示组件/日志追加器?

我意识到我可以轻松地将字符串值附加到Textarea但是如果可能的话我会更喜欢“免费”(搜索,按事件过滤,按记录器过滤,导出等)

我目前正在使用SLF4J进行回溯,但是如果存在这样的组件,我在切换到另一个日志框架时没有任何问题。

2 个答案:

答案 0 :(得分:1)

我抓住了这个。虽然这对我来说是一次教学练习,而且 非常接近完全可用,还有一些缺少的必需品。 也许有人可以帮助完成最后的工作。

背景

这是一个更大的工作应用程序的一部分,所以虽然我只是 发布与此问题相关的代码,有一些工件 应用程序。代码在Scala中,但降级到Java应该 直截了当。我不包括大多数import指令; 希望很清楚我指的是哪些课程。一世 相信只有两个具有冲突的简单类名的类是 scala.swing.Componentjava.awt.Component

概述

代码存在于以下文件中:

  • Main.scala具有创建日志窗口的代码。
  • LogFrame是显示日志条目的swing窗口
  • LogModel存储日志记录数据
  • AbstractBaseTableModelLogModel的超类以及 我的应用程序中的另一个类未在此处显示。
  • TableAppender.scala是将Swing连接到Logback的内容。
  • 格式化时间戳的单行方法在我的包对象中,因为它 在我的应用程序的其他地方使用。
  • logback.xml有一行激活我的新appender

代码

Main.scala中,显示日志输出的Frame 可见:

object Main extends swing.SwingApplication {
  override def startup(args: Array[String]) {
    val logFrame = LogFrame
    if (logFrame.size == new Dimension(0,0)) logFrame.pack()
    logFrame.visible = true
  }
}

LogFrame单例对象在LogFrame.scala

中定义
object LogFrame extends Frame {
  title = "Log"
  iconImage = new ImageIcon("log.png").getImage
  preferredSize = new Dimension(1200,370)

  object LogTable extends Table {
    model = LogModel
    Map(0 -> 50, 1 -> 32, 4 -> 400) foreach { m =>
      peer.getColumnModel getColumn m._1 setPreferredWidth m._2
    }

    override def rendererComponent(
      isSelected: Boolean, focused: Boolean, row: Int, column: Int
    ) = {
      val v = model.getValueAt(
        peer.convertRowIndexToModel(row), 
        peer.convertColumnIndexToModel(column)
      ).toString
      TableCellRenderer.componentFor(this, isSelected, focused, v, row, column)
    }

    import ch.qos.logback.classic.Level.{ERROR,WARN}
    object TableCellRenderer extends AbstractRenderer[String, TextArea](new TextArea {
      lineWrap = true; wordWrap = true
    }) {
      val brown = new java.awt.Color(143,112,0)
      def configure(t: Table, sel: Boolean, foc: Boolean, s: String, row: Int, col: Int) = {
        component.text = s
        model.getValueAt(
          LogTable.this.peer.convertRowIndexToModel(row),
          LogModel.columnNames.indexOf("Level")
        ) match {
          case ERROR => component.foreground = java.awt.Color.RED
          case WARN => component.foreground = brown
          case _ =>
        }
      }
    }
  }

  contents = new BoxPanel(Vertical) {
    contents += new ScrollPane { viewportView = LogTable }
  }

  def logEvent(event: ILoggingEvent) {
    event +=: LogModel
  }

}

LogModel单身人士在LogModel.scala

object LogModel extends AbstractBaseTableModel {

  final val columnNames = Array("Time","Level","Thread","Logger","Message")

  val data = ListBuffer[Array[AnyRef]]()

  def +=:(event: ILoggingEvent) {
    Array[AnyRef](
      formatTimeStamp(event.getTimeStamp),
      event.getLevel,
      event.getThreadName,
      event.getLoggerName.replaceFirst(".*\\.",""),
      event.getFormattedMessage
    ) +=: data
    fireTableChanged( new TableModelEvent(this) )
  }
}

我的包对象中的这两行定义了 formatTimeStamp()方法:

final val isoFormatter = org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis
def formatTimeStamp(millis: Long)      = isoFormatter.print(millis)

LogModel延伸AbstractBaseTableModel的原因是因为我 应用程序有一些其他表格模型,一次更新, 而不是像日志记录模型那样的一行。从而 AbstractBaseTableModel的{​​{1}}成员类型为data 子类可以使用不可变的SeqLike或可变的 根据需要List

ListBuffer

import scala.collection.SeqLike abstract class AbstractBaseTableModel extends AbstractTableModel { val columnNames: Array[String] val data: SeqLike[Array[AnyRef],_] def getRowCount: Int = data.size def getColumnCount: Int = columnNames.size override def getColumnName(column: Int) = columnNames(column) override def getValueAt(row: Int, column: Int): AnyRef = data(row)(column) override def isCellEditable(row: Int, col: Int) = false override def getColumnClass(columnIndex: Int): Class[_] = getValueAt(0, columnIndex).getClass } 文件很小:

TableAppender.scala

最后,对class TableAppender extends AppenderBase[ILoggingEvent] { def append(event: ILoggingEvent) { LogFrame.logEvent(event) } } 文件的更改甚至更小:

logback.xml

问题

唯一阻止我决定这个问题的问题 比老式的日志文件更好:

1)因为我已经覆盖了<appender name="swingTable" class="mypackage.TableAppender"/> Table.rendererComponent()无法正常工作。

2)我还没弄明白如何让包裹的线条可见 桌子。我所知道的是,我必须增加高度 行。

如果这些问题得到解决,接下来就要补充一下 根据日志级别和记录器名称进行实时过滤。就这样 是的,我现在至少要把它放在一边,但如果有的话 有什么建议,我有兴趣听听他们。

参考

以下资源对我构成前述内容有用 代码,或者在解决剩余问题时可能有用:

答案 1 :(得分:0)

我会看SwingX。它在这个页面有一个很好的演示。以JXTable为例。