17ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu/**
27ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * Copyright (c) 2004-2011 QOS.ch
37ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * All rights reserved.
47ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
57ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * Permission is hereby granted, free  of charge, to any person obtaining
67ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * a  copy  of this  software  and  associated  documentation files  (the
77ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * "Software"), to  deal in  the Software without  restriction, including
87ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * without limitation  the rights to  use, copy, modify,  merge, publish,
97ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * distribute,  sublicense, and/or sell  copies of  the Software,  and to
107ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * permit persons to whom the Software  is furnished to do so, subject to
117ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * the following conditions:
127ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
137ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * The  above  copyright  notice  and  this permission  notice  shall  be
147ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * included in all copies or substantial portions of the Software.
157ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
167ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
177ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
187ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
197ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
207ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
217ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
227ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
237ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
247ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu */
25cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersenpackage org.slf4j.agent;
26cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersen
271adb4e0c1aa8507a14e69f57cb61698f9b0e0859Thorbjorn Ravn Andersenimport java.io.ByteArrayInputStream;
281adb4e0c1aa8507a14e69f57cb61698f9b0e0859Thorbjorn Ravn Andersenimport java.io.IOException;
29cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersenimport java.lang.instrument.Instrumentation;
30cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersenimport java.util.Date;
311adb4e0c1aa8507a14e69f57cb61698f9b0e0859Thorbjorn Ravn Andersenimport java.util.Properties;
32cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersen
33cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersenimport org.slf4j.instrumentation.LogTransformer;
34cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersen
35fdb2c137a1e0917a356fe61846c4c406fb99fc7fThorbjorn Ravn Andersen/**
36fdb2c137a1e0917a356fe61846c4c406fb99fc7fThorbjorn Ravn Andersen * Entry point for slf4j-ext when used as a Java agent.
37a579aaf9c32a01a29111be23170824e6b0f3912aThorbjorn Ravn Andersen *
38fdb2c137a1e0917a356fe61846c4c406fb99fc7fThorbjorn Ravn Andersen */
39cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersenpublic class AgentPremain {
40cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersen
4131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
4231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * JavaAgent premain entry point as specified in the MANIFEST.MF file. See
4331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * {@link http
4431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * ://java.sun.com/javase/6/docs/api/java/lang/instrument/package-
4531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * summary.html} for details.
4631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
4731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @param agentArgument
4831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *            string provided after "=" up to first space
4931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @param instrumentation
5031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *            instrumentation environment provided by the JVM
5131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
5231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    public static void premain(String agentArgument, Instrumentation instrumentation) {
5331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
5431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        // We cannot do sanity checks for slf4j here as the jars loaded
5531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        // by the application are not visible here.
5631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
5731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        LogTransformer.Builder builder = new LogTransformer.Builder();
5831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        builder = builder.addEntryExit(true);
5931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
6031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (agentArgument != null) {
6131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Properties args = parseArguments(agentArgument, ",");
6231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
6331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (args.containsKey(AgentOptions.VERBOSE)) {
6431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                builder = builder.verbose(true);
6531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
6631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
6731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (args.containsKey(AgentOptions.TIME)) {
6831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                printStartStopTimes();
6931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
7031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
7131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (args.containsKey(AgentOptions.IGNORE)) {
7231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                String ignore = args.getProperty(AgentOptions.IGNORE);
7331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                builder = builder.ignore(ignore.split(":"));
7431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
7531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
7631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (args.containsKey(AgentOptions.LEVEL)) {
7731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                builder = builder.level(args.getProperty(AgentOptions.LEVEL));
7831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
7931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
8031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
8131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        instrumentation.addTransformer(builder.build());
8231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
8331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
8431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
8531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * Consider the argument string to be a property file (by converting the
8631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * splitter character to line feeds), and then reading it like any other
8731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * property file.
8831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
8931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
9031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @param agentArgument
9131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *            string given by instrumentation framework
9231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @param separator
9331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *            String to convert to line feeds
9431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @return argument converted to properties
9531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
9631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static Properties parseArguments(String agentArgument, String separator) {
9731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Properties p = new Properties();
9831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        try {
9931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            String argumentAsLines = agentArgument.replaceAll(separator, "\n");
10031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            p.load(new ByteArrayInputStream(argumentAsLines.getBytes()));
10131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        } catch (IOException e) {
10231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            String s = "Could not load arguments as properties";
10331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            throw new RuntimeException(s, e);
10431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
10531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        return p;
10631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
10731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
10831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
10931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * Print the start message to System.err with the time NOW, and register a
11031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * shutdown hook which will print the stop message to System.err with the
11131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * time then and the number of milliseconds passed since.
11231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
11331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
11431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static void printStartStopTimes() {
11531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        final long start = System.currentTimeMillis();
11631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
11731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        System.err.println("Start at " + new Date());
11831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
11931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Thread hook = new Thread() {
12031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            @Override
12131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            public void run() {
12231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                long timePassed = System.currentTimeMillis() - start;
12331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                System.err.println("Stop at " + new Date() + ", execution time = " + timePassed + " ms");
12431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
12531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        };
12631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Runtime.getRuntime().addShutdownHook(hook);
12731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
128cdfaeefef04d5b1500e897ecc75982a5316407e8Thorbjorn Ravn Andersen}