001/* 002 * Stallion Core: A Modern Web Framework 003 * 004 * Copyright (C) 2015 - 2016 Stallion Software LLC. 005 * 006 * This program is free software: you can redistribute it and/or modify it under the terms of the 007 * GNU General Public License as published by the Free Software Foundation, either version 2 of 008 * the License, or (at your option) any later version. This program is distributed in the hope that 009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 011 * License for more details. You should have received a copy of the GNU General Public License 012 * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. 013 * 014 * 015 * 016 */ 017 018package io.stallion.services; 019 020import io.stallion.Context; 021import io.stallion.exceptions.ConfigException; 022import io.stallion.monitoring.HealthTracker; 023import io.stallion.settings.Settings; 024import org.apache.commons.io.FilenameUtils; 025 026import java.io.Console; 027import java.io.File; 028import java.io.IOException; 029import java.text.MessageFormat; 030import java.util.logging.*; 031 032import static io.stallion.utils.Literals.*; 033 034public class Log { 035 //private static Logger logger = LogManager.getLogManager().getLogger("stallion"); 036 private static Logger logger; 037 private static Handler handler; 038 private static Handler fileHandler; 039 private static boolean alwaysIncludeLineNumber = true; 040 041 static { 042 043 044 045 logger = Logger.getLogger("io.stallion"); 046 logger.config(""); 047 048 //TODO: configure the logger from settingsp 049 logger.setUseParentHandlers(false); 050 handler = new ConsoleHandler(); 051 //Level defaultLevel = Level.INFO; 052 //handler.setLevel(defaultLevel); 053 //logger.setLevel(defaultLevel); 054 055 handler.setFormatter(new LogFormatter()); 056 logger.addHandler(handler); 057 // Hack to fix a bug where ScssStylesheet will reset the global logger 058 System.setProperty("java.util.logging.config.file", "noop"); 059 } 060 061 /** 062 * Disable logging to the console 063 */ 064 public static void disableConsoleHandler() { 065 Log.info("Silencing console logger."); 066 logger.removeHandler(handler); 067 handler.close(); 068 } 069 070 /** 071 * Start logging to the file defined by "logFile" in settings files 072 */ 073 public static void enableFileLogger() { 074 logger.removeHandler(handler); 075 handler.close(); 076 String logPath = Settings.instance().getLogFile(); 077 if (!new File(logPath).getParentFile().isDirectory()) { 078 new File(logPath).getParentFile().mkdirs(); 079 } 080 try { 081 fileHandler = new FileHandler(logPath, 50000000, 7, true); 082 } catch (IOException e) { 083 throw new ConfigException("Invalid log file path: " + logPath); 084 } 085 fileHandler.setFormatter(new LogFormatter()); 086 handler.setLevel(logger.getLevel()); 087 logger.addHandler(fileHandler); 088 System.out.println("-----> Logging to file " + logPath + " at level " + logger.getLevel() + " ---->"); 089 } 090 091 092 093 public static void setLogLevel(Level level) { 094 handler.setLevel(level); 095 logger.setLevel(level); 096 if (fileHandler != null) { 097 fileHandler.setLevel(level); 098 } 099 } 100 101 public static Level getLogLevel() { 102 103 if (logger == null) { 104 return Level.OFF; 105 } else if (logger.getLevel() == null) { 106 107 return Level.INFO; 108 } else { 109 return logger.getLevel(); 110 } 111 } 112 113 114 public static void setLogLevelFromSettings() { 115 if (!empty(Context.getSettings().getLogLevel())) { 116 Level level = Level.parse(Context.getSettings().getLogLevel()); 117 handler.setLevel(level); 118 logger.setLevel(level); 119 if (fileHandler != null) { 120 fileHandler.setLevel(level); 121 } 122 } 123 if (!empty(Context.getSettings().getPackageLogLevels())) { 124 LogFilter filter = new LogFilter(logger.getLevel(), Context.getSettings().getPackageLogLevels()); 125 logger.setFilter(filter); 126 } 127 } 128 129 public static void fine(String message, Object ... args) { 130 if (getLogLevel().intValue() > Level.FINE.intValue()) { 131 return; 132 } 133 //System.out.println(message); 134 if (alwaysIncludeLineNumber) { 135 Throwable t = new Throwable(); 136 t.getStackTrace()[2].toString(); 137 String clz = t.getStackTrace()[2].getClassName().replace("io.stallion.", ""); 138 String method = t.getStackTrace()[2].getMethodName(); 139 logger.logp(Level.FINE, clz, method, message, args); 140 } else { 141 logger.logp(Level.FINE, "", "", message, args); 142 } 143 144 } 145 146 public static void finer(String message, Object ... args) { 147 if (getLogLevel().intValue() > Level.FINER.intValue()) { 148 return; 149 } 150 151 //System.out.println(message); 152 153 Throwable t = new Throwable(); 154 t.getStackTrace()[2].toString(); 155 String clz = t.getStackTrace()[2].getClassName().replace("io.stallion.", ""); 156 String method = t.getStackTrace()[2].getMethodName(); 157 logger.logp(Level.FINER, clz, method, message, args); 158 159 } 160 161 public static void finest(String message, Object ... args) { 162 if (getLogLevel().intValue() > Level.FINEST.intValue()) { 163 return; 164 } 165 //System.out.println(message); 166 Throwable t = new Throwable(); 167 t.getStackTrace()[2].toString(); 168 String clz = t.getStackTrace()[2].getClassName().replace("io.stallion.", ""); 169 String method = t.getStackTrace()[2].getMethodName(); 170 logger.logp(Level.FINEST, clz, method, message, args); 171 172 } 173 174 public static void info(String message, Object ... args) { 175 if (getLogLevel().intValue() > Level.INFO.intValue()) { 176 return; 177 } 178 // Info statements don't include the class and line number, since that kills performance 179 //System.out.println(message); 180 if (alwaysIncludeLineNumber) { 181 Throwable t = new Throwable(); 182 StackTraceElement stackTraceElement = t.getStackTrace()[1]; 183 String clz = stackTraceElement.getClassName().replace("io.stallion.", ""); 184 String method = stackTraceElement.getMethodName() + ":" + t.getStackTrace()[1].getLineNumber(); 185 logger.logp(Level.INFO, clz, method, message, args); 186 } else { 187 logger.logp(Level.INFO, "", "", message, args); 188 } 189 190 } 191 192 public static void warning(String message, Object ... args) { 193 if (getLogLevel().intValue() > Level.WARNING.intValue()) { 194 return; 195 } 196 Throwable t = new Throwable(); 197 StackTraceElement stackTraceElement = t.getStackTrace()[1]; 198 String clz = stackTraceElement.getClassName().replace("io.stallion.", ""); 199 String method = stackTraceElement.getMethodName() + ":" + t.getStackTrace()[1].getLineNumber(); 200 logger.logp(Level.WARNING, clz, method, message, args); 201 202 } 203 204 205 206 public static void warn(String message, Object ... args) { 207 if (getLogLevel().intValue() > Level.WARNING.intValue()) { 208 return; 209 } 210 Throwable t = new Throwable(); 211 StackTraceElement stackTraceElement = t.getStackTrace()[1]; 212 String clz = stackTraceElement.getClassName().replace("io.stallion.", ""); 213 String method = stackTraceElement.getMethodName() + ":" + t.getStackTrace()[1].getLineNumber(); 214 logger.logp(Level.WARNING, clz, method, message, args); 215 216 } 217 218 /** 219 * Logs a message, setting the class, method and source line number using the stack frame index passed in. 220 * This is useful if you are wrapping a logging class, and want to include the line number from where 221 * the wrapper method is called. 222 * 223 * @param frame - the stack frame to use. Use '2' to log to one level above the caller 224 * @param level 225 * @param message 226 * @param args 227 */ 228 public static void logForFrame(int frame, Level level, String message, Object ...args) { 229 if (getLogLevel().intValue() > level.intValue()) { 230 return; 231 } 232 Throwable t = new Throwable(); 233 StackTraceElement stackTraceElement = t.getStackTrace()[frame]; 234 String clz = stackTraceElement.getClassName().replace("io.stallion.", ""); 235 String method = stackTraceElement.getMethodName() + ":" + t.getStackTrace()[frame].getLineNumber(); 236 logger.logp(level, clz, method, message, args); 237 } 238 239 240 public static void exception(Throwable ex, String message, Object ... args) { 241 HealthTracker.instance().logException(ex); 242 if (getLogLevel().intValue() > Level.SEVERE.intValue()) { 243 return; 244 } 245 if (args.length > 0) { 246 message = MessageFormat.format(message, args); 247 } 248 // TODO: WTF -- figure out how the hell the handler got removed; 249 if (logger.getHandlers().length == 0) { 250 logger.addHandler(handler); 251 } 252 Throwable t = new Throwable(); 253 StackTraceElement stackTraceElement = t.getStackTrace()[1]; 254 String clz = stackTraceElement.getClassName().replace("io.stallion.", ""); 255 String method = stackTraceElement.getMethodName() + ":" + t.getStackTrace()[1].getLineNumber(); 256 logger.logp(Level.SEVERE, clz, method, message, ex); 257 } 258 259 public static boolean isAlwaysIncludeLineNumber() { 260 return alwaysIncludeLineNumber; 261 } 262 263 public static void setAlwaysIncludeLineNumber(boolean alwaysIncludeLineNumber) { 264 Log.alwaysIncludeLineNumber = alwaysIncludeLineNumber; 265 } 266}