class SolonAppender extends AbstractAppender {

    protected SolonAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions) {
        super(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY);
    }

    @Override
    public void append(LogEvent e) {<FILL_FUNCTION_BODY>}

    @PluginFactory
    public static SolonAppender createAppender(
            @PluginAttribute("name") String name,
            @PluginElement("Layout") Layout<? extends Serializable> layout,
            @PluginElement("Filter") final Filter filter,
            @PluginAttribute("otherAttribute") String otherAttribute) {

        if (name == null) {
            LOGGER.error("No name provided for SolonAppender");
            return null;
        }

        if (layout == null) {
            layout = PatternLayout.createDefaultLayout();
        }

        return new SolonAppender(name, filter, layout, true);
    }
}

        //solon console 1个，所以最少2个起
        if (AppenderManager.count() < 2) {
            return;
        }

        Level level;

        int eLevel = e.getLevel().intLevel();
        if (StandardLevel.DEBUG.intLevel() == (eLevel)) {
            level = Level.DEBUG;
        } else if (StandardLevel.WARN.intLevel() == (eLevel)) {
            level = Level.WARN;
        } else if (StandardLevel.INFO.intLevel() == (eLevel)) {
            level = Level.INFO;
        } else if (StandardLevel.TRACE.intLevel() == (eLevel)) {
            level = Level.TRACE;
        } else {
            level = Level.ERROR;
        }

        String message = e.getMessage().getFormattedMessage();
        Throwable throwable = e.getMessage().getThrowable();
        if (throwable != null) {
            String errorStr = Utils.throwableToString(throwable);

            if (message.contains("{}")) {
                message = message.replace("{}", errorStr);
            } else {
                message = message + "\n" + errorStr;
            }
        }

        ReadOnlyStringMap eData = e.getContextData();

        org.noear.solon.logging.event.LogEvent event = new org.noear.solon.logging.event.LogEvent(
                e.getLoggerName(),
                level,
                (eData == null ? null : eData.toMap()),
                message,
                e.getTimeMillis(),
                e.getThreadName(),
                throwable);

        AppenderManager.appendNotPrinted(event);
    
<methods>public void error(java.lang.String) ,public void error(java.lang.String, java.lang.Throwable) ,public void error(java.lang.String, org.apache.logging.log4j.core.LogEvent, java.lang.Throwable) ,public org.apache.logging.log4j.core.ErrorHandler getHandler() ,public Layout<? extends java.io.Serializable> getLayout() ,public java.lang.String getName() ,public boolean ignoreExceptions() ,public static int parseInt(java.lang.String, int) ,public boolean requiresLocation() ,public void setHandler(org.apache.logging.log4j.core.ErrorHandler) ,public java.lang.String toString() <variables>private org.apache.logging.log4j.core.ErrorHandler handler,private final boolean ignoreExceptions,private final Layout<? extends java.io.Serializable> layout,private final java.lang.String name