001    /*
002     * $Id: SqlStatistic.java,v 1.7 2014/05/17 17:31:34 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 16.04.2014 by oliver (ob@oasd.de)
019     */
020    
021    package patterntesting.runtime.monitor.db;
022    
023    import java.util.regex.Pattern;
024    
025    import org.slf4j.*;
026    
027    import patterntesting.runtime.monitor.*;
028    import patterntesting.runtime.monitor.db.internal.*;
029    import patterntesting.runtime.util.*;
030    
031    /**
032     * This class monitors and measures SQL statements. To be able to distinguish
033     * them from methods profiling it is a separate class derived from
034     * {@link ProfileStatistic}.
035     *
036     * @author oliver
037     * @since 1.4.2 (16.04.2014)
038     */
039    public class SqlStatistic extends ProfileStatistic implements SqlStatisticMBean {
040    
041        private static final Logger log = LoggerFactory.getLogger(SqlStatistic.class);
042        private static final SqlStatistic sqlInstance;
043    
044        /**
045         * rootMonitor *must* be initialized before isJamonAvailable() is called.
046         * Otherwise you'll get a NullPointerException because in
047         * JamonAvailable() rootMonitor will be accessed (so rootMonitor must
048         * be initialized before!)
049         */
050        static {
051            sqlInstance = new SqlStatistic();
052        }
053    
054        /**
055         * Gets the single instance of SqlStatistic.
056         *
057         * @return single instance of SqlStatistic
058         */
059        public static SqlStatistic getInstance() {
060            return sqlInstance;
061        }
062    
063        private SqlStatistic() {
064            super("SQL");
065        }
066    
067        /**
068         * To start a new statistic call this method. In contradiction to
069         * {@link ProfileStatistic#reset()} old {@link ProfileMonitor}s will be not
070         * kept.
071         */
072        public void reset() {
073            synchronized(SqlStatistic.class) {
074                this.resetRootMonitor();
075            }
076        }
077    
078        /**
079         * Start.
080         *
081         * @param sql the sql
082         * @return the started profile monitor
083         */
084        public static ProfileMonitor start(final String sql) {
085            return sqlInstance.startProfileMonitorFor(sql);
086        }
087    
088        /**
089         * Stops the given 'mon' and logs the given command with the needed time if
090         * debug is enabled.
091         *
092         * @param mon the mon
093         * @param command the command
094         */
095        public static void stop(final ProfileMonitor mon, final String command) {
096            stop(mon, command, Void.TYPE);
097        }
098    
099        /**
100         * Stops the given 'mon' and logs the given command with the needed time if
101         * debug is enabled.
102         *
103         * @param mon the mon
104         * @param command the command
105         * @param returnValue the return value
106         */
107        public static void stop(final ProfileMonitor mon, final String command, final Object returnValue) {
108            mon.stop();
109            if (log.isDebugEnabled()) {
110                String msg = '"' + command + "\" returned with " + Converter.toShortString(returnValue)
111                        + " after " + mon.getLastTime();
112                if (log.isTraceEnabled()) {
113                    StackTraceElement[] stacktrace = StackTraceScanner.getCallerStackTrace(
114                            new Pattern[0], SqlStatistic.class, StasiStatement.class,
115                            StasiPreparedStatement.class);
116                    log.trace("{}\n\t{}", msg, Converter.toLongString(stacktrace).trim());
117                } else {
118                    log.debug("{}.", msg);
119                }
120            }
121        }
122    
123        /**
124         * You can register the instance as shutdown hook. If the VM is
125         * terminated the profile values are logged and dumped to a CSV file in the
126         * tmp directory.
127         *
128         * @see #logStatistic()
129         * @see #dumpStatistic()
130         */
131        public static void addAsShutdownHook() {
132            addAsShutdownHook(sqlInstance);
133        }
134    
135    }