Commit 129a7c39 authored by Skylot's avatar Skylot

gui: add log viewer

parent ac3f3e83
......@@ -116,7 +116,8 @@ public class JadxCLIArgs implements IJadxArgs {
if (isVerbose()) {
ch.qos.logback.classic.Logger rootLogger =
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(ch.qos.logback.classic.Level.DEBUG);
// remove INFO ThresholdFilter
rootLogger.getAppender("STDOUT").clearAllFilters();
}
} catch (JadxException e) {
System.err.println("ERROR: " + e.getMessage());
......
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%-5level - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
......
......@@ -3,6 +3,7 @@ package jadx.gui;
import jadx.gui.settings.JadxSettings;
import jadx.gui.settings.JadxSettingsAdapter;
import jadx.gui.ui.MainWindow;
import jadx.gui.utils.LogCollector;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
......@@ -15,6 +16,7 @@ public class JadxGUI {
public static void main(String[] args) {
try {
LogCollector.register();
final JadxSettings jadxArgs = JadxSettingsAdapter.load();
// overwrite loaded settings by command line arguments
if (!jadxArgs.processArgs(args)) {
......
package jadx.gui.ui;
import ch.qos.logback.classic.Level;
import jadx.gui.utils.LogCollector;
import jadx.gui.utils.NLS;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
class LogViewer extends JDialog {
private static final long serialVersionUID = -2188700277429054641L;
private static final Level[] LEVEL_ITEMS = {Level.DEBUG, Level.INFO, Level.WARN, Level.ERROR};
private static Level level = Level.WARN;
private RSyntaxTextArea textPane;
public LogViewer() {
initUI();
registerLogListener();
}
public final void initUI() {
textPane = new RSyntaxTextArea();
textPane.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
JPanel controlPane = new JPanel();
controlPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
final JComboBox cb = new JComboBox(LEVEL_ITEMS);
cb.setSelectedItem(level);
cb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int i = cb.getSelectedIndex();
level = LEVEL_ITEMS[i];
registerLogListener();
}
});
JLabel levelLabel = new JLabel(NLS.str("log.level"));
levelLabel.setLabelFor(cb);
controlPane.add(levelLabel);
controlPane.add(cb);
JScrollPane scrollPane = new JScrollPane(textPane);
JButton close = new JButton(NLS.str("tabs.close"));
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
close();
}
});
close.setAlignmentX(0.5f);
Container contentPane = getContentPane();
contentPane.add(controlPane, BorderLayout.PAGE_START);
contentPane.add(scrollPane, BorderLayout.CENTER);
contentPane.add(close, BorderLayout.PAGE_END);
setTitle("Log Viewer");
pack();
setSize(800, 600);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setModalityType(ModalityType.MODELESS);
setLocationRelativeTo(null);
}
private void registerLogListener() {
LogCollector logCollector = LogCollector.getInstance();
logCollector.resetListener();
textPane.setText("");
logCollector.registerListener(new LogCollector.ILogListener() {
@Override
public Level getFilterLevel() {
return level;
}
@Override
public void onAppend(final String logStr) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textPane.append(logStr);
textPane.updateUI();
}
});
}
});
}
private void close() {
LogCollector.getInstance().resetListener();
dispose();
}
public static void main(String[] args) {
new LogViewer().setVisible(true);
}
}
......@@ -84,6 +84,7 @@ public class MainWindow extends JFrame {
private static final ImageIcon ICON_FORWARD = Utils.openIcon("icon_forward");
private static final ImageIcon ICON_PREF = Utils.openIcon("wrench");
private static final ImageIcon ICON_DEOBF = Utils.openIcon("lock_edit");
private static final ImageIcon ICON_LOG = Utils.openIcon("report");
private final JadxWrapper wrapper;
private final JadxSettings settings;
......@@ -375,6 +376,19 @@ public class MainWindow extends JFrame {
};
find.addActionListener(findAction);
JMenu tools = new JMenu(NLS.str("menu.tools"));
tools.setMnemonic(KeyEvent.VK_T);
JMenuItem logItem = new JMenuItem(NLS.str("menu.log"), ICON_LOG);
ActionListener logAction = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new LogViewer().setVisible(true);
}
};
logItem.addActionListener(logAction);
tools.add(logItem);
JMenu help = new JMenu(NLS.str("menu.help"));
help.setMnemonic(KeyEvent.VK_H);
......@@ -390,6 +404,7 @@ public class MainWindow extends JFrame {
menuBar.add(file);
menuBar.add(view);
menuBar.add(nav);
menuBar.add(tools);
menuBar.add(help);
setJMenuBar(menuBar);
......@@ -470,6 +485,10 @@ public class MainWindow extends JFrame {
}
});
JButton logBtn = new JButton(ICON_LOG);
logBtn.setToolTipText(NLS.str("menu.log"));
logBtn.addActionListener(logAction);
updateLink = new Link("", JadxUpdate.JADX_RELEASES_URL);
updateLink.setVisible(false);
......@@ -495,6 +514,9 @@ public class MainWindow extends JFrame {
toolbar.add(deobfToggleBtn);
toolbar.addSeparator();
toolbar.add(logBtn);
toolbar.addSeparator();
toolbar.add(prefButton);
toolbar.addSeparator();
......
......@@ -9,6 +9,7 @@ import jadx.gui.treemodel.JNode;
import jadx.gui.utils.NLS;
import jadx.gui.utils.NameIndex;
import jadx.gui.utils.Position;
import jadx.gui.utils.TextStandardActions;
import javax.swing.BorderFactory;
import javax.swing.Box;
......@@ -198,7 +199,7 @@ public class SearchDialog extends JDialog {
@Override
public Component getListCellRendererComponent(JList list,
Object obj, int index, boolean isSelected, boolean cellHasFocus) {
Object obj, int index, boolean isSelected, boolean cellHasFocus) {
if (!(obj instanceof JNode)) {
return null;
}
......@@ -317,7 +318,7 @@ public class SearchDialog extends JDialog {
setSize(700, 500);
setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setModalityType(ModalityType.APPLICATION_MODAL);
setModalityType(ModalityType.MODELESS);
}
private JCheckBox makeOptionsCheckBox(String name, final SearchOptions opt) {
......
package jadx.gui.utils;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.read.CyclicBufferAppender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.LoggerFactory;
public class LogCollector extends CyclicBufferAppender<ILoggingEvent> {
private static LogCollector instance = new LogCollector();
public static LogCollector getInstance() {
return instance;
}
public static void register() {
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
LoggerContext loggerContext = rootLogger.getLoggerContext();
PatternLayout layout = new PatternLayout();
layout.setContext(loggerContext);
layout.setPattern("%-5level: %msg%n");
layout.start();
instance.setContext(loggerContext);
instance.setLayout(layout);
instance.start();
rootLogger.addAppender(instance);
}
public interface ILogListener {
Level getFilterLevel();
void onAppend(String logStr);
}
private Layout<ILoggingEvent> layout;
@Nullable
private ILogListener listener;
public LogCollector() {
setName("LogCollector");
setMaxSize(50000);
}
@Override
protected void append(ILoggingEvent event) {
super.append(event);
if (listener != null
&& event.getLevel().isGreaterOrEqual(listener.getFilterLevel())) {
synchronized (this) {
listener.onAppend(layout.doLayout(event));
}
}
}
public void setLayout(Layout<ILoggingEvent> layout) {
this.layout = layout;
}
public void registerListener(@NotNull ILogListener listener) {
this.listener = listener;
synchronized (this) {
listener.onAppend(init(listener.getFilterLevel()));
}
}
public void resetListener() {
this.listener = null;
}
private String init(Level filterLevel) {
StringBuilder sb = new StringBuilder();
int length = getLength();
for (int i = 0; i < length; i++) {
ILoggingEvent event = get(i);
if (event.getLevel().isGreaterOrEqual(filterLevel)) {
sb.append(layout.doLayout(event));
}
}
return sb.toString();
}
}
......@@ -8,6 +8,8 @@ menu.flatten=Show flatten packages
menu.navigation=Navigation
menu.search=Search ...
menu.find_in_file=Find in ...
menu.tools=Tools
menu.log=Log Viewer
menu.help=Help
menu.about=About
menu.update_label=New version %s available!
......@@ -69,6 +71,8 @@ preferences.cancel=Cancel
msg.open_file=Please open file
msg.saving_sources=Saving sources
log.level=Log level:
popup.undo=Undo
popup.redo=Redo
popup.cut=Cut
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment