문제

public static Logger getLogger() {
    final Throwable t = new Throwable();
    final StackTraceElement methodCaller = t.getStackTrace()[1];
    final Logger logger = Logger.getLogger(methodCaller.getClassName());
    logger.setLevel(ResourceManager.LOGLEVEL);
    return logger;
}

이 메소드는 로깅 중인 클래스를 알고 있는 로거를 반환합니다.그것에 반대하는 아이디어가 있나요?

많은 시간이 지나고: https://github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.java

도움이 되었습니까?

해결책

매 수업마다 많은 오버헤드가 추가되는 것 같아요.모든 수업은 '조회'되어야 합니다.이를 위해 새로운 Throwable 객체를 생성합니다.이 투척물은 무료로 제공되지 않습니다.

다른 팁

스택 추적을 만드는 것은 상대적으로 느린 작업입니다.호출자는 이미 어떤 클래스와 메서드에 있는지 알고 있으므로 노력이 낭비됩니다.솔루션의 이러한 측면은 비효율적입니다.

정적 클래스 정보를 사용하더라도 각 메시지에 대해 Logger를 다시 가져오면 안 됩니다. 저자로부터 Log4j의 Ceki Gülcü:

래퍼 클래스에서 가장 일반적인 오류는 각 로그 요청에서 Logger.getLogger 메서드를 호출하는 것입니다.이는 애플리케이션 성능에 큰 타격을 줄 수 있습니다.정말!!!

이는 클래스 초기화 중에 Logger를 가져오는 기존의 효율적인 관용어입니다.

private static final Logger log = Logger.getLogger(MyClass.class);

이는 계층 구조의 각 유형에 대해 별도의 로거를 제공합니다.호출하는 메소드를 생각해 내면 getClass() 인스턴스에서는 하위 유형의 로거 아래에 표시되는 기본 유형에 의해 기록된 메시지를 볼 수 있습니다.어떤 경우에는 이것이 바람직할 수도 있지만 혼란스럽습니다. 어쨌든 저는 상속보다 구성을 선호하는 경향이 있습니다.

분명히 다음을 통해 동적 유형을 사용합니다. getClass() 정적 유형 정보를 사용하는 권장 관용어처럼 클래스당 한 번이 아니라 인스턴스당 적어도 한 번 로거를 가져와야 합니다.

그만큼 메소드 핸들 클래스(Java 7 기준)에는 다음이 포함됩니다. 조회 정적 컨텍스트에서 현재 클래스의 이름을 찾아 반환할 수 있는 클래스입니다.다음 예를 고려하십시오.

import java.lang.invoke.MethodHandles;

public class Main {
  private static final Class clazz = MethodHandles.lookup().lookupClass();
  private static final String CLASSNAME = clazz.getSimpleName();

  public static void main( String args[] ) {
    System.out.println( CLASSNAME );
  }
}

실행하면 다음이 생성됩니다.

Main

로거의 경우 다음을 사용할 수 있습니다.

private static Logger LOGGER = 
  Logger.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());

실제로 LogUtils 클래스에는 꽤 비슷한 것이 있습니다.예, 좀 이상하지만 제가 생각하는 한 이점은 그만한 가치가 있습니다.우리는 반복적으로 호출되는 데 따른 오버헤드가 없는지 확인하고 싶었기 때문에 (다소 해킹적으로) 정적 초기화 컨텍스트에서만 호출할 수 있도록 보장합니다.

private static final Logger LOG = LogUtils.loggerForThisClass();

일반 메서드나 인스턴스 초기화 프로그램(예:위에서 '정적'을 생략한 경우) 성능 오버헤드의 위험을 줄입니다.방법은 다음과 같습니다.

public static Logger loggerForThisClass() {
    // We use the third stack element; second is this method, first is .getStackTrace()
    StackTraceElement myCaller = Thread.currentThread().getStackTrace()[2];
    Assert.equal("<clinit>", myCaller.getMethodName());
    return Logger.getLogger(myCaller.getClassName());
}

이것이 어떤 이점이 있는지 묻는 사람은 누구나

= Logger.getLogger(MyClass.class);

아마도 다른 곳에서 해당 줄을 복사하여 붙여넣고 클래스 이름을 변경하는 것을 잊어버려 모든 내용을 다른 로거로 보내는 클래스를 처리하는 사람을 처리할 필요가 없었을 것입니다.

로거에 대한 정적 참조를 유지한다고 가정하면 다음은 독립 실행형 정적 싱글톤입니다.

public class LoggerUtils extends SecurityManager
{
    public static Logger getLogger()
    {
        String className = new LoggerUtils().getClassName();
        Logger logger = Logger.getLogger(className);
        return logger;
    }

    private String getClassName()
    {
        return getClassContext()[2].getName();
    }
}

사용법은 훌륭하고 깨끗합니다.

Logger logger = LoggerUtils.getLogger();

이것을 사용하는 모든 클래스에 대해 어쨌든 Logger를 찾아야 하므로 해당 클래스에서 정적 Logger를 사용하는 것이 좋습니다.

private static final Logger logger = Logger.getLogger(MyClass.class.getName());

그런 다음 로그 메시지를 수행해야 할 때 해당 로거를 참조하면 됩니다.귀하의 방법은 정적 Log4J Logger가 이미 수행하는 것과 동일한 작업을 수행하는데 왜 바퀴를 재발명합니까?

그렇다면 가장 좋은 것은 두 가지를 혼합하는 것입니다.

public class LoggerUtil {

    public static Level level=Level.ALL;

    public static java.util.logging.Logger getLogger() {
        final Throwable t = new Throwable();
        final StackTraceElement methodCaller = t.getStackTrace()[1];
        final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(methodCaller.getClassName());
        logger.setLevel(level);

        return logger;
    }
}

그리고 모든 수업에서:

private static final Logger LOG = LoggerUtil.getLogger();

코드에서 :

LOG.fine("debug that !...");

모든 클래스에서 오버헤드 없이 복사하여 붙여넣기만 하면 되는 정적 로거가 제공됩니다.

알라

이 사이트의 다른 모든 피드백을 읽은 후 Log4j와 함께 사용할 수 있도록 다음을 만들었습니다.

package com.edsdev.testapp.util;

import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Level;
import org.apache.log4j.Priority;

public class Logger extends SecurityManager {

private static ConcurrentHashMap<String, org.apache.log4j.Logger> loggerMap = new ConcurrentHashMap<String, org.apache.log4j.Logger>();

public static org.apache.log4j.Logger getLog() {
    String className = new Logger().getClassName();
    if (!loggerMap.containsKey(className)) {
        loggerMap.put(className, org.apache.log4j.Logger.getLogger(className));
    }
    return loggerMap.get(className);
}
public String getClassName() {
    return getClassContext()[3].getName();
}
public static void trace(Object message) {
    getLog().trace(message);
}
public static void trace(Object message, Throwable t) {
    getLog().trace(message, t);
}
public static boolean isTraceEnabled() {
    return getLog().isTraceEnabled();
}
public static void debug(Object message) {
    getLog().debug(message);
}
public static void debug(Object message, Throwable t) {
    getLog().debug(message, t);
}
public static void error(Object message) {
    getLog().error(message);
}
public static void error(Object message, Throwable t) {
    getLog().error(message, t);
}
public static void fatal(Object message) {
    getLog().fatal(message);
}
public static void fatal(Object message, Throwable t) {
    getLog().fatal(message, t);
}
public static void info(Object message) {
    getLog().info(message);
}
public static void info(Object message, Throwable t) {
    getLog().info(message, t);
}
public static boolean isDebugEnabled() {
    return getLog().isDebugEnabled();
}
public static boolean isEnabledFor(Priority level) {
    return getLog().isEnabledFor(level);
}
public static boolean isInfoEnabled() {
    return getLog().isInfoEnabled();
}
public static void setLevel(Level level) {
    getLog().setLevel(level);
}
public static void warn(Object message) {
    getLog().warn(message);
}
public static void warn(Object message, Throwable t) {
    getLog().warn(message, t);
}

}

이제 코드에서 필요한 것은

Logger.debug("This is a test");

또는

Logger.error("Look what happened Ma!", e);

log4j 메소드에 대한 추가 노출이 필요한 경우 위에 나열된 Logger 클래스에서 위임하면 됩니다.

물론 적절한 패턴 레이아웃으로 Log4J를 사용할 수도 있습니다.

예를 들어 클래스 이름이 "org.apache.xyz.SomeClass"인 경우 %C{1} 패턴은 "SomeClass"를 출력합니다.

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

나는 각 클래스에 대해 (명시적인 클래스 이름을 사용하여) (정적) 로거를 생성하는 것을 선호합니다.나는 로거를 그대로 사용합니다.

새로운 Throwable 객체를 생성할 필요가 없습니다.그냥 전화하시면 돼요Thread.currentThread().getStackTrace()[1]

