SLF4J 拓展-Java-优质IT资源分享社区

admin
管理员
管理员
  • UID1
  • 粉丝26
  • 关注4
  • 发帖数581
  • 社区居民
  • 忠实会员
  • 原创写手
阅读:160回复:0

  SLF4J 拓展

楼主#
更多 发布于:2016-05-22 15:06

SLF4J 拓展被打包在slf4j-ext.jar里,它跟着 SLF4J 一同发布。

主要内容包括如下几有些:

功用剖析器(Profiler)

MDCStrLookup

拓展日志(Extended logger)

作业日志(Event Logging)

经过Java 署理(agent)来增加日志

功用剖析器(Profiler)

啥是功用剖析器?

根据维基百科(Wikipedia)介绍,功用剖析(Profiling)

是经过收集程序时的信息,来对程序做法进行一种研讨剖析活动,相关于静态的代码剖析来说,这是一种动态的程序剖析。

功用剖析一般是为了断定对程序中哪块有些的运转速度或许内存运用进行优化。

SLF4J

功用剖析器,能够说是一种弱剖析器,将协助开发人员收集功用数据。本质上来讲,功用剖析器即是由一个或许多个秒表(stopwatches)构成的。秒表由源码中的句子来驱动开端或许完毕。一个示例或许将这点解释得更明晰。

根本示例

32  public class BasicProfilerDemo {3334    public

static void main(String[] args) {35      // create a profiler called "BASIC"36  

   Profiler profiler = new Profiler("BASIC");37      profiler.start("A");38    

 doA();3940      profiler.start("B");41      doB();4243    

 profiler.start("OTHER");44      doOther();45      profiler.stop().print();46  

 }

运转上面的示例将输出如下内容:

+ Profiler [BASIC]|-- elapsed time                

     [A]   220.487 milliseconds.|-- elapsed time                      [B]

 2499.866 milliseconds.|-- elapsed time                  [OTHER]  3300.745

milliseconds.|-- Total                         [BASIC]  6022.568

milliseconds.

实例化一个功用剖析器就发动了一个大局秒表。每次调用start()办法将发动一个新的被命名了的秒表。除了发动一个命名了的秒表,start()办法还将导致上一个秒表中止。因而,调用profiler.start("A")时,发动了一个被命名为 A 的秒表。随后,调用profiler.start("B")将发动秒表 B,而且一起将中止秒表 A。在一个功用剖析器实例上调用stop(),将中止最终一个秒表和随同剖析器实例化而发动起来的大局秒表。

剖析器嵌套

剖析器也能够嵌套。经过嵌套的剖析器,不只能够丈量一个使命的耗时,还能够丈量需求战略的子使命的耗时。

发动嵌套的剖析器将中止曾经一切现已发动的秒表或许有关到上级剖析器。

通常状况下,子使命会被不一样的类来完结,而且保管着上级剖析器。运用ProfilerRegistry是

一种方便地将嵌套剖析器从当时方针传递到别的方针的办法。每一个线程都有自己的剖析器注册表

(profiler

registry),能够经过调用getThreadContextInstance()办法来获取。

33  public class NestedProfilerDemo {3435  

 public static void main(String[] args) {36      // create a profiler called

"DEMO"37      Profiler profiler = new Profiler("DEMO");3839      // register

this profiler in the thread context's profiler registry40      ProfilerRegistry

profilerRegistry = ProfilerRegistry.getThreadContextInstance();41    

 profiler.registerWith(profilerRegistry);4243      // start a stopwatch called

"RANDOM"44      profiler.start("RANDOM");45      RandomIntegerArrayGenerator

riaGenerator = new RandomIntegerArrayGenerator();46      int n = 1000*1000;47  

   int[] randomArray = riaGenerator.generate(n);4849      // create and start a

nested profiler called "SORT_AND_PRUNE"50      // By virtue of its parent-child

relationship with the "DEMO"51      // profiler, and the previous registration

of the parent profiler,52      // this nested profiler will be automatically

registered53      // with the thread context's profiler registry54    

 profiler.startNested(SortAndPruneComposites.NESTED_PROFILER_NAME);5556    

 SortAndPruneComposites pruner = new SortAndPruneComposites(randomArray);57    

 pruner.sortAndPruneComposites();5859      // stop and print the "DEMO"

printer60      profiler.stop().print();61    }62  }

这是引证的有关类:SortAndPruneComposites。

6   public class SortAndPruneComposites {78    

static String NESTED_PROFILER_NAME = "SORT_AND_PRUNE";910    final int[]

originalArray;11    final int originalArrayLength;1213    public

SortAndPruneComposites(int[] randomArray) {14      this.originalArray =

randomArray;15      this.originalArrayLength = randomArray.length;1617    }1819

   public int[] sortAndPruneComposites() {20      // retrieve previously

registered profiler named "SORT_AND_PRUNE"21      ProfilerRegistry

profilerRegistry = ProfilerRegistry.getThreadContextInstance();22      Profiler

sortProfiler = profilerRegistry.get(NESTED_PROFILER_NAME);2324      // start a

new stopwatch called SORT25      sortProfiler.start("SORT");26      int[]

sortedArray = sort();27      // start a new stopwatch called PRUNE_COMPOSITES28

     sortProfiler.start("PRUNE_COMPOSITES");29      int result[] =

pruneComposites(sortedArray);3031      return result;32    }

在双核而且主频为 3.2G 赫兹的 Intel CPU

上,运转这个ProfilerDemo发作如下输出:

+ Profiler [DEMO]|-- elapsed time                

[RANDOM]    70.524 milliseconds.|---+ Profiler [SORT_AND_PRUNE]    |-- elapsed

time                   [SORT]   665.281 milliseconds.    |-- elapsed time      

[PRUNE_COMPOSITES]  5695.515 milliseconds.    |-- Subtotal            

[SORT_AND_PRUNE]  6360.866 milliseconds.|-- elapsed time        

[SORT_AND_PRUNE]  6360.866 milliseconds.|-- Total                        

 [DEMO]  6433.922 milliseconds.

从上面的比如中,咱们能够得出发作 1 000 000 个随机整数需求耗费 70 毫秒,排序需求

665 毫秒,裁剪 5695 毫秒,总计耗时 6433 毫秒。从这儿输出能够看出,裁剪计算占用了最多的 CPU

时刻,将来任何优化都将直接在裁剪有些进行。

经过放置一些恰当的剖析器调用,咱们就能够识别出咱们程序中的热门。一起,咱们也应当留意到,为了将一个剖析器传递到方针类,咱们能够经过将剖析器注册到注册表,然后就能够在方针类中获取出来。

运用日志输出

调用profiler.print()将在操控台中打印出成果。假如你想在生成环境中也保留剖析器,那么

你或许需求操控输出目的地。你能够经过将一个剖析器有关到你挑选的一个日志上来完结。

当你将一个剖析器和一个日志进行有关后,你只需求经过调用log()来替代上面调用print(),

下面是演示示例:

17  public class NestedProfilerDemo2 {1819  

 static Logger logger = LoggerFactory.getLogger(NestedProfilerDemo2.class);2021

   public static void main(String[] args) {22      Profiler profiler = new

Profiler("DEMO");23      // associate a logger with the profiler24    

 profiler.setLogger(logger);2526      ProfilerRegistry profilerRegistry =

ProfilerRegistry.getThreadContextInstance();27    

 profiler.registerWith(profilerRegistry);2829      profiler.start("RANDOM");30  

   RandomIntegerArrayGenerator riaGenerator = new

RandomIntegerArrayGenerator();31      int n = 10*1000;32      int[] randomArray

= riaGenerator.generate(n);3334    

 profiler.startNested(SortAndPruneComposites.NESTED_PROFILER_NAME);3536    

 SortAndPruneComposites pruner = new SortAndPruneComposites(randomArray);37    

 pruner.sortAndPruneComposites();3839      // stop and log40    

 profiler.stop().log();41    }42  }

上面比如的输出依靠日志环境,可是和上面的NestedProfilerDemo比如的输出很相似。

log()办法在DEBUG根本输出,而且运用 PROFILER 作为符号。

假如你的日志体系支撑符号(marker),例如 logback,你能够清晰地启用或许禁用 SLF4J

剖析器

输出。下面是 logback 装备文件,禁用任何匹配 PROFILER 符号的日志,即便DEBUG等级

的日志能够输出。

PROFILERDENY%-5level %logger{36} -

%msg%n

MDCStrLookup

StrLookup是一个界说在 Apache Commons Lang 中的类。It is used

in conjunction

with the StrSubstitutor class to allow Strings to

have tokens in the Strings

dynamically replaced at run time. There are many

cases where it is desirable to

merge the values for keys in the SLF4J MDC into

Strings. MDCStrLookup makes this possible.

Apache Commons Configuration provides

aConfigurationInterpolatorclass. This

class allows new StrLookups to be registered and

the values can then be used to

merge with both the configuration of Commons

Configuration as well as the

configuration files it manages.

StrLookup obviously has a dependency on Commons

Lang. The Maven pom.xml for

slf4j-ext lists this dependency as optional so

that those wishing to use other

extensions are not required to unnecessarily

package the commons lang jar.

Therefore, when using MDCStrLookup the dependency

for commons-lang must be

explicitly declared along with slf4j-ext.

拓展日志(Extended logger)

XLogger类供给了一些额定的日志办法,履行途径后的程序十分有用。这些办法发作日志作业,可

以从别的的调试日志中过滤出来。鼓舞运用这些办法,输出能够

在开发环境下,有助于在没有调试会话时确诊疑问。

在生成环境下,即便没有调试,确诊疑问也成为也许。

协助训练新的开发人员学习运用。

最常用的是entry()和exit()办法。entry()应当放在办法的开端有些,除了简略的

Getter

和 Setter 办法。entry()能够经过 0 到 4

个参数来调用。代表性的一种状况是,它们是传递

给这个办法的参数。entry()办法运用TRACE等级的日志,而且运用一个姓名为 ENTER 的符号,

这也是一个 FLOW 符号。

exit()办法应当放置在任何回来句子之前,或许没有回来的办法的最终一句。exit()能够经过

一个或许零个参数来调用。具有代表性的是,假如办法回来为void,则运用exit();假如返

回一个方针,则运用exit(Object

obj)。entry()办法运用TRACE根本的日志,而且运用

一个姓名为 EXIT 的符号,这也是一个 FLOW 符号。

throwing()办法能够用于处理程序抛出而又不也许处理反常,例如RuntimeException。这

能够显着保证恰当确诊信息是可用的,假如需求的话。这个日志作业发作将运用ERROR根本的日志,

而且和命名为 THROWING 的符号有关,这也是一个 EXCEPTION 符号

catching()办法能够被程序用于它捕获一个反常,而且又不想再次抛出,能够是清晰的Exception

或许别的反常。这个日志作业发作将运用ERROR根本的日志,而且和命名为 CATCHING 的标

记有关,这也是一个 EXCEPTION 符号

经过运用这些拓展办法,规范了 SLF4J

的运用,程序能够坚信,它们能够以一种规范的办法来展现确诊日志。

留意,XLogger实例能够经过XLoggerFactory东西类来取得。

接下来的比如演示了一个简略程序以恰当典型的办法运用这些办法。throwing()办法没有展现,

这是由于没有反常要而且抛出而且不处理。

package com.test;import

org.slf4j.ext.XLogger;import org.slf4j.ext.XLoggerFactory;import

java.util.Random;public class TestService {  private XLogger logger =

XLoggerFactory.getXLogger(TestService.class      .getName());  private String[]

messages = new String[] { "Hello, World",      "Goodbye Cruel World", "You had

me at hello" };  private Random rand = new Random(1);  public String

retrieveMessage() {    logger.entry();    String testMsg = getMessage(getKey());

   logger.exit(testMsg);    return testMsg;  }  public void exampleException() {

   logger.entry();    try {      String msg = messages[messages.length];    

 logger.error("An exception should have been thrown");    } catch (Exception ex)

{      logger.catching(ex);    }    logger.exit();  }  public String

getMessage(int key) {    logger.entry(key);    String value = messages[key];  

 logger.exit(value);    return value;  }  private int getKey() {  

 logger.entry();    int key = rand.nextInt(messages.length);  

 logger.exit(key);    return key;  }}

这些测验运用运用了前面的效劳来发作日志作业。

package com.test;public class App {  public static

void main( String[] args )    {    TestService service = new TestService();  

 service.retrieveMessage();    service.retrieveMessage();  

 service.exampleException();  }}

下面的装备将一切的输出路由到target/test.log。供给给FileAppender的形式,包括了类名,

行号以及办法名。在形式中包括这些内容关于日志的值来说是十分要害的。

ERRORACCEPTDENY%d{HH:mm:ss.SSS}

%-5level %class{36}:%L %M - %msg%ntarget/test.logfalse%d{HH:mm:ss.SSS}

%-5level %class{36}:%L %M - %msg%n

下面是上面 Java 类以及装备文件的输出成果。

00:07:57.725 TRACE com.test.TestService:22

retrieveMessage - entry00:07:57.738 TRACE com.test.TestService:57 getKey -

entry00:07:57.739 TRACE com.test.TestService:59 getKey - exit with

(0)00:07:57.741 TRACE com.test.TestService:47 getMessage - entry with

(0)00:07:57.741 TRACE com.test.TestService:51 getMessage - exit with (Hello,

World)00:07:57.742 TRACE com.test.TestService:26 retrieveMessage - exit with

(Hello, World)00:07:57.742 TRACE com.test.TestService:22 retrieveMessage -

entry00:07:57.742 TRACE com.test.TestService:57 getKey - entry00:07:57.743 TRACE

com.test.TestService:59 getKey - exit with (1)00:07:57.745 TRACE

com.test.TestService:47 getMessage - entry with (1)00:07:57.745 TRACE

com.test.TestService:51 getMessage - exit with (Goodbye Cruel World)00:07:57.746

TRACE com.test.TestService:26 retrieveMessage - exit with (Goodbye Cruel

World)00:07:57.746 TRACE com.test.TestService:32 exampleException -

entry00:07:57.750 ERROR com.test.TestService:40 exampleException -

catchingjava.lang.ArrayIndexOutOfBoundsException: 3  at

com.test.TestService.exampleException(TestService.java:35)  at

com.test.AppTest.testApp(AppTest.java:39)  at

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

 at

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

 at java.lang.reflect.Method.invoke(Method.java:585)  at

junit.framework.TestCase.runTest(TestCase.java:154)  at

junit.framework.TestCase.runBare(TestCase.java:127)  at

junit.framework.TestResult$1.protect(TestResult.java:106)  at

junit.framework.TestResult.runProtected(TestResult.java:124)  at

junit.framework.TestResult.run(TestResult.java:109)  at

junit.framework.TestCase.run(TestCase.java:118)  at

junit.framework.TestSuite.runTest(TestSuite.java:208)  at

junit.framework.TestSuite.run(TestSuite.java:203)  at

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

 at

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

 at java.lang.reflect.Method.invoke(Method.java:585)  at

org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)  at

org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)

 at

org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)

 at org.apache.maven.surefire.Surefire.run(Surefire.java:177)  at

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

 at

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

 at java.lang.reflect.Method.invoke(Method.java:585)  at

org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)

 at

org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)00:07:57.750

TRACE com.test.TestService:42 exampleException - exit

在上面的比如中,只需求简略地将root日志的等级修正为DEBUG,将大幅削减输出内容。

00:28:06.004 ERROR com.test.TestService:40

exampleException - catchingjava.lang.ArrayIndexOutOfBoundsException: 3  at

com.test.TestService.exampleException(TestService.java:35)  at

com.test.AppTest.testApp(AppTest.java:39)  at

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

 at

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

 at java.lang.reflect.Method.invoke(Method.java:585)  at

junit.framework.TestCase.runTest(TestCase.java:154)  at

junit.framework.TestCase.runBare(TestCase.java:127)  at

junit.framework.TestResult$1.protect(TestResult.java:106)  at

junit.framework.TestResult.runProtected(TestResult.java:124)  at

junit.framework.TestResult.run(TestResult.java:109)  at

junit.framework.TestCase.run(TestCase.java:118)  at

junit.framework.TestSuite.runTest(TestSuite.java:208)  at

junit.framework.TestSuite.run(TestSuite.java:203)  at

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

 at

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

 at java.lang.reflect.Method.invoke(Method.java:585)  at

org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)  at

org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)

 at

org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)

 at org.apache.maven.surefire.Surefire.run(Surefire.java:177)  at

sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at

sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

 at

sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

 at java.lang.reflect.Method.invoke(Method.java:585)  at

org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)

 at

org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)

作业日志(Event Logging)

EventLogger类供给了一个简略的机制,这个机制可用于记载运用中发作的作业。

EventLogger的引荐运用办法,例如在网站应中,将数据填入到 SLF4J

的MDC,这儿数据贯

穿一个恳求的始末,这些数据中包括用户 ID,用户的 IP

地址,商品称号等等。这些能够十分简单

地在 Servlet

过滤器(filter)中完结,在这儿MDC也能够恳求完毕后整理掉。当一个作业需

要被记载偏重现时,一个EventData应当被创立并发布。然后调用EventLogger.logEvent(data)

这儿data即是指向EventData方针的引证。

import org.slf4j.MDC;import

org.apache.commons.lang.time.DateUtils;import javax.servlet.Filter;import

javax.servlet.FilterConfig;import javax.servlet.ServletException;import

javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import

javax.servlet.FilterChain;import javax.servlet.http.HttpSession;import

javax.servlet.http.HttpServletRequest;import javax.servlet.http.Cookie;import

javax.servlet.http.HttpServletResponse;import java.io.IOException;import

java.util.TimeZone;public class RequestFilter implements Filter{  private

FilterConfig filterConfig;  private static String TZ_NAME = "timezoneOffset";

 public void init(FilterConfig filterConfig) throws ServletException {  

 this.filterConfig = filterConfig;  }  /**   * Sample filter that populates the

MDC on every request.   */  public void doFilter(ServletRequest servletRequest,

ServletResponse servletResponse,                       FilterChain filterChain)

throws IOException, ServletException {    HttpServletRequest request =

(HttpServletRequest)servletRequest;    HttpServletResponse response =

(HttpServletResponse)servletResponse;    MDC.put("ipAddress",

request.getRemoteAddr());    HttpSession session = request.getSession(false);  

 TimeZone timeZone = null;    if (session != null) {      // Something should

set this after authentication completes      String loginId =

(String)session.getAttribute("LoginId");      if (loginId != null) {      

 MDC.put("loginId", loginId);      }      // This assumes there is some

javascript on the user's page to create the cookie.      if

(session.getAttribute(TZ_NAME) == null) {        if (request.getCookies() !=

null) {          for (Cookie cookie : request.getCookies()) {            if

(TZ_NAME.equals(cookie.getName())) {              int tzOffsetMinutes =

Integer.parseInt(cookie.getValue());              timeZone =

TimeZone.getTimeZone("GMT");            

 timeZone.setRawOffset((int)(tzOffsetMinutes * DateUtils.MILLIS_PER_MINUTE));  

           request.getSession().setAttribute(TZ_NAME, tzOffsetMinutes);        

     cookie.setMaxAge(0);              response.addCookie(cookie);            }

         }        }      }    }    MDC.put("hostname",

servletRequest.getServerName());    MDC.put("productName",

filterConfig.getInitParameter("ProductName"));    MDC.put("locale",

servletRequest.getLocale().getDisplayName());    if (timeZone == null) {    

 timeZone = TimeZone.getDefault();    }    MDC.put("timezone",

timeZone.getDisplayName());    filterChain.doFilter(servletRequest,

servletResponse);    MDC.clear();  }  public void destroy() {  }}

运用EventLogger的示例类。

import org.slf4j.ext.EventData;import

org.slf4j.ext.EventLogger;import java.util.Date;import java.util.UUID;public

class MyApp {  public String doFundsTransfer(Account toAccount, Account

fromAccount, long amount) {    toAccount.deposit(amount);  

 fromAccount.withdraw(amount);    EventData data = new EventData();  

 data.setEventDateTime(new Date());    data.setEventType("transfer");    String

confirm = UUID.randomUUID().toString();    data.setEventId(confirm);  

 data.put("toAccount", toAccount);    data.put("fromAccount", fromAccount);  

 data.put("amount", amount);    EventLogger.logEvent(data);    return confirm;

 }}

EventLogger类运用一个被命名为EventLogger的日志。EventLogger运用INFO等级

的日志。下面是一个运用 Logback 的装备。

%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -

%msg%n%d{HH:mm:ss.SSS} %X -

%msg%n

经过Java 署理(agent)来增加日志

入门概要:

Use Java 5 or later.

运用 Java 5 或许更高。

Download slf4j-ext-1.7.19.jar and javassist.jar,

and put them both in the same directory.

下载slf4j-ext-1.7.19.jar和javassist.jar,并将它们放置在同一个目录中。

Ensure your application is properly configured

with slf4j-api-1.7.19.jar and a

