2014-01-31 57 views
0

我正在尋找log4j2中的一個簡單方法來將日誌追加到textArea。將log4j2輸出附加到TextArea

在log4j中,這可以通過擴展AppenderSkeleton類來實現,但我在log4j2中找不到類似的機制。

此外,

System.setOut(myPrintStream); 

轉引系統輸出也不起作用。

有沒有可能讓這個與log4j2一起工作?

+0

[AbstractAppender](http://logging.apache.org/log4j/2.0/log4j-core/apidocs/org/apache/logging/log4j/core/appender/AbstractAppender.html )看起來相當於[AppenderSkeleton](http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/AppenderSkeleton.html) – vanOekel

回答

0

它看起來像你正在嘗試做一些與此類似:https://issues.apache.org/jira/browse/LOG4J2-303

那吉拉票有部分解決方案。您可以查看ConsoleAppender的代碼以瞭解如何創建自定義appender。

您可以配置自定義的appender在log4j2.xml就像配置元素的內置附加目的地,但你需要在包來指定插件的包屬性(這樣log4j2插件管理能找到你的插件。)

5

答案很晚,但我終於找到了解決問題的辦法。 要將一個log4j2控制檯流附加到JavaFX TextArea,ListView或類似的控件,甚至是一個揮杆控制都是可能的。我的解決方案還將標準System.out附加到記錄器視圖。看看你自己。

起初,我告訴你的截圖我現在的結果(對不起,我不能在這裏直接包含它,因爲我已經在計算器...沒有足夠的信譽與我的用戶帳戶): View the screenshot

第1步:編輯您log4j2.xml文件,並添加屬性遵循=「真」:

<?xml version="1.0" encoding="UTF-8"?> 
<Configuration status="WARN"> 
<Appenders> 
    <Console name="STDOUT" target="SYSTEM_OUT" follow="true"> 
     <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" /> 
    </Console> 
</Appenders> 
<Loggers> 
    <Root level="DEBUG"> 
     <AppenderRef ref="STDOUT" /> 
    </Root> 
</Loggers> 
</Configuration> 

第2步:寫一個類,它的用途是將SYSTEM_OUT追加到所需的視覺控制

對於我的例子,我編寫了一個小的UI控件組成,如截圖所示。因此需要一個FXML,對於FXML和另外一個LogStringCell的控制器,它提供了顏色格式(這是沒有必要螺母好的噱頭)

LoggerConsole.fxml

<?import java.lang.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 
<?import javafx.scene.layout.AnchorPane?> 

<VBox prefHeight="200.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tuc.plentyfx.configurator.views.LoggerConsoleController"> 
    <children> 
     <ListView fx:id="listViewLog" /> 
     <ToolBar prefHeight="40.0" prefWidth="200.0"> 
     <items> 
      <Button mnemonicParsing="false" onAction="#handleRemoveSelected" text="Selektierte löschen" /> 
      <Button fx:id="buttonClearLog" mnemonicParsing="false" onAction="#handleClearLog" text="Leeren" /> 
      <ToggleButton fx:id="toggleButtonAutoScroll" mnemonicParsing="false" text="Auto-Scroll" /> 
      <ChoiceBox fx:id="choiceBoxLogLevel" prefWidth="150.0" /> 
     </items> 
     </ToolBar> 
    </children> 
</VBox> 

控制器類LoggerConsoleController.java

package tuc.plentyfx.configurator.views; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PipedInputStream; 
import java.io.PipedOutputStream; 
import java.io.PrintStream; 

import javafx.application.Platform; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.concurrent.Task; 
import javafx.fxml.FXML; 
import javafx.scene.control.ChoiceBox; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.ListView; 
import javafx.scene.control.SelectionMode; 
import javafx.scene.control.ToggleButton; 
import javafx.util.Callback; 

import org.apache.logging.log4j.Level; 
import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 
import org.apache.logging.log4j.core.LoggerContext; 
import org.apache.logging.log4j.core.config.Configuration; 
import org.apache.logging.log4j.core.config.LoggerConfig; 

import tuc.plentyfx.common.LogStringCell; 

public class LoggerConsoleController { 
    static final Logger logger = LogManager.getLogger(LoggerConsoleController.class.getName()); 

    @FXML 
    private ListView<String> listViewLog; 

    @FXML 
    private ToggleButton toggleButtonAutoScroll; 

    @FXML 
    private ChoiceBox<Level> choiceBoxLogLevel; 

    @FXML 
    void handleRemoveSelected() { 
     listViewLog.getItems().removeAll(listViewLog.getSelectionModel().getSelectedItems()); 
    } 

    @FXML 
    void handleClearLog() { 
     listViewLog.getItems().clear(); 
    } 

    @FXML 
    void initialize() { 
     listViewLog.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 
     LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); 
     Configuration loggerConfiguration = loggerContext.getConfiguration(); 
     LoggerConfig loggerConfig = loggerConfiguration.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); 
     /* ChoiceBox füllen */ 
     for (Level level : Level.values()) { 
      choiceBoxLogLevel.getItems().add(level); 
     } 
     /* Aktuellen LogLevel in der ChoiceBox als Auswahl setzen */ 
     choiceBoxLogLevel.getSelectionModel().select(loggerConfig.getLevel()); 
     choiceBoxLogLevel.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Level>() { 
      @Override 
      public void changed(ObservableValue<? extends Level> arg0, Level oldLevel, Level newLevel) { 
       loggerConfig.setLevel(newLevel); 
       loggerContext.updateLoggers(); // übernehme aktuellen LogLevel 
      } 
     }); 

     listViewLog.setCellFactory(new Callback<ListView<String>, ListCell<String>>() { 
      @Override 
      public ListCell<String> call(ListView<String> listView) { 
       return new LogStringCell(); 
      } 
     }); 

     /* den Origial System.out Stream in die ListView umleiten */ 
     PipedOutputStream pOut = new PipedOutputStream(); 
     System.setOut(new PrintStream(pOut)); 
     PipedInputStream pIn = null; 
     try { 
      pIn = new PipedInputStream(pOut); 
     } 
     catch (IOException e) { 
      e.printStackTrace(); 
     } 
     BufferedReader reader = new BufferedReader(new InputStreamReader(pIn)); 

     Task<Void> task = new Task<Void>() { 
      @Override 
      protected Void call() throws Exception { 
       while (!isCancelled()) { 
        try { 
         String line = reader.readLine(); 
         if (line != null) { 
          Platform.runLater(new Runnable() { 
           @Override 
           public void run() { 
            listViewLog.getItems().add(line); 

            /* Auto-Scroll + Select */ 
            if (toggleButtonAutoScroll.selectedProperty().get()) { 
             listViewLog.scrollTo(listViewLog.getItems().size() - 1); 
             listViewLog.getSelectionModel().select(listViewLog.getItems().size() - 1); 
            } 
           } 
          }); 
         } 
        } 
        catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 
       return null; 
      } 
     }; 
     Thread thread = new Thread(task); 
     thread.setDaemon(true); 
     thread.start(); 
    } 
} 

