以编程方式在log4j2.xml中添加记录器



是否可以通过指定记录器名称在log4j2中添加记录器可编程性?我在网上搜索了一下,发现log4j2不允许这种功能。这是链接:

如何在运行时以编程方式添加Log4J2 appender ?

有办法做到这一点吗?

我想分享我是如何使用log4j2实现它的。您可以添加新的日志记录器并删除现有的日志记录器。修改日志级别也是可能的。

    src/
        main/
            java/
               com/foo/bar/
                   LogLevelPM  
                   LogLevelWin  -- Swing UI
            resources/
                log4j2.xml

log4j2配置

<?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
      <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
          <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
      </Appenders>
      <Loggers>
        <Logger name="com.foo.bar.myLogger" level="debug" additivity="false">
            <appender-ref ref="Console"/>
        </Logger>
        <Root level="trace">
          <AppenderRef ref="Console"/>
        </Root>
      </Loggers>
    </Configuration>

LogLevelPM做了实际的操作,LogLevelWin只是使用它的一个例子。

package com.foo.bar;
import java.util.Collection;
import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
public class LogLevelPM {
    public Object[][] retrieveLoggers() {
        Object[][] result = null;
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        Collection<LoggerConfig> loggerConfigs = config.getLoggers().values();
        result = new Object[loggerConfigs.size()][];
        LoggerConfig rootLoggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
        result[0] = new Object[] {"ROOT", rootLoggerConfig.getLevel().toString(), getAppenderNames(rootLoggerConfig.getAppenders())};
        int i = 1;
        for (LoggerConfig loggerConfig : loggerConfigs) {
            if (!loggerConfig.getName().isEmpty()) {
                result[i++] = new Object[]{loggerConfig.getName(), loggerConfig.getLevel().toString(), getAppenderNames(loggerConfig.getAppenders())};
            }
        }
        return result;
    }
    public String[] getAllAppenders() {
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        Map<String, Appender> appenders = config.getAppenders();
        String[] appenderNames = (String[]) appenders.keySet().toArray(new String[appenders.size()]);
        return appenderNames;
    }
    private String getAppenderNames(Map<String, Appender> appenders) {
        Collection<Appender> existingAppenders = appenders.values();
        String result = "";
        for (Appender appender : existingAppenders) {
            if (!result.isEmpty()) {
                result += ",";
            }
            result += appender.getName();
        }
        return result;
    }
    public void changeLogLevel(String loggerName, Level level) {
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        LoggerConfig loggerConfig = null;
        if (loggerName.equals("ROOT")) {
            loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);         
        } else {
            loggerConfig = config.getLoggerConfig(loggerName);          
        }
        if (loggerConfig != null) {
            loggerConfig.setLevel(level);
            ctx.updateLoggers();            
        }
    }
    public void changeAppender(String loggerName, Level level, String appenderName) {
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        Map<String, Appender> allAppenders = config.getAppenders();
        Appender newAppender = allAppenders.get(appenderName);
        if (newAppender != null) {
            LoggerConfig loggerConfig = null;
            org.apache.logging.log4j.core.Logger coreLogger = null;
            if (loggerName.equals("ROOT")) {
                loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); 
            } else {
                loggerConfig = config.getLoggerConfig(loggerName);          
            }
            Map<String, Appender> appenders = loggerConfig.getAppenders();
            Collection<Appender> existingAppenders = appenders.values();
            for (Appender appender : existingAppenders) {
                loggerConfig.removeAppender(appender.getName());
            }
            loggerConfig.addAppender(newAppender, level, null);
            ctx.updateLoggers();            
        }
    }
    public void addLogger(String loggerName, Level level, String appenderName) {
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        LoggerConfig loggerConfig = new LoggerConfig(loggerName, level, false);
        Map<String, Appender> allAppenders = config.getAppenders();
        Appender appender = allAppenders.get(appenderName);
        loggerConfig.addAppender(appender, level, null);
        config.addLogger(loggerName, loggerConfig);
        ctx.updateLoggers();
    }
    public void deleteLogger(String loggerName) {
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        config.removeLogger(loggerName);
        ctx.updateLoggers();        
    }
}

LogLevelWin是一个基于Swing使用上述方法的示例。这是一个位日志代码,所以你可以跳过它。

    package com.foo.bar;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import net.miginfocom.swing.MigLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.ListSelectionModel;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.JPanel;