대부분의 수업이 시작될 때 다음 줄이 있습니다.

  private static final Logger log = 
     LoggerFactory.getLogger(new Throwable().getStackTrace()[0].getClassName());

예, 해당 클래스의 객체가 처음 생성될 때 약간의 오버헤드가 있지만 저는 주로 웹앱에서 작업하므로 20초 시작에 마이크로초를 추가하는 것은 실제로 문제가 되지 않습니다.

Google Flogger 로깅 API는 이를 지원합니다.

private static final FluentLogger logger = FluentLogger.forEnclosingClass();

보다 https://github.com/google/flogger 상세 사항은.

왜 안 돼?

public static Logger getLogger(Object o) {
  final Logger logger = Logger.getLogger(o.getClass());
  logger.setLevel(ResourceManager.LOGLEVEL);
  return logger;
}

그런 다음 클래스에 대한 로거가 필요한 경우:

getLogger(this).debug("Some log message")

이 메커니즘은 런타임에 많은 추가 노력을 기울입니다.

Eclipse를 IDE로 사용하는 경우 다음을 사용해 보세요. Log4e.이 편리한 플러그인은 선호하는 로깅 프레임워크를 사용하여 로거 선언을 생성합니다.코딩 시간에 더 많은 노력이 필요하지만 많이 런타임에 작업량이 줄어듭니다.

너가 아니라면 정말 Logger가 정적으로 필요하면 다음을 사용할 수 있습니다.

final Logger logger = LoggerFactory.getLogger(getClass());

내 정적 getLogger() 구현을 참조하세요(JDK 7에서 기본 Java Logger doit과 동일한 "sun.*" 매직 사용).

  • 보기 흉한 로그 속성이 없는 정적 로깅 방법(정적 가져오기 포함)에 유의하세요.

    import static my.pakg.Logger.*;

속도는 기본 Java 구현과 동일합니다(100만 개의 로그 추적으로 확인).

package my.pkg;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.IllegalFormatException;
import java.util.logging.Level;
import java.util.logging.LogRecord;

import sun.misc.JavaLangAccess;
import sun.misc.SharedSecrets;


public class Logger {
static final int CLASS_NAME = 0;
static final int METHOD_NAME = 1;

// Private method to infer the caller's class and method names
protected static String[] getClassName() {
    JavaLangAccess access = SharedSecrets.getJavaLangAccess();
    Throwable throwable = new Throwable();
    int depth = access.getStackTraceDepth(throwable);

    boolean lookingForLogger = true;
    for (int i = 0; i < depth; i++) {
        // Calling getStackTraceElement directly prevents the VM
        // from paying the cost of building the entire stack frame.
        StackTraceElement frame = access.getStackTraceElement(throwable, i);
        String cname = frame.getClassName();
        boolean isLoggerImpl = isLoggerImplFrame(cname);
        if (lookingForLogger) {
            // Skip all frames until we have found the first logger frame.
            if (isLoggerImpl) {
                lookingForLogger = false;
            }
        } else {
            if (!isLoggerImpl) {
                // skip reflection call
                if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
                    // We've found the relevant frame.
                    return new String[] {cname, frame.getMethodName()};
                }
            }
        }
    }
    return new String[] {};
    // We haven't found a suitable frame, so just punt.  This is
    // OK as we are only committed to making a "best effort" here.
}

protected static String[] getClassNameJDK5() {
    // Get the stack trace.
    StackTraceElement stack[] = (new Throwable()).getStackTrace();
    // First, search back to a method in the Logger class.
    int ix = 0;
    while (ix < stack.length) {
        StackTraceElement frame = stack[ix];
        String cname = frame.getClassName();
        if (isLoggerImplFrame(cname)) {
            break;
        }
        ix++;
    }
    // Now search for the first frame before the "Logger" class.
    while (ix < stack.length) {
        StackTraceElement frame = stack[ix];
        String cname = frame.getClassName();
        if (isLoggerImplFrame(cname)) {
            // We've found the relevant frame.
            return new String[] {cname, frame.getMethodName()};
        }
        ix++;
    }
    return new String[] {};
    // We haven't found a suitable frame, so just punt.  This is
    // OK as we are only committed to making a "best effort" here.
}


private static boolean isLoggerImplFrame(String cname) {
    // the log record could be created for a platform logger
    return (
            cname.equals("my.package.Logger") ||
            cname.equals("java.util.logging.Logger") ||
            cname.startsWith("java.util.logging.LoggingProxyImpl") ||
            cname.startsWith("sun.util.logging."));
}

