├── .gitignore ├── README.md ├── logging_system.svg ├── pom.xml └── src ├── main └── java │ └── cc │ └── leevi │ └── common │ └── logc │ ├── ConfigException.java │ ├── ContextInitializer.java │ ├── ILoggerFactory.java │ ├── Level.java │ ├── LifeCycle.java │ ├── LogcLogger.java │ ├── Logger.java │ ├── LoggerContext.java │ ├── LoggerFactory.java │ ├── LoggingEvent.java │ ├── StaticLoggerFactory.java │ ├── appender │ ├── Appender.java │ ├── AppenderAttachable.java │ ├── AppenderAttachableImpl.java │ ├── AppenderBase.java │ └── ConsoleAppender.java │ ├── config │ ├── Configurator.java │ ├── XMLConfigurator.java │ └── YAMLConfigurator.java │ ├── filter │ ├── Filter.java │ └── LevelFilter.java │ ├── layout │ ├── Layout.java │ ├── Pattern.java │ ├── PatternLayout.java │ ├── PlainLayout.java │ └── pattern │ │ ├── Converter.java │ │ ├── DateConverter.java │ │ ├── KeywordConverter.java │ │ ├── KeywordNode.java │ │ ├── LevelConverter.java │ │ ├── LineSeparatorConverter.java │ │ ├── LiteralConverter.java │ │ ├── LoggerConverter.java │ │ ├── MessageConverter.java │ │ ├── Node.java │ │ ├── PatternParser.java │ │ └── ThreadConverter.java │ └── util │ ├── LogUtils.java │ ├── ReflectionUtils.java │ └── StringUtils.java └── test ├── java └── cc │ └── leevi │ └── common │ └── logc │ ├── LoggerFactoryTest.java │ ├── appender │ └── ConsoleAppenderTest.java │ ├── config │ └── XMLConfiguratorTest.java │ └── layout │ ├── PatternLayoutTest.java │ └── pattern │ └── PatternParserTest.java └── resources └── logc.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /target/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # logc 2 | 从零实现一个日志框架 - 完整代码 3 | 4 |  5 | -------------------------------------------------------------------------------- /logging_system.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | jul-to-slf4jjul-to-slf4jjuljava.util.loggingjul...jclcommons-logging(apache)jcl...jboss-loggingjboss-loggingslf4j-jclslf4j-jclslf4j-jboss-loggingslf4j-jboss...slf4j-jdk14 slf4j-jdk14 slf4jslf4jlogbacklogbacklog4j-jullog4j-jullog4j-over-slf4jlog4j-over-slf4jlog4j-1.2-apilog4j-1.2-apilog4j(1)Apachelog4j(1)... log4j-to-slf4j log4j-to-slf4jlog4j(2)Apachelog4j(2)...log4j-jcllog4j-jcllog4j-slf4j-impllog4j-slf4j-implslf4j-log4j12slf4j-log4j12jcl-over-slf4jjcl-over-slf4jLogger Facade: slf4j, jclLogger Facade: slf4j, jclLogger Implements: jul, jboss-logging, logback, log4j(1), log4j(2)Logger Implements: jul, jboss-logging, logback, log4j(1), log4j(2)Viewer does not support full SVG 1.1 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | cc.leevi.common 8 | logc 9 | 1.0-SNAPSHOT 10 | 11 | logc 12 | 13 | http://www.example.com 14 | 15 | 16 | UTF-8 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | 24 | junit 25 | junit 26 | 4.11 27 | test 28 | 29 | 30 | 31 | org.slf4j 32 | slf4j-api 33 | 1.7.25 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/ConfigException.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public class ConfigException extends RuntimeException { 4 | public ConfigException(Exception e) { 5 | super(e); 6 | } 7 | 8 | public ConfigException(String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/ContextInitializer.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | import cc.leevi.common.logc.config.Configurator; 4 | import cc.leevi.common.logc.config.XMLConfigurator; 5 | import cc.leevi.common.logc.config.YAMLConfigurator; 6 | 7 | import java.net.URL; 8 | 9 | public class ContextInitializer { 10 | final public static String AUTOCONFIG_FILE = "logc.xml"; 11 | final public static String YAML_FILE = "logc.yml"; 12 | 13 | private static final LoggerContext DEFAULT_LOGGER_CONTEXT = new LoggerContext(); 14 | 15 | static { 16 | } 17 | 18 | 19 | 20 | public static void autoconfig() { 21 | URL url = getConfigURL(); 22 | if(url == null){ 23 | System.err.println("config[logc.xml or logc.yml] file not found!"); 24 | return ; 25 | } 26 | String urlString = url.toString(); 27 | Configurator configurator = null; 28 | 29 | if(urlString.endsWith("xml")){ 30 | configurator = new XMLConfigurator(url,DEFAULT_LOGGER_CONTEXT); 31 | } 32 | if(urlString.endsWith("yml")){ 33 | configurator = new YAMLConfigurator(url,DEFAULT_LOGGER_CONTEXT); 34 | } 35 | configurator.doConfigure(); 36 | } 37 | 38 | private static URL getConfigURL(){ 39 | URL url = null; 40 | ClassLoader classLoader = ContextInitializer.class.getClassLoader(); 41 | url = classLoader.getResource(AUTOCONFIG_FILE); 42 | if(url != null){ 43 | return url; 44 | } 45 | url = classLoader.getResource(YAML_FILE); 46 | if(url != null){ 47 | return url; 48 | } 49 | return null; 50 | } 51 | 52 | public static LoggerContext getDefautLoggerContext(){ 53 | return DEFAULT_LOGGER_CONTEXT; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/ILoggerFactory.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public interface ILoggerFactory { 4 | Logger getLogger(Class> clazz); 5 | 6 | Logger getLogger(String name); 7 | 8 | Logger newLogger(String name); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/Level.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public enum Level { 4 | ERROR(40000, "ERROR"), WARN(30000, "WARN"), INFO(20000, "INFO"), DEBUG(10000, "DEBUG"), TRACE(5000, "TRACE"); 5 | 6 | private int levelInt; 7 | private String levelStr; 8 | 9 | Level(int i, String s) { 10 | levelInt = i; 11 | levelStr = s; 12 | } 13 | 14 | public static Level parse(String level) { 15 | return valueOf(level.toUpperCase()); 16 | } 17 | 18 | public int toInt() { 19 | return levelInt; 20 | } 21 | 22 | public String toString() { 23 | return levelStr; 24 | } 25 | 26 | public boolean isGreaterOrEqual(Level level) { 27 | return levelInt>=level.toInt(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/LifeCycle.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public interface LifeCycle { 4 | void start(); 5 | void stop(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/LogcLogger.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | import cc.leevi.common.logc.appender.AppenderAttachableImpl; 4 | 5 | public class LogcLogger implements Logger ,LifeCycle{ 6 | 7 | private String name; 8 | private Level level = Level.TRACE; 9 | private int effectiveLevelInt; 10 | private LogcLogger parent; 11 | private AppenderAttachableImpl aai; 12 | 13 | private LoggerContext loggerContext; 14 | 15 | @Override 16 | public void trace(String msg) { 17 | filterAndLog(Level.TRACE,msg); 18 | } 19 | 20 | @Override 21 | public void info(String msg) { 22 | filterAndLog(Level.INFO,msg); 23 | } 24 | 25 | @Override 26 | public void debug(String msg) { 27 | filterAndLog(Level.DEBUG,msg); 28 | } 29 | 30 | @Override 31 | public void warn(String msg) { 32 | filterAndLog(Level.WARN,msg); 33 | } 34 | 35 | @Override 36 | public void error(String msg) { 37 | filterAndLog(Level.ERROR,msg); 38 | } 39 | 40 | @Override 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | private void filterAndLog(Level level,String msg){ 46 | LoggingEvent e = new LoggingEvent(level, msg,getName()); 47 | for (LogcLogger l = this;l != null;l = l.parent){ 48 | if(l.aai == null){ 49 | continue; 50 | } 51 | if(level.toInt()>effectiveLevelInt){ 52 | l.aai.appendLoopOnAppenders(e); 53 | } 54 | //优先使用当前logger,如果当前没有则向上查找,找到就跳出 55 | //默认情况下,如果不配置完整类名的logger,这里都需要向上查找,直至root 56 | //比如name=x.y.z.AClass,则配置logger name="x.y.z",则Aclass会使用x.y.z这个logger 57 | break; 58 | } 59 | 60 | } 61 | 62 | public void setName(String name) { 63 | this.name = name; 64 | } 65 | 66 | public void setLevel(Level level) { 67 | this.effectiveLevelInt = level.toInt(); 68 | this.level = level; 69 | } 70 | 71 | public void setEffectiveLevelInt(int effectiveLevelInt) { 72 | this.effectiveLevelInt = effectiveLevelInt; 73 | } 74 | 75 | public void setParent(Logger parent) { 76 | this.parent = (LogcLogger) parent; 77 | } 78 | 79 | public void setAai(AppenderAttachableImpl aai) { 80 | this.aai = aai; 81 | } 82 | 83 | public void setLoggerContext(LoggerContext loggerContext) { 84 | this.loggerContext = loggerContext; 85 | } 86 | 87 | @Override 88 | public void start() { 89 | 90 | } 91 | 92 | @Override 93 | public void stop() { 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/Logger.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public interface Logger{ 4 | void trace(String msg); 5 | 6 | void info(String msg); 7 | 8 | void debug(String msg); 9 | 10 | void warn(String msg); 11 | 12 | void error(String msg); 13 | 14 | String getName(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/LoggerContext.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 一个全局的上下文对象 8 | */ 9 | public class LoggerContext { 10 | 11 | /** 12 | * 根logger 13 | */ 14 | private Logger root; 15 | 16 | /** 17 | * logger缓存,存放解析配置文件后生成的logger对象,以及通过程序手动创建的logger对象 18 | */ 19 | private Map loggerCache = new HashMap<>(); 20 | 21 | public void addLogger(String name,Logger logger){ 22 | loggerCache.put(name,logger); 23 | } 24 | 25 | public void addLogger(Logger logger){ 26 | loggerCache.put(logger.getName(),logger); 27 | } 28 | 29 | public Logger getRoot() { 30 | return root; 31 | } 32 | 33 | public void setRoot(Logger root) { 34 | this.root = root; 35 | } 36 | 37 | public Map getLoggerCache() { 38 | return loggerCache; 39 | } 40 | 41 | public void setLoggerCache(Map loggerCache) { 42 | this.loggerCache = loggerCache; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/LoggerFactory.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public class LoggerFactory { 4 | 5 | private static ILoggerFactory loggerFactory = new StaticLoggerFactory(); 6 | 7 | public static ILoggerFactory getLoggerFactory(){ 8 | return loggerFactory; 9 | } 10 | 11 | public static Logger getLogger(Class> clazz){ 12 | return getLoggerFactory().getLogger(clazz); 13 | } 14 | 15 | public static Logger getLogger(String name){ 16 | return getLoggerFactory().getLogger(name); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/LoggingEvent.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public class LoggingEvent { 4 | public long timestamp; 5 | private Level level; 6 | private Object message; 7 | private String threadName; 8 | private long threadId; 9 | private String loggerName; 10 | 11 | public LoggingEvent(Level level, Object message, String loggerName) { 12 | this.level = level; 13 | this.message = message; 14 | this.loggerName = loggerName; 15 | this.timestamp = System.currentTimeMillis(); 16 | Thread ct = Thread.currentThread(); 17 | this.threadId = ct.getId(); 18 | this.threadName = ct.getName(); 19 | } 20 | 21 | public long getTimestamp() { 22 | return timestamp; 23 | } 24 | 25 | public void setTimestamp(long timestamp) { 26 | this.timestamp = timestamp; 27 | } 28 | 29 | public Level getLevel() { 30 | return level; 31 | } 32 | 33 | public void setLevel(Level level) { 34 | this.level = level; 35 | } 36 | 37 | public Object getMessage() { 38 | return message; 39 | } 40 | 41 | public void setMessage(Object message) { 42 | this.message = message; 43 | } 44 | 45 | public String getThreadName() { 46 | return threadName; 47 | } 48 | 49 | public void setThreadName(String threadName) { 50 | this.threadName = threadName; 51 | } 52 | 53 | public long getThreadId() { 54 | return threadId; 55 | } 56 | 57 | public void setThreadId(long threadId) { 58 | this.threadId = threadId; 59 | } 60 | 61 | public String getLoggerName() { 62 | return loggerName; 63 | } 64 | 65 | public void setLoggerName(String loggerName) { 66 | this.loggerName = loggerName; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return "LoggingEvent{" + 72 | "timestamp=" + timestamp + 73 | ", level=" + level + 74 | ", message=" + message + 75 | ", threadName='" + threadName + '\'' + 76 | ", threadId=" + threadId + 77 | ", loggerName='" + loggerName + '\'' + 78 | '}'; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/StaticLoggerFactory.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | public class StaticLoggerFactory implements ILoggerFactory { 4 | 5 | private LoggerContext loggerContext; 6 | 7 | public StaticLoggerFactory() { 8 | ContextInitializer.autoconfig(); 9 | loggerContext = ContextInitializer.getDefautLoggerContext(); 10 | } 11 | 12 | @Override 13 | public Logger getLogger(Class> clazz) { 14 | return getLogger(clazz.getName()); 15 | } 16 | 17 | @Override 18 | public Logger getLogger(String name) { 19 | Logger logger = loggerContext.getLoggerCache().get(name); 20 | if(logger == null){ 21 | logger = newLogger(name); 22 | } 23 | return logger; 24 | } 25 | 26 | @Override 27 | public Logger newLogger(String name) { 28 | LogcLogger logger = new LogcLogger(); 29 | logger.setName(name); 30 | Logger parent = null; 31 | //拆分包名,向上查找parent logger 32 | for (int i = name.lastIndexOf("."); i >= 0; i = name.lastIndexOf(".",i-1)) { 33 | String parentName = name.substring(0,i); 34 | parent = loggerContext.getLoggerCache().get(parentName); 35 | if(parent != null){ 36 | break; 37 | } 38 | } 39 | if(parent == null){ 40 | parent = loggerContext.getRoot(); 41 | } 42 | logger.setParent(parent); 43 | logger.setLoggerContext(loggerContext); 44 | return logger; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/appender/Appender.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.appender; 2 | 3 | import cc.leevi.common.logc.LifeCycle; 4 | import cc.leevi.common.logc.LoggingEvent; 5 | 6 | public interface Appender extends LifeCycle { 7 | 8 | String getName(); 9 | 10 | void setName(String name); 11 | 12 | void append(LoggingEvent e); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/appender/AppenderAttachable.java: -------------------------------------------------------------------------------- 1 | 2 | package cc.leevi.common.logc.appender; 3 | 4 | /** 5 | * Interface for attaching appenders to objects. 6 | * 7 | * @author Ceki Gülcü 8 | * @since 0.9.1 9 | */ 10 | public interface AppenderAttachable { 11 | 12 | void addAppender(Appender newAppender); 13 | 14 | Appender getAppender(String name); 15 | 16 | boolean isAttached(Appender appender); 17 | 18 | void removeAppender(Appender appender); 19 | 20 | void removeAppender(String name); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/appender/AppenderAttachableImpl.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.appender; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | import java.util.List; 6 | import java.util.concurrent.CopyOnWriteArrayList; 7 | 8 | public class AppenderAttachableImpl implements AppenderAttachable { 9 | 10 | final private List appenderList = new CopyOnWriteArrayList<>(); 11 | 12 | @Override 13 | public void addAppender(Appender newAppender) { 14 | appenderList.add(newAppender); 15 | } 16 | 17 | public int appendLoopOnAppenders(LoggingEvent event) { 18 | int size = 0; 19 | Appender appender; 20 | 21 | if(appenderList != null) { 22 | size = appenderList.size(); 23 | for(int i = 0; i < size; i++) { 24 | appender = appenderList.get(i); 25 | appender.append(event); 26 | } 27 | } 28 | return size; 29 | } 30 | 31 | @Override 32 | public Appender getAppender(String name) { 33 | if (name == null) { 34 | return null; 35 | } 36 | for (Appender appender : appenderList) { 37 | if (name.equals(appender.getName())) { 38 | return appender; 39 | } 40 | } 41 | return null; 42 | } 43 | 44 | @Override 45 | public boolean isAttached(Appender appender) { 46 | if (appender == null) { 47 | return false; 48 | } 49 | for (Appender a : appenderList) { 50 | if (a == appender) 51 | return true; 52 | } 53 | return false; 54 | } 55 | 56 | @Override 57 | public void removeAppender(Appender appender) { 58 | removeAppender(appender.getName()); 59 | } 60 | 61 | @Override 62 | public void removeAppender(String name) { 63 | if (name == null) { 64 | return ; 65 | } 66 | for (Appender a : appenderList) { 67 | if (name.equals((a).getName())) { 68 | appenderList.remove(a); 69 | break; 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/appender/AppenderBase.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.appender; 2 | 3 | import cc.leevi.common.logc.filter.Filter; 4 | import cc.leevi.common.logc.layout.Layout; 5 | import cc.leevi.common.logc.LoggingEvent; 6 | 7 | import java.nio.charset.Charset; 8 | import java.util.List; 9 | 10 | public abstract class AppenderBase implements Appender{ 11 | protected Layout layout; 12 | protected List filterList; 13 | protected String encoding = Charset.defaultCharset().name(); 14 | protected String name; 15 | 16 | protected Object lock = new Object(); 17 | 18 | @Override 19 | public void append(LoggingEvent e) { 20 | if(filterList!=null){ 21 | for (Filter filter : filterList) { 22 | if(!filter.doFilter(e)){ 23 | return ; 24 | } 25 | } 26 | } 27 | String body = layout.doLayout(e); 28 | synchronized (lock){ 29 | doAppend(body); 30 | } 31 | } 32 | 33 | protected abstract void doAppend(String body); 34 | 35 | @Override 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | @Override 41 | public void setName(String name) { 42 | this.name = name; 43 | } 44 | 45 | public Layout getLayout() { 46 | return layout; 47 | } 48 | 49 | public List getFilterList() { 50 | return filterList; 51 | } 52 | 53 | public String getEncoding() { 54 | return encoding; 55 | } 56 | 57 | public void setLayout(Layout layout) { 58 | this.layout = layout; 59 | } 60 | 61 | public void setFilterList(List filterList) { 62 | this.filterList = filterList; 63 | } 64 | 65 | public void setEncoding(String encoding) { 66 | this.encoding = encoding; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/appender/ConsoleAppender.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.appender; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | public class ConsoleAppender extends AppenderBase { 7 | private OutputStream out = System.out; 8 | private OutputStream out_err = System.err; 9 | 10 | @Override 11 | protected void doAppend(String body) { 12 | try { 13 | out.write(body.getBytes(encoding)); 14 | } catch (IOException e) { 15 | e.printStackTrace(); 16 | } 17 | } 18 | 19 | @Override 20 | public void start() { 21 | 22 | } 23 | 24 | @Override 25 | public void stop() { 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/config/Configurator.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.config; 2 | 3 | import cc.leevi.common.logc.LifeCycle; 4 | 5 | public interface Configurator extends LifeCycle { 6 | void doConfigure(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/config/XMLConfigurator.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.config; 2 | 3 | import cc.leevi.common.logc.Level; 4 | import cc.leevi.common.logc.LifeCycle; 5 | import cc.leevi.common.logc.LogcLogger; 6 | import cc.leevi.common.logc.LoggerContext; 7 | import cc.leevi.common.logc.appender.Appender; 8 | import cc.leevi.common.logc.appender.AppenderAttachableImpl; 9 | import cc.leevi.common.logc.appender.AppenderBase; 10 | import cc.leevi.common.logc.filter.Filter; 11 | import cc.leevi.common.logc.layout.Layout; 12 | import cc.leevi.common.logc.util.ReflectionUtils; 13 | import cc.leevi.common.logc.util.StringUtils; 14 | import org.w3c.dom.Document; 15 | import org.w3c.dom.Element; 16 | import org.w3c.dom.Node; 17 | import org.w3c.dom.NodeList; 18 | 19 | import javax.xml.parsers.DocumentBuilder; 20 | import javax.xml.parsers.DocumentBuilderFactory; 21 | import java.net.URL; 22 | import java.util.ArrayList; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | public class XMLConfigurator implements Configurator{ 28 | 29 | private final URL url; 30 | 31 | private final LoggerContext loggerContext; 32 | 33 | static final String APPENDER_TAG = "appender"; 34 | 35 | static final String LOGGER_TAG = "logger"; 36 | 37 | static final String CLASS_ATTR = "class"; 38 | 39 | static final String NAME_ATTR = "name"; 40 | 41 | static final String VALUE_ATTR = "value"; 42 | 43 | static final String LEVEL_ATTR = "level"; 44 | 45 | static final String FILTER_ATTR = "filter"; 46 | 47 | static final String LAYOUT_TAG = "layout"; 48 | 49 | static final String ENCODING_TAG = "encoding"; 50 | 51 | static final String PARAM_TAG = "param"; 52 | 53 | static final String ROOT_TAG = "root"; 54 | 55 | static final String APPENDER_REF_TAG = "appender-ref"; 56 | 57 | static final String APPENDER_REF_ATTR = "ref"; 58 | 59 | private Map appenderCache = new HashMap<>(); 60 | 61 | public XMLConfigurator(URL url, LoggerContext loggerContext) { 62 | this.url = url; 63 | this.loggerContext = loggerContext; 64 | } 65 | 66 | @Override 67 | public void doConfigure() { 68 | try{ 69 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 70 | DocumentBuilder documentBuilder = factory.newDocumentBuilder(); 71 | Document document = documentBuilder.parse(url.openStream()); 72 | parse(document.getDocumentElement()); 73 | }catch (Exception e){ 74 | e.printStackTrace(); 75 | } 76 | 77 | } 78 | 79 | private void parse(Element document) throws IllegalAccessException, ClassNotFoundException, InstantiationException { 80 | parseLoggers(document); 81 | parseRoot(document); 82 | } 83 | 84 | private void parseLoggers(Element document) throws IllegalAccessException, ClassNotFoundException, InstantiationException { 85 | NodeList loggerNodeList = document.getElementsByTagName(LOGGER_TAG); 86 | 87 | for (int i = 0; i < loggerNodeList.getLength(); i++) { 88 | LogcLogger logger = parseChildrenOfLoggerElement((Element) loggerNodeList.item(i)); 89 | loggerContext.addLogger(logger); 90 | } 91 | } 92 | 93 | private void parseRoot(Element document) throws IllegalAccessException, ClassNotFoundException, InstantiationException { 94 | Element rootEle = getFirstElementByTagName(document,ROOT_TAG); 95 | 96 | LogcLogger root = parseChildrenOfLoggerElement(rootEle); 97 | loggerContext.setRoot(root); 98 | } 99 | 100 | private LogcLogger parseChildrenOfLoggerElement(Element element) throws InstantiationException, IllegalAccessException, ClassNotFoundException { 101 | LogcLogger logger = new LogcLogger(); 102 | 103 | String name = element.getAttribute(NAME_ATTR); 104 | logger.setName(name); 105 | 106 | String level = element.getAttribute(LEVEL_ATTR); 107 | if(!StringUtils.isEmpty(level)){ 108 | logger.setLevel(Level.parse(level)); 109 | } 110 | 111 | AppenderAttachableImpl aai = new AppenderAttachableImpl(); 112 | logger.setAai(aai); 113 | 114 | NodeList appenderRefNodeList = element.getElementsByTagName(APPENDER_REF_TAG); 115 | int refLength = appenderRefNodeList.getLength(); 116 | for (int i = 0; i < refLength; i++) { 117 | Element appenderRefNode = (Element) appenderRefNodeList.item(i); 118 | String appenderName = appenderRefNode.getAttribute(APPENDER_REF_ATTR); 119 | Appender appender = findAppenderByName(element.getOwnerDocument(), appenderName); 120 | aai.addAppender(appender); 121 | } 122 | return logger; 123 | } 124 | 125 | protected Appender findAppenderByName(Document document, String appenderName) throws ClassNotFoundException, InstantiationException, IllegalAccessException { 126 | Appender appender = appenderCache.get(appenderName); 127 | if(appender != null){ 128 | return appender; 129 | } 130 | NodeList appenderNodeList = document.getElementsByTagName(APPENDER_TAG); 131 | for (int i = 0; i < appenderNodeList.getLength(); i++) { 132 | Element appenderEle = (Element) appenderNodeList.item(i); 133 | String itemAppenderName = appenderEle.getAttribute(NAME_ATTR); 134 | 135 | if(appenderName.equals(itemAppenderName)){ 136 | String itemAppenderClassName = appenderEle.getAttribute(CLASS_ATTR); 137 | 138 | appender = (Appender) Class.forName(itemAppenderClassName).newInstance(); 139 | appender.setName(itemAppenderName); 140 | 141 | Element layoutEle = getFirstElementByTagName(appenderEle, LAYOUT_TAG); 142 | Layout layout = parseLayout(layoutEle); 143 | ((AppenderBase)appender).setLayout(layout); 144 | startComponent(layout); 145 | Element encodingELe = getFirstElementByTagName(appenderEle, ENCODING_TAG); 146 | if(encodingELe!=null){ 147 | String encoding = parseEncoding(encodingELe); 148 | ((AppenderBase)appender).setEncoding(encoding); 149 | } 150 | NodeList filterNodeList = appenderEle.getElementsByTagName(FILTER_ATTR); 151 | if(filterNodeList.getLength()>0){ 152 | List filterList = parseFilter(filterNodeList); 153 | ((AppenderBase)appender).setFilterList(filterList); 154 | for (Filter filter : filterList) { 155 | startComponent(filter); 156 | } 157 | } 158 | startComponent(appender); 159 | return appender; 160 | } 161 | } 162 | return null; 163 | } 164 | 165 | private String parseEncoding(Element encodingEle){ 166 | return encodingEle.getNodeValue(); 167 | } 168 | 169 | private Element getFirstElementByTagName(Element ele,String tagName){ 170 | NodeList elements = ele.getElementsByTagName(tagName); 171 | if(elements.getLength()>0){ 172 | return (Element) elements.item(0); 173 | } 174 | return null; 175 | } 176 | 177 | protected List parseFilter(NodeList filterNodeList) throws ClassNotFoundException, IllegalAccessException, InstantiationException { 178 | List filterList = new ArrayList<>(filterNodeList.getLength()); 179 | 180 | for (int j = 0; j < filterNodeList.getLength(); j++) { 181 | Element filterEle = (Element) filterNodeList.item(0); 182 | String filterClassName = filterEle.getAttribute(CLASS_ATTR); 183 | Filter filter = (Filter) Class.forName(filterClassName).newInstance(); 184 | NodeList paramNodeList = filterEle.getElementsByTagName(PARAM_TAG); 185 | for (int k = 0; k < paramNodeList.getLength(); k++) { 186 | Element paramEle = (Element) paramNodeList.item(k); 187 | ReflectionUtils.setFiled(filter,paramEle.getAttribute(NAME_ATTR),paramEle.getAttribute(VALUE_ATTR)); 188 | } 189 | filterList.add(filter); 190 | } 191 | return filterList; 192 | } 193 | 194 | protected Layout parseLayout(Element layoutEle) throws ClassNotFoundException, IllegalAccessException, InstantiationException { 195 | String className = layoutEle.getAttribute(CLASS_ATTR); 196 | Object instance = Class.forName(className).newInstance(); 197 | Layout layout = (Layout)instance; 198 | 199 | NodeList params = layoutEle.getChildNodes(); 200 | final int length = params.getLength(); 201 | 202 | for (int loop = 0; loop < length; loop++) { 203 | Node currentNode = params.item(loop); 204 | if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 205 | Element currentElement = (Element) currentNode; 206 | String tagName = currentElement.getTagName(); 207 | if(tagName.equals(PARAM_TAG)) { 208 | String name = currentElement.getAttribute(NAME_ATTR); 209 | String value = currentElement.getAttribute(VALUE_ATTR); 210 | ReflectionUtils.setFiled(layout,name,value); 211 | } 212 | } 213 | } 214 | return layout; 215 | } 216 | 217 | private void startComponent(LifeCycle component){ 218 | component.start(); 219 | } 220 | 221 | @Override 222 | public void start() { 223 | 224 | } 225 | 226 | @Override 227 | public void stop() { 228 | 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/config/YAMLConfigurator.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.config; 2 | 3 | import cc.leevi.common.logc.LoggerContext; 4 | 5 | import java.net.URL; 6 | 7 | public class YAMLConfigurator implements Configurator{ 8 | 9 | private final URL url; 10 | 11 | private final LoggerContext loggerContext; 12 | 13 | public YAMLConfigurator(URL url, LoggerContext loggerContext) { 14 | this.url = url; 15 | this.loggerContext = loggerContext; 16 | } 17 | 18 | @Override 19 | public void doConfigure() { 20 | 21 | } 22 | 23 | @Override 24 | public void start() { 25 | 26 | } 27 | 28 | @Override 29 | public void stop() { 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/filter/Filter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.filter; 2 | 3 | import cc.leevi.common.logc.LifeCycle; 4 | import cc.leevi.common.logc.LoggingEvent; 5 | 6 | public interface Filter extends LifeCycle { 7 | boolean doFilter(LoggingEvent event); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/filter/LevelFilter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.filter; 2 | 3 | import cc.leevi.common.logc.Level; 4 | import cc.leevi.common.logc.LoggingEvent; 5 | 6 | public class LevelFilter implements Filter{ 7 | 8 | private String level; 9 | 10 | private Level l; 11 | 12 | @Override 13 | public boolean doFilter(LoggingEvent event) { 14 | return event.getLevel().isGreaterOrEqual(l); 15 | } 16 | 17 | public void setLevel(String level) { 18 | this.level = level; 19 | } 20 | 21 | @Override 22 | public void start() { 23 | this.l = Level.parse(level); 24 | } 25 | 26 | @Override 27 | public void stop() { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/Layout.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout; 2 | 3 | import cc.leevi.common.logc.LifeCycle; 4 | import cc.leevi.common.logc.LoggingEvent; 5 | 6 | public interface Layout extends LifeCycle { 7 | String doLayout(LoggingEvent e); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/Pattern.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout; 2 | 3 | public class Pattern { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/PatternLayout.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | import cc.leevi.common.logc.layout.Layout; 5 | import cc.leevi.common.logc.layout.pattern.Node; 6 | import cc.leevi.common.logc.layout.pattern.PatternParser; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 可配置的字符串模板布局 12 | */ 13 | public class PatternLayout implements Layout { 14 | 15 | private String pattern; 16 | 17 | private PatternParser patternParser; 18 | 19 | private List nodes; 20 | 21 | @Override 22 | public String doLayout(LoggingEvent e) { 23 | StringBuilder sb = new StringBuilder(); 24 | for (Node n : nodes) { 25 | sb.append(n.getConverter().convert(e)); 26 | } 27 | return sb.toString(); 28 | } 29 | 30 | 31 | 32 | public void setPattern(String pattern) { 33 | this.pattern = pattern; 34 | 35 | } 36 | 37 | private void prepare(){ 38 | this.patternParser = new PatternParser(pattern); 39 | this.nodes = patternParser.parse(); 40 | } 41 | 42 | @Override 43 | public void start() { 44 | prepare(); 45 | } 46 | 47 | @Override 48 | public void stop() { 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/PlainLayout.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | import cc.leevi.common.logc.layout.Layout; 5 | 6 | /** 7 | * 纯文本布局,直接调用{@link cc.leevi.common.logc.LoggingEvent#toString()} 8 | */ 9 | public class PlainLayout implements Layout { 10 | 11 | @Override 12 | public String doLayout(LoggingEvent e) { 13 | return e.toString(); 14 | } 15 | 16 | @Override 17 | public void start() { 18 | 19 | } 20 | 21 | @Override 22 | public void stop() { 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/Converter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | public interface Converter { 6 | 7 | String convert(LoggingEvent e); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/DateConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | import java.text.SimpleDateFormat; 6 | import java.time.Instant; 7 | import java.time.ZoneId; 8 | import java.time.format.DateTimeFormatter; 9 | 10 | public class DateConverter extends KeywordConverter { 11 | 12 | private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); 13 | 14 | private SimpleDateFormat sdf = new SimpleDateFormat(); 15 | 16 | @Override 17 | public String convert(LoggingEvent e) { 18 | return dateTimeFormatter.format(Instant.ofEpochMilli((e.getTimestamp())).atZone(ZoneId.systemDefault()).toLocalDateTime()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/KeywordConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | public abstract class KeywordConverter implements Converter { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/KeywordNode.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | public class KeywordNode extends Node { 4 | 5 | public KeywordNode(String value) { 6 | super(Node.KEYWORD,value); 7 | } 8 | 9 | public KeywordNode() { 10 | } 11 | 12 | public String getKeyword(){ 13 | return value.substring(1); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/LevelConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | public class LevelConverter implements Converter { 6 | 7 | @Override 8 | public String convert(LoggingEvent e) { 9 | return e.getLevel().toString(); 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/LineSeparatorConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | public class LineSeparatorConverter extends KeywordConverter { 6 | @Override 7 | public String convert(LoggingEvent e) { 8 | return System.lineSeparator(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/LiteralConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | public class LiteralConverter implements Converter { 6 | 7 | private String literal; 8 | 9 | @Override 10 | public String convert(LoggingEvent e) { 11 | return literal; 12 | } 13 | 14 | public LiteralConverter(String literal) { 15 | this.literal = literal; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/LoggerConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | public class LoggerConverter extends KeywordConverter { 6 | @Override 7 | public String convert(LoggingEvent e) { 8 | return e.getLoggerName(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/MessageConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | public class MessageConverter extends KeywordConverter { 6 | @Override 7 | public String convert(LoggingEvent e) { 8 | return String.valueOf(e.getMessage()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/Node.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | public class Node { 4 | 5 | public static final int LITERAL = 0; 6 | 7 | public static final int KEYWORD = 1; 8 | 9 | 10 | public Node(int type, String value) { 11 | this.type = type; 12 | this.value = value; 13 | } 14 | 15 | public Node() { 16 | } 17 | 18 | protected int type; 19 | 20 | protected String value; 21 | 22 | protected Node next; 23 | 24 | protected Converter converter; 25 | 26 | public int getType() { 27 | return type; 28 | } 29 | 30 | public void setType(int type) { 31 | this.type = type; 32 | } 33 | 34 | public String getValue() { 35 | return value; 36 | } 37 | 38 | public void setValue(String value) { 39 | this.value = value; 40 | } 41 | 42 | public Node getNext() { 43 | return next; 44 | } 45 | 46 | public void setNext(Node next) { 47 | this.next = next; 48 | } 49 | 50 | public Converter getConverter() { 51 | return converter; 52 | } 53 | 54 | public void setConverter(Converter converter) { 55 | this.converter = converter; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/PatternParser.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.ConfigException; 4 | import cc.leevi.common.logc.util.ReflectionUtils; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * 解析日志输出规则 13 | */ 14 | public class PatternParser { 15 | 16 | enum ParserState { 17 | //字符 18 | LITERAL_STATE, 19 | 20 | KEYWORD_STATE 21 | } 22 | 23 | public static final char PERCENT_CHAR = '%'; 24 | 25 | private String pattern; 26 | 27 | public static final Map defaultConverterMap = new HashMap<>(); 28 | 29 | public PatternParser(String pattern) { 30 | this.pattern = pattern; 31 | } 32 | 33 | static { 34 | //put converters to defaultConverterMap 35 | defaultConverterMap.put("d",DateConverter.class); 36 | defaultConverterMap.put("t",ThreadConverter.class); 37 | defaultConverterMap.put("m",MessageConverter.class); 38 | defaultConverterMap.put("p",LevelConverter.class); 39 | defaultConverterMap.put("c",LoggerConverter.class); 40 | defaultConverterMap.put("n",LineSeparatorConverter.class); 41 | } 42 | 43 | public List parse(){ 44 | List nodes = new ArrayList<>(); 45 | int i = 0; 46 | char c; 47 | ParserState state = ParserState.LITERAL_STATE; 48 | StringBuilder literalBuf = new StringBuilder(); 49 | int patternLength = pattern.length(); 50 | while (i != patternLength-1){ 51 | c = pattern.charAt(i++); 52 | switch (state){ 53 | case LITERAL_STATE: 54 | if(c == PERCENT_CHAR){ 55 | if(literalBuf.length()>0){ 56 | Node node = new Node(Node.LITERAL, literalBuf.toString()); 57 | nodes.add(node); 58 | literalBuf.setLength(0); 59 | } 60 | state = ParserState.KEYWORD_STATE; 61 | } 62 | literalBuf.append(c); 63 | break; 64 | case KEYWORD_STATE: 65 | if(!Character.isJavaIdentifierPart(c)){ 66 | 67 | KeywordNode node = new KeywordNode(literalBuf.toString()); 68 | nodes.add(node); 69 | state = ParserState.LITERAL_STATE; 70 | literalBuf.setLength(0); 71 | 72 | 73 | } 74 | literalBuf.append(c); 75 | break; 76 | } 77 | } 78 | 79 | compileNode(nodes); 80 | return nodes; 81 | } 82 | 83 | private void compileNode(List nodes) { 84 | for (Node n : nodes){ 85 | Converter converter = null; 86 | if(n instanceof KeywordNode){ 87 | String keyword = ((KeywordNode) n).getKeyword(); 88 | Class clazz = defaultConverterMap.get(keyword); 89 | if(clazz == null){ 90 | throw new ConfigException("pattern[%"+keyword+"] illegal!"); 91 | } 92 | try{ 93 | converter = (Converter) ReflectionUtils.newInstance(clazz); 94 | }catch (Exception e){ 95 | throw new ConfigException(e); 96 | } 97 | }else{ 98 | converter = new LiteralConverter(n.getValue()); 99 | } 100 | n.converter = converter; 101 | } 102 | } 103 | 104 | private Node newHead(Node head,Node node){ 105 | if(head == null){ 106 | head = node; 107 | }else{ 108 | 109 | head.next = node; 110 | } 111 | return head; 112 | } 113 | 114 | public static void main(String[] args) { 115 | System.out.println(Character.isJavaIdentifierPart(' ')); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/layout/pattern/ThreadConverter.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import cc.leevi.common.logc.LoggingEvent; 4 | 5 | public class ThreadConverter extends KeywordConverter { 6 | @Override 7 | public String convert(LoggingEvent e) { 8 | return e.getThreadName(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/util/LogUtils.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.util; 2 | 3 | public class LogUtils { 4 | 5 | private static final String LOG_PREFIX = "logc: "; 6 | 7 | public static void info(String msg) { 8 | System.out.println(LOG_PREFIX + msg); 9 | } 10 | 11 | public static void error(String msg, Throwable t) { 12 | System.err.println(LOG_PREFIX + msg); 13 | if(t != null){ 14 | System.err.println(LOG_PREFIX + t.getMessage()); 15 | } 16 | } 17 | 18 | public static void error(String msg) { 19 | error(msg, null); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/util/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.util; 2 | 3 | 4 | import cc.leevi.common.logc.ConfigException; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | /** 9 | * 简易反射工具类,演示代码,不做缓存 10 | */ 11 | public class ReflectionUtils { 12 | 13 | public static void setFiled(Object instance,String fieldName,String fieldValue){ 14 | Class> clazz = instance.getClass(); 15 | try{ 16 | Field field = clazz.getDeclaredField(fieldName); 17 | field.setAccessible(true); 18 | field.set(instance,fieldValue); 19 | }catch (ReflectiveOperationException e){ 20 | throw new ConfigException(e); 21 | } 22 | } 23 | 24 | public static Object newInstance(Class> clazz){ 25 | try { 26 | return clazz.newInstance(); 27 | } catch (InstantiationException e) { 28 | throw new ConfigException(e); 29 | } catch (IllegalAccessException e) { 30 | throw new ConfigException(e); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cc/leevi/common/logc/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.util; 2 | 3 | public class StringUtils { 4 | public static boolean isEmpty(String str){ 5 | return str == null||str.length()==0; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/cc/leevi/common/logc/LoggerFactoryTest.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.IOException; 9 | import java.io.ObjectOutputStream; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class LoggerFactoryTest { 14 | 15 | @Before 16 | public void setUp() throws Exception { 17 | } 18 | 19 | @After 20 | public void tearDown() throws Exception { 21 | } 22 | 23 | @Test 24 | public void getLogger() { 25 | } 26 | 27 | @Test 28 | public void testGetLogger() { 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/test/java/cc/leevi/common/logc/appender/ConsoleAppenderTest.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.appender; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | public class ConsoleAppenderTest { 10 | 11 | @Before 12 | public void setUp() throws Exception { 13 | } 14 | 15 | @After 16 | public void tearDown() throws Exception { 17 | } 18 | 19 | @Test 20 | public void doAppend() { 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/java/cc/leevi/common/logc/config/XMLConfiguratorTest.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.config; 2 | 3 | import cc.leevi.common.logc.Logger; 4 | import cc.leevi.common.logc.LoggerContext; 5 | import cc.leevi.common.logc.LoggerFactory; 6 | import org.junit.After; 7 | import org.junit.Assert; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class XMLConfiguratorTest { 14 | 15 | private Configurator configurator; 16 | 17 | private LoggerContext loggerContext = new LoggerContext(); 18 | 19 | @Before 20 | public void setUp() throws Exception { 21 | 22 | configurator = new XMLConfigurator(getClass().getClassLoader().getResource("logc.xml"),loggerContext); 23 | } 24 | 25 | @Test 26 | public void doConfigure() { 27 | configurator.doConfigure(); 28 | System.out.println(loggerContext); 29 | System.out.println("done!"); 30 | } 31 | 32 | @After 33 | public void after(){ 34 | } 35 | } -------------------------------------------------------------------------------- /src/test/java/cc/leevi/common/logc/layout/PatternLayoutTest.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout; 2 | 3 | import cc.leevi.common.logc.Level; 4 | import cc.leevi.common.logc.LoggingEvent; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class PatternLayoutTest { 11 | 12 | private PatternLayout patternLayout; 13 | 14 | @Before 15 | public void setUp() throws Exception { 16 | patternLayout = new PatternLayout(); 17 | patternLayout.setPattern("LOGC %d %t %p %c - %m%n"); 18 | } 19 | 20 | @Test 21 | public void doLayout() { 22 | for (int i = 0; i < 10; i++) { 23 | LoggingEvent e = new LoggingEvent(Level.INFO,"hello logc",PatternLayoutTest.class.getName()); 24 | String body = patternLayout.doLayout(e); 25 | System.out.println(body); 26 | } 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /src/test/java/cc/leevi/common/logc/layout/pattern/PatternParserTest.java: -------------------------------------------------------------------------------- 1 | package cc.leevi.common.logc.layout.pattern; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import java.util.List; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | public class PatternParserTest { 12 | 13 | private PatternParser patternParser; 14 | 15 | @Before 16 | public void setUp() throws Exception { 17 | patternParser = new PatternParser("LOGC %d %t %p %c - %m%n"); 18 | } 19 | 20 | @After 21 | public void tearDown() throws Exception { 22 | } 23 | 24 | @Test 25 | public void parse() { 26 | List nodes = patternParser.parse(); 27 | for (Node node : nodes) { 28 | System.out.println(node.converter.getClass().getName()); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/test/resources/logc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------