001 /*
002 * $Id: PerfLogger.java,v 1.8 2014/05/17 06:55:25 oboehm Exp $
003 *
004 * Copyright (c) 2014 by Oliver Boehm
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 *
018 * (c)reated 17.03.2014 by oliver (ob@oasd.de)
019 */
020
021 package patterntesting.runtime.log;
022
023 import org.slf4j.*;
024
025 import patterntesting.runtime.monitor.ProfileMonitor;
026 import patterntesting.runtime.util.Converter;
027
028 /**
029 * This class is a kind of performance logger to be able to log the execution
030 * times of methods or code segments which may need a little bit longer. It can
031 * be used as a replacement of a normal logger.
032 * <p>
033 * We use a {@link LogWatch} to measure the times between a
034 * {@link #start(String, Object...)} and {@link #end(String, Object...)} call.
035 * We store this {@link LogWatch} as {@link ThreadLocal} because loggers are
036 * normally used as static variables. So we can be sure that each thread has
037 * its own {@link LogWatch}.
038 * </p>
039 *
040 * @author oliver
041 * @since 1.4.1 (17.03.2014)
042 * @version $Revision: 1.8 $
043 */
044 public final class PerfLogger {
045
046 private final Logger logger;
047
048 /** The local stopwatch. */
049 private final ThreadLocal<LogWatch> timer = new ThreadLocal<LogWatch>() {
050 @Override
051 protected LogWatch initialValue() {
052 LogWatch watch = new LogWatch();
053 return watch;
054 }
055 };
056
057 /**
058 * Instantiates a new perf logger.
059 */
060 public PerfLogger() {
061 this(PerfLogger.class);
062 }
063
064 /**
065 * Instantiates a new perf logger.
066 *
067 * @param clazz the clazz
068 */
069 public PerfLogger(final Class<?> clazz) {
070 this(LoggerFactory.getLogger(clazz));
071 }
072
073 /**
074 * Instantiates a new perf logger.
075 *
076 * @param logger the logger
077 */
078 public PerfLogger(final Logger logger) {
079 this.logger = logger;
080 }
081
082 /**
083 * Start the log for the given message. The default level for the logged
084 * message is "INFO".
085 *
086 * @param format the format
087 * @param args the args
088 */
089 public void start(final String format, final Object... args) {
090 this.start(SimpleLog.LOG_LEVEL_INFO, format, args);
091 }
092
093 /**
094 * Start the log for the given message. For the valid log levels see
095 *
096 * @param level the level
097 * @param format the format
098 * @param args the args
099 * {@link SimpleLog}.
100 * @see SimpleLog
101 */
102 public void start(final int level, final String format, final Object... args) {
103 this.log(level, format, args);
104 timer.get().start();
105 }
106
107 /**
108 * End the log with the given message. The output will contain the measure
109 * time from the last {@link #start(String, Object...)} log. So be sure to
110 * call one of the start methods before.
111 * <p>
112 * The default level for the logged message is "INFO".
113 * </p>
114 *
115 * @param format the format
116 * @param args the args
117 */
118 public void end(final String format, final Object... args) {
119 this.end(SimpleLog.LOG_LEVEL_INFO, format, args);
120 }
121
122 /**
123 * End the log with the given message. The output will contain the measure
124 * time from the last {@link #start(String, Object...)} log. So be sure to
125 * call one of the start methods before.
126 * <p>
127 * It is recommended to use the same as in
128 *
129 * @param level the level
130 * @param format the format
131 * @param args the args
132 * {@link #start(int, String, Object...)}. If the reported times is greater
133 * than 1 minute the log level will be increased at least to "INFO".
134 * </p>
135 */
136 public void end(int level, final String format, final Object... args) {
137 LogWatch watch = timer.get();
138 watch.stop();
139 long millis = watch.getElapsedTime();
140 if ((millis > 60000L) && (level < SimpleLog.LOG_LEVEL_INFO)) {
141 this.logger.trace("Log level will be increased from {} to 'INFO'", level);
142 level = SimpleLog.LOG_LEVEL_INFO;
143 }
144 this.log(level, format + " finished after " + watch + ".", args);
145 }
146
147 /**
148 * Log.
149 *
150 * @param level the level
151 * @param format the format
152 * @param args the args
153 */
154 public void log(final int level, final String format, final Object... args) {
155 switch (level) {
156 case SimpleLog.LOG_LEVEL_TRACE:
157 this.logger.trace(format, args);
158 break;
159 case SimpleLog.LOG_LEVEL_DEBUG:
160 this.logger.debug(format, args);
161 break;
162 case SimpleLog.LOG_LEVEL_INFO:
163 this.logger.info(format, args);
164 break;
165 case SimpleLog.LOG_LEVEL_WARN:
166 this.logger.warn(format, args);
167 break;
168 case SimpleLog.LOG_LEVEL_ERROR:
169 case SimpleLog.LOG_LEVEL_FATAL:
170 this.logger.trace(format, args);
171 break;
172 default:
173 this.logger.info("Level " + level + ": " + format, args);
174 break;
175 }
176 }
177
178 /**
179 * Error.
180 *
181 * @param format the format
182 * @param args the args
183 */
184 public void error(final String format, final Object... args) {
185 logger.error(format, args);
186 }
187
188 /**
189 * Warn.
190 *
191 * @param format the format
192 * @param args the args
193 */
194 public void warn(final String format, final Object... args) {
195 logger.warn(format, args);
196 }
197
198 /**
199 * Info.
200 *
201 * @param format the format
202 * @param args the args
203 */
204 public void info(final String format, final Object... args) {
205 logger.info(format, args);
206 }
207
208 /**
209 * Debug.
210 *
211 * @param format the format
212 * @param args the args
213 */
214 public void debug(final String format, final Object... args) {
215 logger.debug(format, args);
216 }
217
218 /**
219 * Stops the given 'mon' and logs the given command with the needed time if
220 * debug is enabled.
221 *
222 * @param mon the mon
223 * @param command the command
224 * @deprecated moved to SqlStatistic class
225 */
226 @Deprecated
227 public void stop(final ProfileMonitor mon, final String command) {
228 stop(mon, command, Void.TYPE);
229 }
230
231 /**
232 * Stops the given 'mon' and logs the given command with the needed time if
233 * debug is enabled.
234 *
235 * @param mon the mon
236 * @param command the command
237 * @param returnValue the return value
238 * @deprecated moved to SqlStatistic class
239 */
240 @Deprecated
241 public void stop(final ProfileMonitor mon, final String command, final Object returnValue) {
242 mon.stop();
243 if (logger.isDebugEnabled()) {
244 logger.debug("\"{}\" returned with {} after {}.", command,
245 Converter.toShortString(returnValue), mon.getLastTime());
246 }
247 }
248
249 /**
250 * Trace.
251 *
252 * @param format the format
253 * @param args the args
254 */
255 public void trace(final String format, final Object... args) {
256 logger.trace(format, args);
257 }
258
259 /**
260 * Checks if is debug enabled.
261 *
262 * @return true, if is debug enabled
263 */
264 public boolean isDebugEnabled() {
265 return logger.isDebugEnabled();
266 }
267
268 }
269