suitable backend.

保证你的运用现已恰本地装备slf4j-api-1.7.19.jar和一个恰当的后端。

Instead of “java …” use “java

–javaagent:PATH/slf4j-ext-1.7.19.jar=time,verbose,level=info …” (replace PATH

with the path to the jar)

运用java

--javaagent:PATH/slf4j-ext-1.7.19.jar=time,verbose,level=info …(运用指向 Jar

的途径来更换PATH) 替代java …

That’s it!

就这些!

在一些运用中,日志是用于追踪程序实践履行状况的,而不是用于记载偶尔发作的作业。一种完结方

式是运用拓展日志在程序恰当的当地增加句子;但还有一种办法,是运用东西经过修正编译后的字节

码的办法来增加句子。还有别的许多办法存在,其时包括在 slf4j-ext

中的并不是为对比而生的。

这只是供给了一个办法,在既定程序中,迅速获取根本的追踪信息。

在 Java 5 中,增加了 Instrumentation 机制,这个机制供给了 Java

署理(agent)功用,它

答应你在字节码加载时,查看和修正字节码。这就能够让本来的类文件保留不变,这种字节码变换只

是在需求加载时才进行。

public class HelloWorld {  public static void

main(String args[]) {    System.out.println("Hello World");  }}

一个典型的变换入下: (import 句子别忽略)

public class LoggingHelloWorld {  final static

Logger _log = LoggerFactory.getLogger(LoggingHelloWorld.class.getName());

 public static void main(String args[]) {    if (_log.isInfoEnabled()) {    

 _log.info("> main(args=" + Arrays.asList(args) + ")");    }  

 System.out.println("Hello World");    if (_log.isInfoEnabled()) {    

 _log.info("< main()");    }  }}

