代码之家  ›  专栏  ›  技术社区  ›  alex440 Gangaraju

Java中的惰性日志消息评估

  •  3
  • alex440 Gangaraju  · 技术社区  · 6 年前

    在某些情况下,我对延迟日志消息的创建很感兴趣,因此在日志级别不够的情况下不会创建它。

    我通过将回调传递给一个日志函数来实现,如果日志级别足够,就调用这个函数。

    问题是,我不能传递一个不是最终有效的变量,因为Java有关闭限制。

    什么是更清洁的方法?

    运行代码: http://tpcg.io/IspNlN

    import java.util.*;
    import java.lang.*;
    import java.io.*;
    import java.util.function.Supplier;
    
    public class StackOverflow
    {
        private static final int LOG_LEVEL=2;
        private static final int TRACE_LEVEL=0;
    
        private static void trace(Supplier<String> messageCallback){
            if(TRACE_LEVEL>LOG_LEVEL) return;
            System.out.println(messageCallback.get());          
        }
    
        private static void foo(){      
            for(int i=0; i<10; i++){
                doSomething();
                int finalI=i; //I need it because of "Local variable parameterIndex defined in an enclosing scope must be final or effectively final"
                trace(()->"FLOW-1: "+getHugeString()+" for i:"+finalI);
            }
        }
    
        public static void main (String[] args) throws java.lang.Exception
        {
            foo();
        }
    
        private static  void doSomething(){
            //some operation
        }
    
        private static String getHugeString(){          
            return "A huge string that took much time to create";
        }
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   gagan singh    6 年前

    您有三个选项,按优先顺序列出。

    方案1

    使用适当的日志记录库。

    方案2由@glains指出

    private static boolean isTraceEnabled()
    {
        return TRACE_LEVEL <= LOG_LEVEL;
    }
    
    private static void trace(String msg)
    {
        if (isTraceEnabled())
        {
            System.out.println(msg);
        }
    }
    
    private static void foo()
    {
        for (int i = 0; i < 10; i++)
        {
            doSomething();
            if (isTraceEnabled())
            {
                trace("FLOW-1: " + getHugeString() + " for i:" + i);
            }
        }
    }
    

    选项3使用消息格式,如JDK记录器中所示。

    private static void trace(String format, Object... values)
    {
        if (TRACE_LEVEL > LOG_LEVEL)
        {
            return;
        }
        for (int i = 0; i < values.length; i++)
        {
            Object value = values[i];
            if (value instanceof Supplier)
            {
                values[i] = ((Supplier) value).get();
            }
        }
        System.out.println(new MessageFormat(format).format(values));
    }
    

    像调用

    trace("FLOW-1: {0} for i: {1}", (Supplier) (StackOverflow::getHugeString), i);
    
        2
  •  0
  •   Glains    6 年前

    常见的日志框架提供了如下方法 isDebugEnabled isInfoEnabled 为了防止字符串创建时间过长的情况发生。

    if(LOG.isDebugEnabled()) {
        LOG.debug("Some objects toString method called: {}", someObject.toString());
    }
    

    除此之外,您的方法也有效,但有您已经指出的局限性。