上善若水
          In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
          posts - 146,comments - 147,trackbacks - 0

          LoggerRepository從字面上理解,它是一個Logger的容器,它會創建并緩存Logger實例,從而具有相同名字的Logger實例不會多次創建,以提高性能。它的這種特性有點類似SpringIOC概念。Log4J支持兩種配置文件:properties文件和xml文件。Configurator解析配置文件,并將解析后的信息添加到LoggerRepository中。LogManager最終將LoggerRepositoryConfigurator整合在一起。

          LoggerRepository接口

          LoggerRepository是一個Logger的容器,它負責創建、緩存Logger實例,同時它也維護了Logger之間的關系,因為在Log4J中,所有Logger都組裝成以RootLogger為根的一棵樹,樹的層次由LoggerName來決定,其中以’.’分隔。

          除了做為一個Logger容器,它還有一個Threshold屬性,用于過濾所有在Threshold級別以下的日志。以及其他和Logger操作相關的方法和屬性。

          LoggerRepository的接口定義如下:

           1 public interface LoggerRepository {
           2     public void addHierarchyEventListener(HierarchyEventListener listener);
           3     boolean isDisabled(int level);
           4     public void setThreshold(Level level);
           5     public void setThreshold(String val);
           6     public void emitNoAppenderWarning(Category cat);
           7     public Level getThreshold();
           8     public Logger getLogger(String name);
           9     public Logger getLogger(String name, LoggerFactory factory);
          10     public Logger getRootLogger();
          11     public abstract Logger exists(String name);
          12     public abstract void shutdown();
          13     public Enumeration getCurrentLoggers();
          14     public abstract void fireAddAppenderEvent(Category logger, Appender appender);
          15     public abstract void resetConfiguration();
          16 }

           

          Hierarchy

          HierarchyLog4J中默認對LoggerRepository的實現類,它用于表達其內部的Logger是以層次結構存儲的。在對LoggerRepository接口的實現中,getLogger()方法是其最核心的實現,因而首先從這個方法開始。

          Hierarchy中用一個Hashtable來存儲所有Logger實例,它以CategoryKey作為keyLogger作為value,其中CategoryKey是對LoggerName字符串的封裝,之所以要引入這個類是出于性能考慮,因為它會緩存Name字符串的hash code,這樣在查找過程中計算hash code時就可以直接取得而不用每次都計算。

           1 class CategoryKey {
           2     String name;
           3     int hashCache;
           4 
           5     CategoryKey(String name) {
           6         this.name = name;
           7         hashCache = name.hashCode();
           8     }
           9     final public int hashCode() {
          10         return hashCache;
          11     }
          12     final public boolean equals(Object rArg) {
          13         if (this == rArg)
          14             return true;
          15         if (rArg != null && CategoryKey.class == rArg.getClass())
          16             return name.equals(((CategoryKey) rArg).name);
          17         else
          18             return false;
          19     }
          20 }

          getLogger()方法中有一個重載函數提供LoggerFactory接口,它用于沒有在LoggerRepository中找到Logger實例時創建相應的Logger實例,默認實現直接創建一個Logger實例,用戶可以通過自定義LoggerFactory實現創建自己的Logger實例。

          1 public interface LoggerFactory {
          2     public Logger makeNewLoggerInstance(String name);
          3 }
          4 class DefaultCategoryFactory implements LoggerFactory {
          5     public Logger makeNewLoggerInstance(String name) {
          6         return new Logger(name);
          7     }
          8 }

          getLogger()方法首先根據傳入name創建CategoryKey實例,而后從緩存ht字段中查找:

          1.       如果找到對應的Logger實例,則直接返回該實例。

          2.       如果沒有找到任何實例,則使用LoggerFactory創建新的Logger實例,并將該實例緩存到ht集合中,同時更新新創建Logger實例的parent屬性。更新parent屬性最簡單的做法是從后往前以’.’為分隔符截取字符串,使用截取后的字符串從ht集合中查找是否存在Logger實例,如果存在,則新創建的Logger實例的parent即為找到的實例,若在整個遍歷過程中都沒有找到相應的parent實例,則其parent實例為root。然而如果一個“x.y.z.wLogger起初的parent設置為root,而后出現“x.y.zLogger實例,那么就需要更新“x.y.z.wLoggerparent為“x.y.zLogger實例,此時就會遇到一個如何找到在集合中已經存在的“x.y.zLogger實例子節點的問題。當然一種簡單的做法是遍歷ht集合中所有實例,判斷那個實例是不是“x.y.zLogger實例的子節點,是則更新其parent節點。由于每次的遍歷會引起一些性能問題,因而Log4J使用ProvisionNode事先將所有的可能相關的子節點保存起來,并將ProvisionNode實例添加到ht集合中,這樣只要找到對應的ProvisionNode實例,就可以找到所有相關的子節點了。比如對“x.y.z.wLogger實例,它會產生三個ProvisionNode實例(當然如果相應的實例已經存在,則直接添加而無需創建,另外,如果相應節點已經是Logger實例,那么將“x.y.z.wLogger實例的parent直接指向它即可):ProvisionNode(“x”), ProvisionNode(“x.y”), ProvisionNode(“x.y.z”),他們都存儲了“x.y.z.wLogger實例作為其子節點。

           1 class ProvisionNode extends Vector {
           2     ProvisionNode(Logger logger) {
           3         super();
           4         this.addElement(logger);
           5     }
           6 }
           7 final private void updateParents(Logger cat) {
           8     String name = cat.name;
           9     int length = name.length();
          10     boolean parentFound = false;
          11     // if name = "x.y.z.w", loop thourgh "x.y.z", "x.y" and "x"
          12     for (int i = name.lastIndexOf('.', length - 1); i >= 0; i = name
          13             .lastIndexOf('.', i - 1)) {
          14         String substr = name.substring(0, i);
          15         CategoryKey key = new CategoryKey(substr); 
          16         Object o = ht.get(key);
          17         if (o == null) {
          18             ProvisionNode pn = new ProvisionNode(cat);
          19             ht.put(key, pn);
          20         } else if (o instanceof Category) {
          21             parentFound = true;
          22             cat.parent = (Category) o;
          23             break// no need to update the ancestors of the closest
          24                     // ancestor
          25         } else if (o instanceof ProvisionNode) {
          26             ((ProvisionNode) o).addElement(cat);
          27         } else {
          28             Exception e = new IllegalStateException(
          29                     "unexpected object type " + o.getClass() + " in ht.");
          30             e.printStackTrace();
          31         }
          32     }
          33     // If we could not find any existing parents, then link with root.
          34     if (!parentFound)
          35         cat.parent = root;
          36 }

          3.   如果找到的是ProvisionNode實例,首先使用factory創建新的Logger實例,將該實例添加到ht集合中,然后更新找到的ProvisionNode內部所有Loggerparent字段以及新創建Loggerparent字段。更新過程中需要注意ProvisionNode中的Logger實例已經指向了正確的parent了,所以只要更新那些ProvisionNodeLogger實例指向的parent比新創建的Logger本身層次要高的那些parent屬性。比如開始插入“x.y.zLogger實例,而后插入“x.y.z.wLogger實例,此時ProvisionNode(“x”)認為“x.y.zLogger實例和“x.y.z.wLogger實例都是它的子節點,而后插入“xLogger實例,那么只需要更新“x.y.zLogger的父節點為“xLogger實例即可,而不用更新“x.y.z.wLogger實例的父節點。

           1 final private void updateChildren(ProvisionNode pn, Logger logger) {
           2     final int last = pn.size();
           3     for (int i = 0; i < last; i++) {
           4         Logger l = (Logger) pn.elementAt(i);
           5         // Unless this child already points to a correct (lower) parent,
           6         // make cat.parent point to l.parent and l.parent to cat.
           7         if (!l.parent.name.startsWith(logger.name)) {
           8             logger.parent = l.parent;
           9             l.parent = logger;
          10         }
          11     }
          12 }

          綜合起來,getLogger()方法的實現代碼如下:

           1 public Logger getLogger(String name, LoggerFactory factory) {
           2     CategoryKey key = new CategoryKey(name);
           3     Logger logger;
           4     synchronized (ht) {
           5         Object o = ht.get(key);
           6         if (o == null) {
           7             logger = factory.makeNewLoggerInstance(name);
           8             logger.setHierarchy(this);
           9             ht.put(key, logger);
          10             updateParents(logger);
          11             return logger;
          12         } else if (o instanceof Logger) {
          13             return (Logger) o;
          14         } else if (o instanceof ProvisionNode) {
          15             logger = factory.makeNewLoggerInstance(name);
          16             logger.setHierarchy(this);
          17             ht.put(key, logger);
          18             updateChildren((ProvisionNode) o, logger);
          19             updateParents(logger);
          20             return logger;
          21         } else {
          22             // It should be impossible to arrive here
          23             return null// but let's keep the compiler happy.
          24         }
          25     }
          26 }

          其他的方法實現則比較簡單,對LoggerRepository來說,它也可以像其注冊HierarchyEventListener監聽器,每當向一個Logger添加或刪除Appender,該監聽器就會觸發。

           1 public interface HierarchyEventListener {
           2     public void addAppenderEvent(Category cat, Appender appender);
           3     public void removeAppenderEvent(Category cat, Appender appender);
           4 }
           5 private Vector listeners;
           6 public void addHierarchyEventListener(HierarchyEventListener listener) {
           7     if (listeners.contains(listener)) {
           8         LogLog.warn("Ignoring attempt to add an existent listener.");
           9     } else {
          10         listeners.addElement(listener);
          11     }
          12 }
          13 public void fireAddAppenderEvent(Category logger, Appender appender) {
          14     if (listeners != null) {
          15         int size = listeners.size();
          16         HierarchyEventListener listener;
          17         for (int i = 0; i < size; i++) {
          18             listener = (HierarchyEventListener) listeners.elementAt(i);
          19             listener.addAppenderEvent(logger, appender);
          20         }
          21     }
          22 }
          23 void fireRemoveAppenderEvent(Category logger, Appender appender) {
          24     if (listeners != null) {
          25         int size = listeners.size();
          26         HierarchyEventListener listener;
          27         for (int i = 0; i < size; i++) {
          28             listener = (HierarchyEventListener) listeners.elementAt(i);
          29             listener.removeAppenderEvent(logger, appender);
          30         }
          31     }
          32 }

          Hierarchy中保存了threshold字段,用戶可以設置threshold。而對root實例,它在夠著Hierarchy時就被指定了。getCurrentLoggers()方法將ht集合中所有的Logger實例取出。shutdown()方法遍歷所有Logger實例以及root實例,調用所有附加其上的Appenderclose()方法,并將所有Appender實例從Logger中移除,最后觸發AppenderRemove事件。resetConfiguration()方法將root字段初始化、調用shutdown()方法移除Logger中的所有Appender、初始化所有Logger實例當不將其從LoggerRepository中移除、清楚rendererMapthrowableRender中的數據。

          RendererSupport接口

          RendererSupport接口支持用戶為不同的類設置相應的ObjectRender實例,從而可以從被渲染的類中或許更多的信息而不是默認的調用其toString()方法。

           1 public interface RendererSupport {
           2     public RendererMap getRendererMap();
           3     public void setRenderer(Class renderedClass, ObjectRenderer renderer);
           4 }
           5 Hierarchy類實現了RenderedSupprt接口,而且它的實現也很簡單:
           6 RendererMap rendererMap;
           7 public Hierarchy(Logger root) {
           8     
           9     rendererMap = new RendererMap();
          10     
          11 }
          12 public void addRenderer(Class classToRender, ObjectRenderer or) {
          13     rendererMap.put(classToRender, or);
          14 }
          15 public RendererMap getRendererMap() {
          16     return rendererMap;
          17 }
          18 public void setRenderer(Class renderedClass, ObjectRenderer renderer) {
          19     rendererMap.put(renderedClass, renderer);
          20 }

          RendererMap類實現中,它使用Hastable保存被渲染的類實例和相應的ObjectRender實例,在查找一個類是否存在注冊的渲染類時,如果它本身沒有找到,需要向上嘗試其父類和接口是否有注冊相應的ObjectRender類,如果都沒有找到,則返回默認的ObjectRender

           1 public ObjectRenderer get(Class clazz) {
           2     ObjectRenderer r = null;
           3     for (Class c = clazz; c != null; c = c.getSuperclass()) {
           4         r = (ObjectRenderer) map.get(c);
           5         if (r != null) {
           6             return r;
           7         }
           8         r = searchInterfaces(c);
           9         if (r != null)
          10             return r;
          11     }
          12     return defaultRenderer;
          13 }
          14 ObjectRenderer searchInterfaces(Class c) {
          15     ObjectRenderer r = (ObjectRenderer) map.get(c);
          16     if (r != null) {
          17         return r;
          18     } else {
          19         Class[] ia = c.getInterfaces();
          20         for (int i = 0; i < ia.length; i++) {
          21             r = searchInterfaces(ia[i]);
          22             if (r != null)
          23                 return r;
          24         }
          25     }
          26     return null;
          27 }
          28 public ObjectRenderer getDefaultRenderer() {
          29     return defaultRenderer;
          30 }
          31 public void put(Class clazz, ObjectRenderer or) {
          32     map.put(clazz, or);
          33 }

          ThrowableRendererSupport接口

          ThrowableRendererSupport接口用于支持設置和獲取ThrowableRenderer,從而用戶可以自定義對Throwable對象的渲染。

          1 public interface ThrowableRendererSupport {
          2     ThrowableRenderer getThrowableRenderer();
          3     void setThrowableRenderer(ThrowableRenderer renderer);
          4 }

          Hierarchy類以屬性的方式實現了該接口,因而每個Hierarchy實例只能有一個全局的ThrowableRenderer,而不能像ObjectRender那樣為不同的類定義不同的render。當時這種設計也是合理的,因為對Throwable的渲染最主要的就是其棧的渲染,其他的沒什么大的不同,而且對棧渲染方式保持相同的格式會比較好。

           1 private ThrowableRenderer throwableRenderer = null;
           2 public Hierarchy(Logger root) {
           3     
           4     defaultFactory = new DefaultCategoryFactory();
           5     
           6 }
           7 public void setThrowableRenderer(final ThrowableRenderer renderer) {
           8     throwableRenderer = renderer;
           9 }
          10 public ThrowableRenderer getThrowableRenderer() {
          11     return throwableRenderer;
          12 }

          Configurator接口

          Configurator接口用于定義對配置文件的解析。在Log4J中配置文件解析出來的所有信息都可以放在LoggerRepository中,因而Configurator接口的定義非常簡單。

          1 public interface Configurator {
          2     public static final String INHERITED = "inherited";
          3     public static final String NULL = "null";
          4     void doConfigure(URL url, LoggerRepository repository);
          5 }

          Log4J支持兩種文件形式的配置文件:properties文件和xml文件,他們風別對應PropertyConfigurator類和DOMConfigurator類。

          PropertyConfigurator

          PropertyConfigurator類解析properties文件的中的配置信息,可以設置log4j.debugtrue以打開Log4J內部的日志信息;另外PropertyConfigurator還支持Linux風格的變量,即所有${variable}形式的變量都會被系統中對應的屬性或配置文件內部定義的屬性替換(先查找系統中的屬性,后查找配置文件內部定義的屬性);但是PropertyConfigurator不支持一些Log4J中的高級功能,如自定義ErrorHandler和定義AsyncAppender等。

          Configurator中最重要的方法是doConfigure()方法,在PropertyConfigurator實現中,首先將配置文件對應的URL讀取成Properties對象:

           1 public void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
           2     Properties props = new Properties();
           3     
           4         uConn = configURL.openConnection();
           5         uConn.setUseCaches(false);
           6         istream = uConn.getInputStream();
           7         props.load(istream);
           8     
           9     doConfigure(props, hierarchy);
          10 }

          而后檢查是否設置了log4j.debuglog4j.resetlog4j.threshold等屬性,如果有則做相應的設置。這里通過OptionConverter.findAndSubst()方法實現屬性的查找和變量信息的替換。

           1 public void doConfigure(Properties properties, LoggerRepository hierarchy) {
           2     repository = hierarchy;
           3     String value = properties.getProperty(LogLog.DEBUG_KEY);
           4     if (value == null) {
           5         value = properties.getProperty("log4j.configDebug");
           6         if (value != null)
           7             LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
           8     }
           9     if (value != null) {
          10         LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
          11     }
          12     String reset = properties.getProperty(RESET_KEY);
          13     if (reset != null && OptionConverter.toBoolean(reset, false)) {
          14         hierarchy.resetConfiguration();
          15     }
          16     String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
          17             properties);
          18     if (thresholdStr != null) {
          19         hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
          20                 (Level) Level.ALL));
          21         LogLog.debug("Hierarchy threshold set to ["
          22                 + hierarchy.getThreshold() + "].");
          23     }
          24     
          25 }

          然后分三步解析配置信息:

          1.       解析Root Logger配置

          首先找到log4j.rootLogger的值,它以逗號’,’分隔,其中第一個值時rootLevel信息,之后是要添加到rootAppender名字。對Level信息,直接設置給root就行。對Appender名字,繼續解析。

           1 void parseCategory(Properties props, Logger logger, String optionKey,
           2         String loggerName, String value) {
           3     LogLog.debug("Parsing for [" + loggerName + "] with value=[" + value
           4             + "].");
           5     StringTokenizer st = new StringTokenizer(value, ",");
           6     if (!(value.startsWith(","|| value.equals(""))) {
           7         if (!st.hasMoreTokens())
           8             return;
           9         String levelStr = st.nextToken();
          10         LogLog.debug("Level token is [" + levelStr + "].");
          11         if (INHERITED.equalsIgnoreCase(levelStr)
          12                 || NULL.equalsIgnoreCase(levelStr)) {
          13             if (loggerName.equals(INTERNAL_ROOT_NAME)) {
          14                 LogLog.warn("The root logger cannot be set to null.");
          15             } else {
          16                 logger.setLevel(null);
          17             }
          18         } else {
          19             logger.setLevel(OptionConverter.toLevel(levelStr,
          20                     (Level) Level.DEBUG));
          21         }
          22         LogLog.debug("Category " + loggerName + " set to "
          23                 + logger.getLevel());
          24     }
          25     logger.removeAllAppenders();
          26     Appender appender;
          27     String appenderName;
          28     while (st.hasMoreTokens()) {
          29         appenderName = st.nextToken().trim();
          30         if (appenderName == null || appenderName.equals(","))
          31             continue;
          32         LogLog.debug("Parsing appender named \"" + appenderName + "\".");
          33         appender = parseAppender(props, appenderName);
          34         if (appender != null) {
          35             logger.addAppender(appender);
          36         }
          37     }
          38 }

          相同的Appender可以添加到不同的Logger中,因而PropertyConfiguratorAppender做了緩存,如果能從緩存中找到相應的Appender類,則直接返回找到的Appender

          而后解析以下鍵值名以及對應類的屬性信息:

          log4j.appender.appenderName=…

          log4j.appender.appenderName.layout=…

          log4j.appender.appenderName.errorhandler=…

          log4j.appender.appenderName.filter.filterKey.name=…

           1 Appender parseAppender(Properties props, String appenderName) {
           2     Appender appender = registryGet(appenderName);
           3     if ((appender != null)) {
           4         LogLog.debug("Appender \"" + appenderName
           5                 + "\" was already parsed.");
           6         return appender;
           7     }
           8     String prefix = APPENDER_PREFIX + appenderName;
           9     String layoutPrefix = prefix + ".layout";
          10     appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
          11             org.apache.log4j.Appender.classnull);
          12     if (appender == null) {
          13         LogLog.error("Could not instantiate appender named \""
          14                 + appenderName + "\".");
          15         return null;
          16     }
          17     appender.setName(appenderName);
          18     if (appender instanceof OptionHandler) {
          19         if (appender.requiresLayout()) {
          20             Layout layout = (Layout) OptionConverter.instantiateByKey(
          21                     props, layoutPrefix, Layout.classnull);
          22             if (layout != null) {
          23                 appender.setLayout(layout);
          24                 LogLog.debug("Parsing layout options for \"" + appenderName
          25                         + "\".");
          26                 PropertySetter.setProperties(layout, props, layoutPrefix
          27                         + ".");
          28                 LogLog.debug("End of parsing for \"" + appenderName + "\".");
          29             }
          30         }
          31         final String errorHandlerPrefix = prefix + ".errorhandler";
          32         String errorHandlerClass = OptionConverter.findAndSubst(
          33                 errorHandlerPrefix, props);
          34         if (errorHandlerClass != null) {
          35             ErrorHandler eh = (ErrorHandler) OptionConverter
          36                     .instantiateByKey(props, errorHandlerPrefix,
          37                             ErrorHandler.classnull);
          38             if (eh != null) {
          39                 appender.setErrorHandler(eh);
          40                 LogLog.debug("Parsing errorhandler options for \""
          41                         + appenderName + "\".");
          42                 parseErrorHandler(eh, errorHandlerPrefix, props, repository);
          43                 final Properties edited = new Properties();
          44                 final String[] keys = new String[] {
          45                         errorHandlerPrefix + "." + ROOT_REF,
          46                         errorHandlerPrefix + "." + LOGGER_REF,
          47                         errorHandlerPrefix + "." + APPENDER_REF_TAG };
          48                 for (Iterator iter = props.entrySet().iterator(); iter
          49                         .hasNext();) {
          50                     Map.Entry entry = (Map.Entry) iter.next();
          51                     int i = 0;
          52                     for (; i < keys.length; i++) {
          53                         if (keys[i].equals(entry.getKey()))
          54                             break;
          55                     }
          56                     if (i == keys.length) {
          57                         edited.put(entry.getKey(), entry.getValue());
          58                     }
          59                 }
          60                 PropertySetter.setProperties(eh, edited, errorHandlerPrefix
          61                         + ".");
          62                 LogLog.debug("End of errorhandler parsing for \""
          63                         + appenderName + "\".");
          64             }
          65         }
          66         PropertySetter.setProperties(appender, props, prefix + ".");
          67         LogLog.debug("Parsed \"" + appenderName + "\" options.");
          68     }
          69     parseAppenderFilters(props, appenderName, appender);
          70     registryPut(appender);
          71     return appender;
          72 }

          2.       解析LoggerFactory配置

          查找log4j.loggerFactory的值,保存創建的LoggerFactory實例,使用log4j.loggerFactory.propName的方式設置LoggerFactory實例的屬性。

           1 protected void configureLoggerFactory(Properties props) {
           2     String factoryClassName = OptionConverter.findAndSubst(
           3             LOGGER_FACTORY_KEY, props);
           4     if (factoryClassName != null) {
           5         LogLog.debug("Setting category factory to [" + factoryClassName
           6                 + "].");
           7         loggerFactory = (LoggerFactory) OptionConverter
           8                 .instantiateByClassName(factoryClassName,
           9                         LoggerFactory.class, loggerFactory);
          10         PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX
          11                 + ".");
          12     }
          13 }

          3.       解析非Root LoggerObjectRender配置

          解析log4j.logger.log4j.renderer.log4j.throwableRenderer.等信息。

          另外,PropertyConfigurator還通過PropertyWatchLog類支持每個一段時間檢查一次,如果發現配置文件有改動,則自動重新加載配置信息。

          DOMConfigurator

          DOMConfigurator使用DOM解析所有Log4J配置文件中的元素,并根據DOM中的元素查找對應的RootLoggerLoggerAppenderLayout等模塊。另外DOMConfigurator也支持每隔一段時間檢查文件是否有修改,若有,則重新載入新修改后的配置文件。這里DOMConfigurator的實現方式和PropertyConfigurator的實現方式類似,不再詳細介紹。

          LogManager

          LogManagerConfiguratorLoggerRepository整合在一起,它在初始化的時候找到Log4J配置文件,并且將其解析到LoggerRepository中。

           1 static {
           2     Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
           3     repositorySelector = new DefaultRepositorySelector(h);
           4     String override = OptionConverter.getSystemProperty(
           5             DEFAULT_INIT_OVERRIDE_KEY, null);
           6     if (override == null || "false".equalsIgnoreCase(override)) {
           7         String configurationOptionStr = OptionConverter.getSystemProperty(
           8                 DEFAULT_CONFIGURATION_KEY, null);
           9         String configuratorClassName = OptionConverter.getSystemProperty(
          10                 CONFIGURATOR_CLASS_KEY, null);
          11         URL url = null;
          12         if (configurationOptionStr == null) {
          13             url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
          14             if (url == null) {
          15                 url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
          16             }
          17         } else {
          18             try {
          19                 url = new URL(configurationOptionStr);
          20             } catch (MalformedURLException ex) {
          21                 url = Loader.getResource(configurationOptionStr);
          22             }
          23         }
          24         if (url != null) {
          25             LogLog.debug("Using URL [" + url
          26                     + "] for automatic log4j configuration.");
          27             try {
          28                 OptionConverter.selectAndConfigure(url,
          29                         configuratorClassName,
          30                         LogManager.getLoggerRepository());
          31             } catch (NoClassDefFoundError e) {
          32                 LogLog.warn("Error during default initialization", e);
          33             }
          34         } else {
          35             LogLog.debug("Could not find resource: ["
          36                     + configurationOptionStr + "].");
          37         }
          38     } else {
          39         LogLog.debug("Default initialization of overridden by "
          40                 + DEFAULT_INIT_OVERRIDE_KEY + "property.");
          41     }
          42 }

           

           

           

          posted on 2012-07-10 02:38 DLevin 閱讀(5212) 評論(0)  編輯  收藏 所屬分類: Logging
          主站蜘蛛池模板: 阜康市| 灵宝市| 南部县| 长春市| 灯塔市| 宜阳县| 昌黎县| 兴国县| 兰州市| 邢台县| 无锡市| 枝江市| 双柏县| 女性| 河北区| 屏东市| 维西| 万全县| 杭锦旗| 隆尧县| 嘉义县| 开平市| 光山县| 土默特右旗| 福鼎市| 云林县| 新田县| 亳州市| 勐海县| 长兴县| 施秉县| 古交市| 石楼县| 龙口市| 六枝特区| 北辰区| 探索| 巴林右旗| 铜山县| 老河口市| 泸水县|