LogStringCell.class

package tuc.plentyfx.common; 

import javafx.scene.control.ListCell; 
import javafx.scene.layout.FlowPane; 
import javafx.scene.text.Text; 

public class LogStringCell extends ListCell<String> { 

    @Override 
    protected void updateItem(String string, boolean empty) { 
     super.updateItem(string, empty); 
     if (string != null && !isEmpty()) { 
      setGraphic(createAssembledFlowPane(string)); 
     } 
     else { 
      setGraphic(null); 
      setText(null); 
     } 
    } 

    /* Erzeuge ein FlowPane mit gefüllten Textbausteien */ 
    private FlowPane createAssembledFlowPane(String... messageTokens) { 
     FlowPane flow = new FlowPane(); 
     for (String token : messageTokens) { 
      Text text = new Text(token); 

      if (text.toString().contains(" TRACE ")) { 
       text.setStyle("-fx-fill: #0000FF"); 
      } 
      if (text.toString().contains(" ALL ")) { 
       text.setStyle("-fx-fill: #FF00FF"); 
      } 
      if (text.toString().contains(" ERROR ")) { 
       text.setStyle("-fx-fill: #FF8080"); 
      } 
      if (text.toString().contains(" INFO ")) { 
       text.setStyle("-fx-fill: #000000"); 
      } 
      if (text.toString().contains(" FATAL ")) { 
       text.setStyle("-fx-fill: #FF0000"); 
      } 
      if (text.toString().contains(" DEBUG ")) { 
       text.setStyle("-fx-fill: #808080"); 
      } 
      if (text.toString().contains(" OFF ")) { 
       text.setStyle("-fx-fill: #8040FF"); 
      } 
      if (text.toString().contains(" WARN ")) { 
       text.setStyle("-fx-fill: #FF8000"); 
      } 

      flow.getChildren().add(text); 
     } 
     return flow; 
    } 
} 

第3步:用它在你的應用程序。完成...!

問題/創意/限制: 與線程使用它時,目前有一些問題,我的代碼:創建從另一個線程日誌聲明將打破管道流並拋出一個錯誤。也許需要一個同步管道。我發現這些代碼與谷歌,但沒有嘗試它,但(看起來也是在這裏:http://www.certpal.com/blogs/2010/11/using-a-pipedinputstream-and-pipedoutputstream/ ):

package application.common; 

import java.io.InputStream; 
import java.io.OutputStream; 

public class SyncPipe implements Runnable { 

    private final OutputStream outputStream; 
    private final InputStream inputStream; 

    public SyncPipe(InputStream inputStream, OutputStream outputStream) { 
     this.inputStream = inputStream; 
     this.outputStream = outputStream; 
    } 

    @Override 
    public void run() { 
     try { 
      final byte[] buffer = new byte[1024]; 
      for (int length = 0; (length = inputStream.read(buffer)) != -1;) { 
       outputStream.write(buffer, 0, length); 
      } 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 

另一個問題:彩色串格式應與日誌消息類型的一些更好的檢測(信息進行重新編碼,調試,跟蹤等)。過濾諸如「text.toString()。contains(」TRACE「))」真的很醜。

讓我知道如果您有任何問題。這個線程真的很老,但如果你寫在這裏,我會收到一封電子郵件。然後我可以直接回復你