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 long timePassed = System.currentTimeMillis() - start; 119 System.err.println("Stop at " + new Date() + ", execution time = " + timePassed + " ms"); 120 }); 121 Runtime.getRuntime().addShutdownHook(hook); 122 } 123}