    001/**
    002 * Copyright (c) 2004-2011 QOS.ch
    003 * All rights reserved.
    004 *
    005 * Permission is hereby granted, free  of charge, to any person obtaining
    006 * a  copy  of this  software  and  associated  documentation files  (the
    007 * "Software"), to  deal in  the Software without  restriction, including
    008 * without limitation  the rights to  use, copy, modify,  merge, publish,
    009 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
    010 * permit persons to whom the Software  is furnished to do so, subject to
    011 * the following conditions:
    012 *
    013 * The  above  copyright  notice  and  this permission  notice  shall  be
    014 * included in all copies or substantial portions of the Software.
    015 *
    016 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
    017 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
    018 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
    019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    021 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
    022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    023 *
    024 */
    025package org.slf4j.agent;
    026
    027import java.io.ByteArrayInputStream;
    028import java.io.IOException;
    029import java.lang.instrument.Instrumentation;
    030import java.util.Date;
    031import java.util.Properties;
    032
    033import org.slf4j.instrumentation.LogTransformer;
    034
    035/**
    036 * Entry point for slf4j-ext when used as a Java agent.
    037 *
    038 */
    039public class AgentPremain {
    040
    041    /**
    042     * JavaAgent premain entry point as specified in the MANIFEST.MF file. See
    043     * <a href="http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html">http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html</a> for details.
    044     *
    045     * @param agentArgument
    046     *            string provided after "=" up to first space
    047     * @param instrumentation
    048     *            instrumentation environment provided by the JVM
    049     */
    050    public static void premain(String agentArgument, Instrumentation instrumentation) {
    051
    052        // We cannot do sanity checks for slf4j here as the jars loaded
    053        // by the application are not visible here.
    054
    055        LogTransformer.Builder builder = new LogTransformer.Builder();
    056        builder = builder.addEntryExit(true);
    057
    058        if (agentArgument != null) {
    059            Properties args = parseArguments(agentArgument, ",");
    060
    061            if (args.containsKey(AgentOptions.VERBOSE)) {
    062                builder = builder.verbose(true);
    063            }
    064
    065            if (args.containsKey(AgentOptions.TIME)) {
    066                printStartStopTimes();
    067            }
    068
    069            if (args.containsKey(AgentOptions.IGNORE)) {
    070                String ignore = args.getProperty(AgentOptions.IGNORE);
    071                builder = builder.ignore(ignore.split(":"));
    072            }
    073
    074            if (args.containsKey(AgentOptions.LEVEL)) {
    075                builder = builder.level(args.getProperty(AgentOptions.LEVEL));
    076            }
    077        }
    078
    079        instrumentation.addTransformer(builder.build());
    080    }
    081
    082    /**
    083     * Consider the argument string to be a property file (by converting the
    084     * splitter character to line feeds), and then reading it like any other
    085     * property file.
    086     *
    087     *
    088     * @param agentArgument
    089     *            string given by instrumentation framework
    090     * @param separator
    091     *            String to convert to line feeds
    092     * @return argument converted to properties
    093     */
    094    private static Properties parseArguments(String agentArgument, String separator) {
    095        Properties p = new Properties();
    096        try {
    097            String argumentAsLines = agentArgument.replaceAll(separator, "\n");
    098            p.load(new ByteArrayInputStream(argumentAsLines.getBytes()));
    099        } catch (IOException e) {
    100            String s = "Could not load arguments as properties";
    101            throw new RuntimeException(s, e);
    102        }
    103        return p;
    104    }
    105
    106    /**
    107     * Print the start message to System.err with the time NOW, and register a
    108     * shutdown hook which will print the stop message to System.err with the
    109     * time then and the number of milliseconds passed since.
    110     *
    111     */
    112    private static void printStartStopTimes() {
    113        final long start = System.currentTimeMillis();
    114
    115        System.err.println("Start at " + new Date());
    116
    117        Thread hook = new Thread() {
    118            @Override
    119            public void run() {
    120                long timePassed = System.currentTimeMillis() - start;
    121                System.err.println("Stop at " + new Date() + ", execution time = " + timePassed + " ms");
    122            }
    123        };
    124        Runtime.getRuntime().addShutdownHook(hook);
    125    }
    126}