001package org.cache2k.impl.util; 002 003/* 004 * #%L 005 * cache2k core package 006 * %% 007 * Copyright (C) 2000 - 2015 headissue GmbH, Munich 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.util.ServiceLoader; 026import java.util.WeakHashMap; 027import java.util.concurrent.atomic.AtomicInteger; 028import java.util.logging.Level; 029import java.util.logging.Logger; 030 031/** 032 * cache2k has only sparse logging. The direct use of java.util.logging was 033 * examined. However, a thread name is missing within the output and it 034 * is not properly recorded. To have the chance to redirect any 035 * logging to the framework of choice, the log output is channeled 036 * through this class. 037 * 038 * <p/>To hook in another log framework provide another LogFactory 039 * implementation via the service loader. 040 * 041 * @author Jens Wilke; created: 2014-04-27 042 * @see ServiceLoader 043 */ 044public abstract class Log { 045 046 static WeakHashMap<String, Log> loggers = new WeakHashMap<String, Log>(); 047 048 static LogFactory logFactory; 049 050 public static Log getLog(Class<?> _class) { 051 return getLog(_class.getName()); 052 } 053 054 public static synchronized Log getLog(String s) { 055 Log l = loggers.get(s); 056 if (l != null) { 057 return l; 058 } 059 if (logFactory != null) { 060 l = logFactory.getLog(s); 061 loggers.put(s, l); 062 return l; 063 } 064 ServiceLoader<LogFactory> loader = ServiceLoader.load(LogFactory.class); 065 for (LogFactory lf : loader) { 066 logFactory = lf; 067 getLog(Log.class.getName()).debug("New instance, using: " + logFactory); 068 return getLog(s); 069 } 070 try { 071 final org.apache.commons.logging.LogFactory cl = 072 org.apache.commons.logging.LogFactory.getFactory(); 073 logFactory = new LogFactory() { 074 @Override 075 public Log getLog(String s) { 076 return new CommonsLogger(cl.getInstance(s)); 077 } 078 }; 079 getLog(Log.class.getName()).debug("New instance, using: " + logFactory); 080 return getLog(s); 081 } catch (NoClassDefFoundError ignore) { 082 } 083 logFactory = new LogFactory() { 084 @Override 085 public Log getLog(String s) { 086 return new JdkLogger(Logger.getLogger(s)); 087 } 088 }; 089 getLog(Log.class.getName()).debug("New instance, using: " + logFactory); 090 return getLog(s); 091 } 092 093 /** 094 * Redirects log output, this is used for testing purposes. 095 */ 096 public static synchronized void registerSuppression(String s, Log l) { 097 loggers.put(s, l); 098 } 099 100 public static synchronized void unregisterSuppression(String s) { 101 loggers.remove(s); 102 } 103 104 public abstract boolean isDebugEnabled(); 105 106 public abstract boolean isInfoEnabled(); 107 108 public abstract void debug(String s); 109 110 public abstract void debug(String s, Throwable ex); 111 112 public abstract void info(String s); 113 114 public abstract void info(String s, Throwable ex); 115 116 public abstract void warn(String s); 117 118 public abstract void warn(String s, Throwable ex); 119 120 private static class CommonsLogger extends Log { 121 122 org.apache.commons.logging.Log cLog; 123 124 private CommonsLogger(org.apache.commons.logging.Log cLog) { 125 this.cLog = cLog; 126 } 127 128 @Override 129 public boolean isDebugEnabled() { 130 return cLog.isDebugEnabled(); 131 } 132 133 @Override 134 public boolean isInfoEnabled() { 135 return cLog.isInfoEnabled(); 136 } 137 138 @Override 139 public void debug(String s) { 140 cLog.debug(s); 141 } 142 143 @Override 144 public void debug(String s, Throwable ex) { 145 cLog.debug(s, ex); 146 } 147 148 @Override 149 public void info(String s, Throwable ex) { 150 cLog.info(s); 151 } 152 153 @Override 154 public void info(String s) { 155 cLog.info(s); 156 } 157 158 @Override 159 public void warn(String s) { 160 cLog.warn(s); 161 } 162 163 @Override 164 public void warn(String s, Throwable ex) { 165 cLog.warn(s, ex); 166 } 167 } 168 169 private static class JdkLogger extends Log { 170 171 Logger logger; 172 173 private JdkLogger(Logger logger) { 174 this.logger = logger; 175 } 176 177 @Override 178 public boolean isDebugEnabled() { 179 return logger.isLoggable(Level.FINE); 180 } 181 182 @Override 183 public boolean isInfoEnabled() { 184 return logger.isLoggable(Level.INFO); 185 } 186 187 @Override 188 public void debug(String s) { 189 logger.log(Level.FINE, s); 190 } 191 192 @Override 193 public void debug(String s, Throwable ex) { 194 logger.log(Level.FINE, s, ex); 195 } 196 197 @Override 198 public void info(String s) { 199 logger.log(Level.INFO, s); 200 } 201 202 @Override 203 public void info(String s, Throwable ex) { 204 logger.log(Level.INFO, s, ex); 205 } 206 207 @Override 208 public void warn(String s) { 209 logger.log(Level.WARNING, s); 210 } 211 212 @Override 213 public void warn(String s, Throwable ex) { 214 logger.log(Level.WARNING, s, ex); 215 } 216 } 217 218 /** 219 * Log implementation that can be used to count suppressed log outputs. 220 */ 221 public static class SuppressionCounter extends Log { 222 223 AtomicInteger debugCount = new AtomicInteger(); 224 AtomicInteger infoCount = new AtomicInteger(); 225 AtomicInteger warnCount = new AtomicInteger(); 226 227 @Override 228 public boolean isDebugEnabled() { 229 return true; 230 } 231 232 @Override 233 public boolean isInfoEnabled() { 234 return true; 235 } 236 237 @Override 238 public void debug(String s) { 239 debugCount.incrementAndGet(); 240 } 241 242 @Override 243 public void debug(String s, Throwable ex) { 244 debugCount.incrementAndGet(); 245 } 246 247 @Override 248 public void info(String s, Throwable ex) { 249 infoCount.incrementAndGet(); 250 } 251 252 @Override 253 public void info(String s) { 254 infoCount.incrementAndGet(); 255 } 256 257 @Override 258 public void warn(String s) { 259 warnCount.incrementAndGet(); 260 } 261 262 @Override 263 public void warn(String s, Throwable ex) { 264 warnCount.incrementAndGet(); 265 } 266 267 public int getDebugCount() { 268 return debugCount.get(); 269 } 270 271 public int getInfoCount() { 272 return infoCount.get(); 273 } 274 275 public int getWarnCount() { 276 return warnCount.get(); 277 } 278 } 279 280}