protected static java.util.logging.Logger getLogger(String name) {
    return java.util.logging.Logger.getLogger(name);
}

protected static boolean log(Level level, String msg, Object... args) {
    return log(level, null, msg, args);
}

protected static boolean log(Level level, Throwable thrown, String msg, Object... args) {
    String[] values = getClassName();
    java.util.logging.Logger log = getLogger(values[CLASS_NAME]);
    if (level != null && log.isLoggable(level)) {
        if (msg != null) {
            log.log(getRecord(level, thrown, values[CLASS_NAME], values[METHOD_NAME], msg, args));
        }
        return true;
    }
    return false;
}

protected static LogRecord getRecord(Level level, Throwable thrown, String className, String methodName, String msg, Object... args) {
    LogRecord record = new LogRecord(level, format(msg, args));
    record.setSourceClassName(className);
    record.setSourceMethodName(methodName);
    if (thrown != null) {
        record.setThrown(thrown);
    }
    return record;
}

private static String format(String msg, Object... args) {
    if (msg == null || args == null || args.length == 0) {
        return msg;
    } else if (msg.indexOf('%') >= 0) {
        try {
            return String.format(msg, args);
        } catch (IllegalFormatException esc) {
            // none
        }
    } else if (msg.indexOf('{') >= 0) {
        try {
            return MessageFormat.format(msg, args);
        } catch (IllegalArgumentException exc) {
            // none
        }
    }
    if (args.length == 1) {
        Object param = args[0];
        if (param != null && param.getClass().isArray()) {
            return msg + Arrays.toString((Object[]) param);
        } else if (param instanceof Throwable){
            return msg;
        } else {
            return msg + param;
        }
    } else {
        return msg + Arrays.toString(args);
    }
}

public static void severe(String msg, Object... args) {
    log(Level.SEVERE, msg, args);
}

public static void warning(String msg, Object... args) {
    log(Level.WARNING, msg, args);
}

public static void info(Throwable thrown, String format, Object... args) {
    log(Level.INFO, thrown, format, args);
}

public static void warning(Throwable thrown, String format, Object... args) {
    log(Level.WARNING, thrown, format, args);
}

public static void warning(Throwable thrown) {
    log(Level.WARNING, thrown, thrown.getMessage());
}

public static void severe(Throwable thrown, String format, Object... args) {
    log(Level.SEVERE, thrown, format, args);
}

public static void severe(Throwable thrown) {
    log(Level.SEVERE, thrown, thrown.getMessage());
}

public static void info(String msg, Object... args) {
    log(Level.INFO, msg, args);
}

public static void fine(String msg, Object... args) {
    log(Level.FINE, msg, args);
}

public static void finer(String msg, Object... args) {
    log(Level.FINER, msg, args);
}

public static void finest(String msg, Object... args) {
    log(Level.FINEST, msg, args);
}

public static boolean isLoggableFinest() {
    return isLoggable(Level.FINEST);
}

public static boolean isLoggableFiner() {
    return isLoggable(Level.FINER);
}

public static boolean isLoggableFine() {
    return isLoggable(Level.FINE);
}

public static boolean isLoggableInfo() {
    return isLoggable(Level.INFO);
}

public static boolean isLoggableWarning() {
    return isLoggable(Level.WARNING);
}
public static boolean isLoggableSevere() {
    return isLoggable(Level.SEVERE);
}

private static boolean isLoggable(Level level) {
    return log(level, null);
}

}

보세요 Logger 수업 jcabi-log.이는 정적 메서드 모음을 제공하여 여러분이 찾고 있는 작업을 정확하게 수행합니다.더 이상 클래스에 로거를 포함할 필요가 없습니다.

import com.jcabi.log.Logger;
class Foo {
  public void bar() {
    Logger.info(this, "doing something...");
  }
}

Logger 런타임에 다른 로깅 기능으로 리디렉션할 수 있는 SLF4J로 모든 로그를 보냅니다.

좋은 대안은 lombok 로그 주석 중 하나를 사용하는 것입니다.https://projectlombok.org/features/Log.html

현재 클래스에 해당하는 로그 문을 생성합니다.

Java 7부터 이를 수행하는 좋은 방법은 다음과 같습니다.

private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

로거는 다음과 같습니다. static 그리고 그거 괜찮아.여기서는 SLF4J API를 사용합니다.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

그러나 원칙적으로는 모든 로깅 프레임워크와 함께 사용할 수 있습니다.로거에 문자열 인수가 필요한 경우 추가 toString()

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top