public class LoglevelWin extends JFrame {
    private static final long serialVersionUID = 1L;
    private Component parent;
    private JScrollPane scrollPane_1;
    private JTable tblLoggers;
    private JButton btnRefresh;
    private JPanel panel;
    private JButton btnNewButton;
    private JButton btnDelete;
    private boolean dirty;
    private LogLevelPM logLevelPM = new LogLevelPM();
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    LoglevelWin frame = new LoglevelWin(null);
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    /**
     * Create the frame.
     */
    public LoglevelWin(Component parent) {
        setMinimumSize(new Dimension(800, 400));
        if (parent != null) {
            this.parent = parent;
            parent.setEnabled(false);           
        }
        initUI();
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                close();
            }
        });
        setLocationRelativeTo(null);
        retrieveLoggers();
        setVisible(true);
    }
    // logger from server
    private void retrieveLoggers() {
        // table model
        Object[][] loggerModels = logLevelPM.retrieveLoggers();
        if (loggerModels != null) {
            String[] columnNames = new String[] {
                    "Logger Name", "Level", "Appender"
            };
            tblLoggers.setModel(new DefaultTableModel(loggerModels, columnNames) {          
                /**
                 * 
                 */
                private static final long serialVersionUID = 1L;
                @Override
                public java.lang.Class<?> getColumnClass(int columnIndex) {
                    switch (columnIndex) {
                    case 0:
                        return String.class;
                    case 1:
                        return String.class;
                    case 2:
                        return String.class;
                    default:
                        return Object.class;
                    }                   
                };
                @Override
                public boolean isCellEditable(int row, int col)
                {
                    if (dirty) {
                        if ((row+1) == this.getRowCount()) {
                            return true;
                        }
                    } 
                    return (col==0)?false:true;
                }
            });
            setUpLevelColumn(tblLoggers.getColumnModel().getColumn(1));
            String[] appenderNames = logLevelPM.getAllAppenders();
            setUpAppenderColumn(appenderNames, tblLoggers.getColumnModel().getColumn(2));
            tblLoggers.getColumnModel().getColumn(0).setPreferredWidth(300);
            tblLoggers.getColumnModel().getColumn(2).setPreferredWidth(200);
            tblLoggers.getTableHeader().setReorderingAllowed(false);
            tblLoggers.getModel().addTableModelListener(new TableModelListener() {
                public void tableChanged(TableModelEvent e) {
                    int type = e.getType();
                    if (type != TableModelEvent.DELETE && type != TableModelEvent.INSERT) {
                        int row = e.getFirstRow();
                        int column = e.getColumn();
                        TableModel model = (TableModel)e.getSource();
                        String loggerName = (String) (model.getValueAt(row, 0));
                        String levelName = (String) (model.getValueAt(row, 1));
                        String appenderName = (String) model.getValueAt(row, 2);
                        if (dirty && (row+1) == model.getRowCount()) {
                            // add
                            if (loggerName != null 
                                    && !loggerName.isEmpty() 
                                    && levelName != null 
                                    && !levelName.isEmpty() 
                                    && appenderName != null 
                                    && !appenderName.isEmpty() 
                                    ) {
                                logLevelPM.addLogger(loggerName, Level.getLevel(levelName), appenderName);
                                dirty = false;
                            }
                        } else {
                            // update
                            if (column == 1) {
                                logLevelPM.changeLogLevel(loggerName, Level.getLevel(levelName));
                            }
                            if (column == 2) {
                                logLevelPM.changeAppender(loggerName, Level.getLevel(levelName), appenderName);
                            }
                        }
                    }
                }
            });
            this.dirty = false;
        }
    }
    private void setUpAppenderColumn(String[] appenderNames, TableColumn column) {
        //Set up the editor for the sport cells.
        JComboBox<String> comboBox = new JComboBox<String>();
        for (int i = 0; i < appenderNames.length; i++) {
            comboBox.addItem(appenderNames[i]);         
        }
        column.setCellEditor(new DefaultCellEditor(comboBox));
        //Set up tool tips for the sport cells.
        DefaultTableCellRenderer renderer =
                new DefaultTableCellRenderer();
        renderer.setToolTipText("Click for appender change");
        column.setCellRenderer(renderer);
    }
    private void setUpLevelColumn(TableColumn column) {
        //Set up the editor for the sport cells.
        JComboBox<String> comboBox = new JComboBox<String>();
//        for (Level level : Level.values()) {
//          comboBox.addItem(level.toString());
//      }
        comboBox.addItem(Level.ALL.name());
        comboBox.addItem(Level.TRACE.name());
        comboBox.addItem(Level.DEBUG.name());
        comboBox.addItem(Level.INFO.name());
        comboBox.addItem(Level.WARN.name());
        comboBox.addItem(Level.ERROR.name());
        comboBox.addItem(Level.FATAL.name());
        comboBox.addItem(Level.OFF.name());
        column.setCellEditor(new DefaultCellEditor(comboBox));
        //Set up tool tips for the sport cells.
        DefaultTableCellRenderer renderer =
                new DefaultTableCellRenderer();
        renderer.setToolTipText("Click for level change");
        column.setCellRenderer(renderer);
    }
    private Object[][]  retrieveLoggersLocal() {
        Object[][] result = null;
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        Collection<LoggerConfig> loggerConfigs = config.getLoggers().values();
        result = new Object[loggerConfigs.size()][];
        result[0] = new Object[] {"ROOT", config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).getLevel()};
        int i = 1;
        for (LoggerConfig loggerConfig : loggerConfigs) {
            if (!loggerConfig.getName().isEmpty()) {
                result[i++] = new Object[]{loggerConfig.getName(), loggerConfig.getLevel()};
            }
        }
        return result;
    }
    private void close() {
        if (parent != null) {
            parent.setEnabled(true);
            ((JFrame)parent).toFront();
            ((JFrame)parent).repaint();
        }
        dispose();
    }
    private void initUI() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new MigLayout("", "[grow][][]", "[][grow][grow]"));
        scrollPane_1 = new JScrollPane();
        getContentPane().add(scrollPane_1, "cell 0 2,grow");
        tblLoggers = new JTable();
        tblLoggers.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        tblLoggers.setModel(new DefaultTableModel(
            new Object[][] {
            },
            new String[] {
                "Logger Name", "Level", "Appender"
            }
        ) {
            private static final long serialVersionUID = 1L;
        });
        tblLoggers.getColumnModel().getColumn(0).setPreferredWidth(300);
        tblLoggers.getColumnModel().getColumn(2).setPreferredWidth(200);
        scrollPane_1.setViewportView(tblLoggers);
        panel = new JPanel();
        getContentPane().add(panel, "flowx,cell 1 2,grow");
        panel.setLayout(new MigLayout("", "[73px]", "[23px][][]"));
        btnRefresh = new JButton("Refresh");
        panel.add(btnRefresh, "cell 0 0,growx");
        btnNewButton = new JButton("Add");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                addLogger();
            }
        });
        panel.add(btnNewButton, "cell 0 1,growx");
        btnDelete = new JButton("Delete");
        btnDelete.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                deleteLogger();
            }
        });
        panel.add(btnDelete, "cell 0 2,growx");
        btnRefresh.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                retrieveLoggers();
            }
        });
    }
    protected void deleteLogger() {
        int row = tblLoggers.getSelectedRow();
        if (row > 0) {
            DefaultTableModel model = ((DefaultTableModel)tblLoggers.getModel());
            String loggerName = (String) (model.getValueAt(row, 0));
            logLevelPM.deleteLogger(loggerName);
            model.removeRow(row);
            tblLoggers.setRowSelectionInterval(row-1, row-1);
        }
    }
    protected void addLogger() {
        if (!dirty) {
            DefaultTableModel model = ((DefaultTableModel)tblLoggers.getModel());
            this.dirty = true;
            model.addRow(new Object[]{"","",""});   
        }
    }
    protected void changeLogLevel(String loggerName, String level) {
        LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        Configuration config = ctx.getConfiguration();
        LoggerConfig loggerConfig = null;
        if (loggerName.equals("ROOT")) {
            loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);         
        } else {
            loggerConfig = config.getLoggerConfig(loggerName);          
        }
        if (loggerConfig != null) {
            loggerConfig.setLevel(Level.getLevel(level));
            ctx.updateLoggers();            
        }
    }
}

