Joystick validations

Fixed logback to log properly
This commit is contained in:
mikael.lantz 2020-12-10 11:03:51 +01:00
parent accfa782b2
commit d886c7d113
7 changed files with 302 additions and 148 deletions

View File

@ -74,7 +74,7 @@ public class JoystickBottomPanel extends JPanel
{ {
if (aComboBox == null) if (aComboBox == null)
{ {
aComboBox = new KeySelectionComboBox(); aComboBox = new KeySelectionComboBox(this.model);
aComboBox.addActionListener(new ActionListener() aComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -90,7 +90,7 @@ public class JoystickBottomPanel extends JPanel
{ {
if (bComboBox == null) if (bComboBox == null)
{ {
bComboBox = new KeySelectionComboBox(); bComboBox = new KeySelectionComboBox(this.model);
bComboBox.addActionListener(new ActionListener() bComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -106,7 +106,7 @@ public class JoystickBottomPanel extends JPanel
{ {
if (cComboBox == null) if (cComboBox == null)
{ {
cComboBox = new KeySelectionComboBox(); cComboBox = new KeySelectionComboBox(this.model);
cComboBox.addActionListener(new ActionListener() cComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)

View File

@ -36,6 +36,7 @@ public class JoystickPanel extends JPanel
private JTextField configTextField; private JTextField configTextField;
private JoystickModel model; private JoystickModel model;
private JPanel configPanel;
public JoystickPanel(int portnumber, JoystickModel model) public JoystickPanel(int portnumber, JoystickModel model)
{ {
@ -102,18 +103,13 @@ public class JoystickPanel extends JPanel
gbc_joystickBottomPanel.gridx = 0; gbc_joystickBottomPanel.gridx = 0;
gbc_joystickBottomPanel.gridy = 5; gbc_joystickBottomPanel.gridy = 5;
add(getJoystickBottomPanel(), gbc_joystickBottomPanel); add(getJoystickBottomPanel(), gbc_joystickBottomPanel);
GridBagConstraints gbc_configLabel = new GridBagConstraints(); GridBagConstraints gbc_configPanel = new GridBagConstraints();
gbc_configLabel.anchor = GridBagConstraints.EAST; gbc_configPanel.fill = GridBagConstraints.HORIZONTAL;
gbc_configLabel.insets = new Insets(0, 0, 0, 5); gbc_configPanel.insets = new Insets(0, 0, 0, 5);
gbc_configLabel.gridx = 0; gbc_configPanel.gridx = 0;
gbc_configLabel.gridy = 6; gbc_configPanel.gridwidth = 3;
add(getConfigLabel(), gbc_configLabel); gbc_configPanel.gridy = 6;
GridBagConstraints gbc_configTextField = new GridBagConstraints(); add(getConfigPanel(), gbc_configPanel);
gbc_configTextField.insets = new Insets(0, 0, 0, 5);
gbc_configTextField.fill = GridBagConstraints.HORIZONTAL;
gbc_configTextField.gridx = 1;
gbc_configTextField.gridy = 6;
add(getConfigTextField(), gbc_configTextField);
if (!Beans.isDesignTime()) if (!Beans.isDesignTime())
{ {
model.addPropertyChangeListener((e) -> modelChanged()); model.addPropertyChangeListener((e) -> modelChanged());
@ -161,7 +157,7 @@ public class JoystickPanel extends JPanel
{ {
if (leftFireComboBox == null) if (leftFireComboBox == null)
{ {
leftFireComboBox = new KeySelectionComboBox(); leftFireComboBox = new KeySelectionComboBox(this.model);
leftFireComboBox.addActionListener(new ActionListener() leftFireComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -189,7 +185,7 @@ public class JoystickPanel extends JPanel
{ {
if (rightFireComboBox == null) if (rightFireComboBox == null)
{ {
rightFireComboBox = new KeySelectionComboBox(); rightFireComboBox = new KeySelectionComboBox(this.model);
rightFireComboBox.addActionListener(new ActionListener() rightFireComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -205,7 +201,7 @@ public class JoystickPanel extends JPanel
{ {
if (tlComboBox == null) if (tlComboBox == null)
{ {
tlComboBox = new KeySelectionComboBox(); tlComboBox = new KeySelectionComboBox(this.model);
tlComboBox.addActionListener(new ActionListener() tlComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -221,7 +217,7 @@ public class JoystickPanel extends JPanel
{ {
if (trComboBox == null) if (trComboBox == null)
{ {
trComboBox = new KeySelectionComboBox(); trComboBox = new KeySelectionComboBox(this.model);
trComboBox.addActionListener(new ActionListener() trComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -283,4 +279,26 @@ public class JoystickPanel extends JPanel
} }
return configTextField; return configTextField;
} }
private JPanel getConfigPanel() {
if (configPanel == null) {
configPanel = new JPanel();
GridBagLayout gbl_configPanel = new GridBagLayout();
configPanel.setLayout(gbl_configPanel);
GridBagConstraints gbc_configLabel = new GridBagConstraints();
gbc_configLabel.anchor = GridBagConstraints.WEST;
gbc_configLabel.insets = new Insets(0, 10, 0, 5);
gbc_configLabel.gridx = 0;
gbc_configLabel.gridy = 0;
configPanel.add(getConfigLabel(), gbc_configLabel);
GridBagConstraints gbc_configTextField = new GridBagConstraints();
gbc_configTextField.insets = new Insets(0, 0, 0, 20);
gbc_configTextField.fill = GridBagConstraints.HORIZONTAL;
gbc_configTextField.weightx = 1.0;
gbc_configTextField.anchor = GridBagConstraints.NORTHWEST;
gbc_configTextField.gridx = 1;
gbc_configTextField.gridy = 0;
configPanel.add(getConfigTextField(), gbc_configTextField);
}
return configPanel;
}
} }

View File

@ -69,7 +69,7 @@ public class JoystickStickPanel extends JPanel
{ {
if (upComboBox == null) if (upComboBox == null)
{ {
upComboBox = new KeySelectionComboBox(); upComboBox = new KeySelectionComboBox(this.model);
upComboBox.addActionListener(new ActionListener() upComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -85,7 +85,7 @@ public class JoystickStickPanel extends JPanel
{ {
if (leftComboBox == null) if (leftComboBox == null)
{ {
leftComboBox = new KeySelectionComboBox(); leftComboBox = new KeySelectionComboBox(this.model);
leftComboBox.addActionListener(new ActionListener() leftComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -101,7 +101,7 @@ public class JoystickStickPanel extends JPanel
{ {
if (rightComboBox == null) if (rightComboBox == null)
{ {
rightComboBox = new KeySelectionComboBox(); rightComboBox = new KeySelectionComboBox(this.model);
rightComboBox.addActionListener(new ActionListener() rightComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -117,7 +117,7 @@ public class JoystickStickPanel extends JPanel
{ {
if (downComboBox == null) if (downComboBox == null)
{ {
downComboBox = new KeySelectionComboBox(); downComboBox = new KeySelectionComboBox(this.model);
downComboBox.addActionListener(new ActionListener() downComboBox.addActionListener(new ActionListener()
{ {
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)

View File

@ -7,6 +7,8 @@ import java.util.Objects;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import se.lantz.model.JoystickModel;
public class KeySelectionComboBox extends JComboBox<String> public class KeySelectionComboBox extends JComboBox<String>
{ {
@ -17,9 +19,12 @@ public class KeySelectionComboBox extends JComboBox<String>
Map<String, String> codeMap = new HashMap<>(); Map<String, String> codeMap = new HashMap<>();
public KeySelectionComboBox() private JoystickModel model;
public KeySelectionComboBox(JoystickModel model)
{ {
super(); super();
this.model = model;
setupItemsAndCodes(); setupItemsAndCodes();
} }
@ -31,50 +36,10 @@ public class KeySelectionComboBox extends JComboBox<String>
this.addItem("Left"); this.addItem("Left");
this.addItem("Right"); this.addItem("Right");
this.addItem("Fire"); this.addItem("Fire");
this.addItem("F1"); for (String code : model.getKeyCodeList())
this.addItem("F2"); {
this.addItem("F3"); this.addItem(code);
this.addItem("F4"); }
this.addItem("F5");
this.addItem("F6");
this.addItem("F7");
this.addItem("F8");
this.addItem("A");
this.addItem("B");
this.addItem("C");
this.addItem("D");
this.addItem("E");
this.addItem("F");
this.addItem("G");
this.addItem("H");
this.addItem("I");
this.addItem("J");
this.addItem("K");
this.addItem("L");
this.addItem("M");
this.addItem("N");
this.addItem("O");
this.addItem("P");
this.addItem("Q");
this.addItem("R");
this.addItem("S");
this.addItem("T");
this.addItem("U");
this.addItem("V");
this.addItem("W");
this.addItem("X");
this.addItem("Y");
this.addItem("Z");
this.addItem("1");
this.addItem("2");
this.addItem("3");
this.addItem("4");
this.addItem("5");
this.addItem("6");
this.addItem("7");
this.addItem("8");
this.addItem("9");
this.addItem("0");
this.addItem("ARROW LEFT"); this.addItem("ARROW LEFT");
this.addItem("ARROW UP"); this.addItem("ARROW UP");
this.addItem("THEC64"); this.addItem("THEC64");
@ -94,32 +59,99 @@ public class KeySelectionComboBox extends JComboBox<String>
this.addItem("SHIFT LOCK"); this.addItem("SHIFT LOCK");
this.addItem("SPACE"); this.addItem("SPACE");
this.addItem("£ (Pound)"); this.addItem("£ (Pound)");
// Codes not matching the text
codeMap.put("", "----"); codeMap = model.getKeyCodeMap();
codeMap.put("JU", "Up");
codeMap.put("JD", "Down"); //
codeMap.put("JL", "Left"); // this.addItem("F1");
codeMap.put("JR", "Right"); // this.addItem("F2");
codeMap.put("JF", "Fire"); // this.addItem("F3");
codeMap.put("AL", "ARROW LEFT"); // this.addItem("F4");
codeMap.put("AU", "ARROW UP"); // this.addItem("F5");
codeMap.put("CM", "THEC64"); // this.addItem("F6");
codeMap.put("CO", ", (Comma)"); // this.addItem("F7");
codeMap.put("CT", "CTRL"); // this.addItem("F8");
codeMap.put("CU", "Cursor Up"); // this.addItem("A");
codeMap.put("CD", "Cursor Down"); // this.addItem("B");
codeMap.put("CL", "Cursor Left"); // this.addItem("C");
codeMap.put("CR", "Cursor Right"); // this.addItem("D");
codeMap.put("DL", "INST/DEL"); // this.addItem("E");
codeMap.put("EN", "RETURN"); // this.addItem("F");
codeMap.put("HM", "CLR/HOME"); // this.addItem("G");
codeMap.put("RS", "RUN/STOP"); // this.addItem("H");
codeMap.put("RE", "RESTORE"); // this.addItem("I");
codeMap.put("SL", "Left SHIFT"); // this.addItem("J");
codeMap.put("SR", "Right SHIFT"); // this.addItem("K");
codeMap.put("SS", "SHIFT LOCK"); // this.addItem("L");
codeMap.put("SP", "SPACE"); // this.addItem("M");
codeMap.put("PO", "£ (Pound)"); // this.addItem("N");
// this.addItem("O");
// this.addItem("P");
// this.addItem("Q");
// this.addItem("R");
// this.addItem("S");
// this.addItem("T");
// this.addItem("U");
// this.addItem("V");
// this.addItem("W");
// this.addItem("X");
// this.addItem("Y");
// this.addItem("Z");
// this.addItem("1");
// this.addItem("2");
// this.addItem("3");
// this.addItem("4");
// this.addItem("5");
// this.addItem("6");
// this.addItem("7");
// this.addItem("8");
// this.addItem("9");
// this.addItem("0");
// this.addItem("ARROW LEFT");
// this.addItem("ARROW UP");
// this.addItem("THEC64");
// this.addItem(", (Comma)");
// this.addItem("CTRL");
// this.addItem("Cursor Up");
// this.addItem("Cursor Down");
// this.addItem("Cursor Left");
// this.addItem("Cursor Right");
// this.addItem("INST/DEL");
// this.addItem("RETURN");
// this.addItem("CLR/HOME");
// this.addItem("RUN/STOP");
// this.addItem("RESTORE");
// this.addItem("Left SHIFT");
// this.addItem("Right SHIFT");
// this.addItem("SHIFT LOCK");
// this.addItem("SPACE");
// this.addItem("£ (Pound)");
// // Codes not matching the text
// codeMap.put("", "----");
// codeMap.put("JU", "Up");
// codeMap.put("JD", "Down");
// codeMap.put("JL", "Left");
// codeMap.put("JR", "Right");
// codeMap.put("JF", "Fire");
// codeMap.put("AL", "ARROW LEFT");
// codeMap.put("AU", "ARROW UP");
// codeMap.put("CM", "THEC64");
// codeMap.put("CO", ", (Comma)");
// codeMap.put("CT", "CTRL");
// codeMap.put("CU", "Cursor Up");
// codeMap.put("CD", "Cursor Down");
// codeMap.put("CL", "Cursor Left");
// codeMap.put("CR", "Cursor Right");
// codeMap.put("DL", "INST/DEL");
// codeMap.put("EN", "RETURN");
// codeMap.put("HM", "CLR/HOME");
// codeMap.put("RS", "RUN/STOP");
// codeMap.put("RE", "RESTORE");
// codeMap.put("SL", "Left SHIFT");
// codeMap.put("SR", "Right SHIFT");
// codeMap.put("SS", "SHIFT LOCK");
// codeMap.put("SP", "SPACE");
// codeMap.put("PO", "£ (Pound)");
} }
public void setSelectedCode(String code) public void setSelectedCode(String code)

View File

@ -20,6 +20,7 @@ import javax.swing.JPopupMenu;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import se.lantz.gui.gameview.GameViewManager; import se.lantz.gui.gameview.GameViewManager;
import se.lantz.model.MainViewModel; import se.lantz.model.MainViewModel;
@ -157,10 +158,10 @@ public class MainPanel extends JPanel
}; };
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
list.addListSelectionListener((e) -> { list.addListSelectionListener(e -> {
if (e.getValueIsAdjusting() == false) if (!e.getValueIsAdjusting())
{ {
getGameDetailsBackgroundPanel().updateSelectedGame(list.getSelectedValue()); SwingUtilities.invokeLater(() -> getGameDetailsBackgroundPanel().updateSelectedGame(list.getSelectedValue()));
} }
}); });
list.setModel(uiModel.getGameListModel()); list.setModel(uiModel.getGameListModel());

View File

@ -4,7 +4,9 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
public class JoystickModel extends AbstractModel public class JoystickModel extends AbstractModel
@ -16,10 +18,98 @@ public class JoystickModel extends AbstractModel
private List<String> configList = new ArrayList<>(); private List<String> configList = new ArrayList<>();
private ActionListener primaryListener; private ActionListener primaryListener;
private Map<String, String> keyCodeMap = new HashMap<>();
private List<String> keyCodeList = new ArrayList<>();
public JoystickModel(boolean port1) public JoystickModel(boolean port1)
{ {
this.port1 = port1; this.port1 = port1;
setupKeyKodes();
}
private void setupKeyKodes()
{
keyCodeList.add("F1");
keyCodeList.add("F2");
keyCodeList.add("F3");
keyCodeList.add("F4");
keyCodeList.add("F5");
keyCodeList.add("F6");
keyCodeList.add("F7");
keyCodeList.add("F8");
keyCodeList.add("A");
keyCodeList.add("B");
keyCodeList.add("C");
keyCodeList.add("D");
keyCodeList.add("E");
keyCodeList.add("F");
keyCodeList.add("G");
keyCodeList.add("H");
keyCodeList.add("I");
keyCodeList.add("J");
keyCodeList.add("K");
keyCodeList.add("L");
keyCodeList.add("M");
keyCodeList.add("N");
keyCodeList.add("O");
keyCodeList.add("P");
keyCodeList.add("Q");
keyCodeList.add("R");
keyCodeList.add("S");
keyCodeList.add("T");
keyCodeList.add("U");
keyCodeList.add("V");
keyCodeList.add("W");
keyCodeList.add("X");
keyCodeList.add("Y");
keyCodeList.add("Z");
keyCodeList.add("1");
keyCodeList.add("2");
keyCodeList.add("3");
keyCodeList.add("4");
keyCodeList.add("5");
keyCodeList.add("6");
keyCodeList.add("7");
keyCodeList.add("8");
keyCodeList.add("9");
keyCodeList.add("0");
// Codes not matching the text
keyCodeMap.put("", "----");
keyCodeMap.put("JU", "Up");
keyCodeMap.put("JD", "Down");
keyCodeMap.put("JL", "Left");
keyCodeMap.put("JR", "Right");
keyCodeMap.put("JF", "Fire");
keyCodeMap.put("AL", "ARROW LEFT");
keyCodeMap.put("AU", "ARROW UP");
keyCodeMap.put("CM", "THEC64");
keyCodeMap.put("CO", ", (Comma)");
keyCodeMap.put("CT", "CTRL");
keyCodeMap.put("CU", "Cursor Up");
keyCodeMap.put("CD", "Cursor Down");
keyCodeMap.put("CL", "Cursor Left");
keyCodeMap.put("CR", "Cursor Right");
keyCodeMap.put("DL", "INST/DEL");
keyCodeMap.put("EN", "RETURN");
keyCodeMap.put("HM", "CLR/HOME");
keyCodeMap.put("RS", "RUN/STOP");
keyCodeMap.put("RE", "RESTORE");
keyCodeMap.put("SL", "Left SHIFT");
keyCodeMap.put("SR", "Right SHIFT");
keyCodeMap.put("SS", "SHIFT LOCK");
keyCodeMap.put("SP", "SPACE");
keyCodeMap.put("PO", "£ (Pound)");
}
public List<String> getKeyCodeList()
{
return keyCodeList;
}
public Map<String, String> getKeyCodeMap()
{
return keyCodeMap;
} }
public String getConfigString() public String getConfigString()
@ -75,37 +165,46 @@ public class JoystickModel extends AbstractModel
public void setConfigString(String configString) public void setConfigString(String configString)
{ {
disableChangeNotification(true);
String definitions = configString;
// Set all other fields based on configString // Set all other fields based on configString
String[] colonSplit = configString.split(":"); String[] colonSplit = configString.split(":");
if (colonSplit.length != 3) if (colonSplit.length == 3)
{ {
throw new IllegalStateException("Invalid config string"); definitions = colonSplit[2];
setPrimary(colonSplit[1].contains("*"));
} }
configList.clear();
configList = new ArrayList<>(Arrays.asList(colonSplit[2].split(","))); ArrayList<String> newConfigList = new ArrayList<>(Arrays.asList(definitions.split(",")));
while (configList.size() < 15) while (newConfigList.size() < 15)
{ {
configList.add(""); newConfigList.add("");
} }
disableChangeNotification(true); //Validate all entries
setUp(configList.get(0)); for (int i = 0; i < newConfigList.size(); i++)
setDown(configList.get(1)); {
setLeft(configList.get(2)); String value = newConfigList.get(i);
setRight(configList.get(3)); if (!keyCodeList.contains(value) && !keyCodeMap.keySet().contains(value))
setLeftFire(configList.get(4)); {
setRightFire(configList.get(5)); newConfigList.set(i, "");
setTl(configList.get(6)); }
setTr(configList.get(7)); }
setUnused1(configList.get(8)); setUp(newConfigList.get(0));
setA(configList.get(9)); setDown(newConfigList.get(1));
setB(configList.get(10)); setLeft(newConfigList.get(2));
setC(configList.get(11)); setRight(newConfigList.get(3));
setUnused2(configList.get(12)); setLeftFire(newConfigList.get(4));
setUnused3(configList.get(13)); setRightFire(newConfigList.get(5));
setUnused4(configList.get(14)); setTl(newConfigList.get(6));
setTr(newConfigList.get(7));
setUnused1(newConfigList.get(8));
setA(newConfigList.get(9));
setB(newConfigList.get(10));
setC(newConfigList.get(11));
setUnused2(newConfigList.get(12));
setUnused3(newConfigList.get(13));
setUnused4(newConfigList.get(14));
setPrimary(colonSplit[1].contains("*"));
disableChangeNotification(false); disableChangeNotification(false);
notifyChange(); notifyChange();
} }

View File

@ -1,30 +1,34 @@
<configuration> <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <appender name="STDOUT"
<encoder> class="ch.qos.logback.core.ConsoleAppender">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <encoder>
</encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</appender> </pattern>
</encoder>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> </appender>
<file>pcusb.log</file>
<append>true</append> <appender name="FILE"
<!-- set immediateFlush to false for much higher logging throughput --> class="ch.qos.logback.core.rolling.RollingFileAppender">
<immediateFlush>true</immediateFlush> <file>pcusb.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy
<fileNamePattern>pcusb-%d{yyyy-MM-dd}.log</fileNamePattern> class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<maxHistory>30</maxHistory> <fileNamePattern>pcusb-%d{yyyy-MM-dd}_%i.log</fileNamePattern>
<totalSizeCap>1Mb</totalSizeCap> <maxHistory>5</maxHistory>
</rollingPolicy> <totalSizeCap>30MB</totalSizeCap>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <timeBasedFileNamingAndTriggeringPolicy
<maxFileSize>1MB</maxFileSize> class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
</triggeringPolicy> <!-- or whenever the file size reaches 5MB -->
<encoder> <maxFileSize>5MB</maxFileSize>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </timeBasedFileNamingAndTriggeringPolicy>
</encoder> </rollingPolicy>
</appender> <encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
<root level="debug"> </pattern>
<appender-ref ref="STDOUT" /> </encoder>
<appender-ref ref="FILE" /> </appender>
</root>
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration> </configuration>