当履行相似java LoggingHelloWorld 1 2 3 4时,输出也大致如下:

1 [main] INFO LoggingHelloWorld - >

main(args=[1, 2, 3, 4])Hello World1 [main] INFO LoggingHelloWorld - <

main()

能够运用下面的指令,来到达相同的作用(javassist.jar 和

slf4j-ext-1.7.19.jar 放在了相对途径../jars中)

java -javaagent:../jars/slf4j-ext-1.7.19.jar

HelloWorld 1 2 3 4

怎么运用

javaagent能够指定一到多个运用逗号切割的选项。所支撑的选项如下:

level=X

The log level to use for the generated log

statements. X is one of “info”, “debug” or “trace”. Default is

“info”.关于生成日志句子所运用的日志等级。其间X可取的值为:info、debug、trace。默许的等级为:info。

time

打印出程序发动的当时日期,而且在程序结尾再输出以毫秒计算的程序履行时刻。

verbose

Print out when a class is processed as part of

being loaded打印出当一个类被装载有些的处理

ignore=X:Y:…

(高档特性)供给不不需求输出日志的类名前缀,运用冒号切割。默许的列表为:org/slf4j/:ch/qos/logback/:org/apache/log4j/。

这还有一个不言自明的现实即是,为了能够输出日志,类有必要能够拜访slf4j-api的类,假如这

些类不能拜访给点的类,则肯定不能重塑。

一些类运用object.toString()进行呈现时,或许变现做法不当。所以,应当在

logback 配

置文件清晰声明日志不可用。在 Apache Jakarta commons lang

包中的ToStringBuilder就

是一个极好的比如。关于 logback,能够将下面这个代码片段增加到 logback.xml

中:

这些还没有最终断定,或许还也许会变。

jar 文件的寄存方位

javassist

库是用来实践进行字节码操纵的,为了增加恣意的日志句子,它有必要可用。slf4j-ext-1.7.19

能够像下面这么进行装备:

“javassist-3.4.GA.jar” 和 “slf4j-ext-1.7.19.jar”

能够运用 Maven 从库房下载。而且,

“slf4j-ext-1.7.19.jar” 在 Maven 库中,直接以 “-javaagent”

参数引证。

“javassist-3.4.GA.jar” 和 “slf4j-ext” 在同一个目录下。

当 javassist

没有被署理发现的话,会打印出正告信息。而且指定的字节码变换也不会作业。

其它留意事项

Java 署理不能用于现已被类加载器加载过的任何类。

Java 署理中的反常通常会被打印出来,也也许被 Java 虚拟机巧巧吞下。

Java 署理只会打印到过错输出(System.err)。

日志称号变量是固定的(好像也没有太大的利用价值),所以,假如这个姓名被运用了,将会发作

过错。这么断定一个没有被运用的姓名,然后运用它。

空办法不会被重塑。(对于接口的正确性查看)

(Java 署理是java.util.logging版别的一种适配。具体描绘在

http://today.java.net/pub/a/today/2008/04/24/add-logging-at-class-load-time-with-instrumentation.html。)

优质IT资源分享社区为你提供此文。

本站有大量优质Java教程视频,资料等资源,包含java基础教程,高级进阶教程等等,教程视频资源涵盖传智播客,极客学院,达内,北大青鸟,猎豹网校等等IT职业培训机构的培训教学视频,价值巨大。欢迎点击下方链接查看。

java教程视频

优质IT资源分享社区(www.itziyuan.top)
一个免费,自由,开放,共享,平等,互助的优质IT资源分享网站。
专注免费分享各大IT培训机构最新培训教学视频,为你的IT学习助力!

!!!回帖受限制请看点击这里!!!
!!!资源失效请在此版块发帖说明!!!

[PS:按 CTRL+D收藏本站网址~]

——“优质IT资源分享社区”管理员专用签名~

本版相似帖子

游客