我最近有机会以编程方式实现log4j2记录器,我想分享一下。

下面是使用configurationbuilder API在log4j2环境中创建/添加记录器的代码片段:

package com.simple.log4j2.demo.demo;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
public class Log4j2Logger {
int counter = 0;
LoggerContext ctx;
Configuration config;
Logger logger;
String loggerName = "testLogger";
String appenderName = "myAppender";
static String testMessage = "This is a Test Message";
public void log() {
    final ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
    config = builder.build();
    ctx = Configurator.initialize(config);
    config = ctx.getConfiguration();
    ctx.start(config);
    ctx.updateLoggers(config);
    // To create/add the logger of the configuration specified above we can use the
    // getLogger(..) method
    logger = ctx.getLogger(loggerName);
    // Now we need to attach an appender to the logger so that our messages could be
    // logged
    logger.addAppender(addConsoleAppender(ctx.getConfiguration(), appenderName));
    while (counter < 10) {
        logger.error(testMessage + counter);
        counter++;
    }
    // We can remove the logger in the context also after use.
    removeLogger();
}
private Appender addConsoleAppender(Configuration config, String appenderName) {
    Appender consoleAppender = ConsoleAppender.newBuilder().setConfiguration(config).setName(appenderName)
            .withImmediateFlush(true).build();
    consoleAppender.start();
    return consoleAppender;
}
public void removeLogger() {
    config.getLoggerConfig(loggerName).getAppenders().get(appenderName).stop();
    config.getLoggerConfig(loggerName).removeAppender(appenderName);
    config.removeLogger(loggerName);
    ctx.updateLoggers(config);
    }
}

对于测试,您可以在任何测试类中使用以下内容:

    Log4j2Logger testLogger = new Log4j2Logger();
    testLogger.log();

这个API帮助你以一种强大的方式处理日志。

你可以:

  • 创建多个记录器
  • 添加多个appeners到它。
  • 当使用结束时删除记录器。
  • 创建异步记录器

PS:我使用的是log4j2 2.12.1版本

最新更新