it-swarm-ko.tech

Java 발신자의 클래스 이름을 자동으로 결정하는 로거

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

35
yanchenko

모든 수업에 많은 오버 헤드가 추가되는 것 같습니다. 모든 수업은 '찾아봐야'합니다. 이를 위해 새로운 Throwable 객체를 생성합니다 ...이 Throwables는 무료로 제공되지 않습니다.

17
Daan

MethodHandles 클래스 (Java 7))에는 정적 컨텍스트에서 이름을 찾아 반환 할 수있는 Lookup 클래스가 포함되어 있습니다. 현재 클래스 다음 예제를 고려하십시오.

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());
25
Neeraj

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

정적 클래스 정보를 사용하더라도 각 메시지에 대해 로거를 다시 가져 오지 않아야합니다. 작성자로부터 Log4j, Ceki Gülcü의 :

랩퍼 클래스에서 가장 일반적인 오류는 각 로그 요청에서 Logger.getLogger 메소드를 호출하는 것입니다. 이것은 응용 프로그램의 성능에 혼란을 초래할 수 있습니다. 정말!!!

이것은 클래스 초기화 중에 Logger를 얻는 데 사용되는 기존의 효율적인 관용구입니다.

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

이것은 계층 구조에서 각 유형마다 별도의 로거를 제공합니다. 인스턴스에서 getClass()을 호출하는 메소드가 나오면 기본 유형별로 로그 된 메시지가 하위 유형의 로거 아래에 표시됩니다. 어쩌면 이것이 어떤 경우에는 바람직하지만 혼란 스럽습니다 (어쨌든 상속보다 구성을 선호하는 경향이 있습니다).

분명히 getClass()을 통해 동적 유형을 사용하려면 정적 유형 정보를 사용하여 권장되는 관용구와 같이 클래스 당 한 번이 아니라 인스턴스 당 적어도 한 번은 로거를 확보해야합니다.

23
erickson

우리는 실제로 LogUtils 클래스와 비슷한 것을 가지고 있습니다. 그렇습니다, 그것은 일종의 불안정한 것이지만 이점은 내가 염려하는 한 가치가 있습니다. 우리는 반복적으로 호출되는 오버 헤드가 없도록하고 싶었습니다. 따라서 우리는 (어쩌면 hackily) 정적 초기화 컨텍스트 인 la에서만 호출 할 수 있습니다.

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);

아마도 다른 곳에서 그 줄을 복사하여 붙여 넣은 사람을 다루지 않았으며 클래스 이름을 변경하는 것을 잊어 버려 모든 물건을 다른 로거에게 보내는 클래스를 다루게됩니다.

18
Cowan

로거에 대한 정적 참조를 유지한다고 가정하면 독립형 정적 싱글 톤이 있습니다.

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();
8
EGB

이 클래스를 사용하는 모든 클래스에 대해 어쨌든 로거를 찾아야하므로 해당 클래스에서 정적 로거를 사용할 수도 있습니다.

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

그런 다음 로그 메시지를 수행해야 할 때 해당 로거를 참조하십시오. 정적 Log4J 로거와 동일한 방법으로 이미 바퀴를 재발 명하는 이유는 무엇입니까?

4
18Rabbit

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

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 !...");

모든 클래스에서 복사하여 붙여 넣을 수 있고 오버 헤드없이 정적 로거를 얻을 수 있습니다 ...

알라

3
Alaa Murad

이 사이트의 다른 모든 피드백을 읽음으로써 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 클래스에서 위임하십시오.

3
Ed Sarrazin

각 클래스에 대해 (정적) 로거를 작성하는 것이 좋습니다 (명시 적 클래스 이름 사용). 로거를 그대로 사용하는 것보다.

2
Philip Helger

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

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

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

2
Ian

새로운 Throwable 객체를 만들 필요가 없습니다. Thread.currentThread().getStackTrace()[1]을 호출하면됩니다.

2
ykaganovich

수업 시작 부분에 다음 줄이 있습니다.

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

예, 해당 클래스의 객체가 처음 만들어 질 때 약간의 오버 헤드가 있지만 대부분 웹 응용 프로그램에서 작동하므로 20 초 시작에 마이크로 초를 추가하는 것은 실제로 문제가되지 않습니다.

1
muttonUp

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

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

자세한 내용은 https://github.com/google/flogger 를 참조하십시오.

1
James Mudd

간단하고 사소한 구식 학교 :

자신의 클래스를 만들고 클래스 이름, 메소드 이름 + 주석을 전달하십시오 (클래스/메소드가 변경된 경우 자동으로 리팩터링됩니다 Shift + F6).

public class MyLogs {    
    public static void LOG(String theClass, String theMethod, String theComment) {
        Log.d("MY_TAG", "class: " + theClass + " meth : " + theMethod + " comm : " + theComment);
    }
}

앱의 어느 곳에서나 사용할 수 있습니다 (컨텍스트 필요 없음, 초기화 없음, 추가 라이브러리 없음 및 조회 없음)-모든 프로그래밍 언어에 사용할 수 있습니다!

MyLogs.LOG("MainActivity", "onCreate", "Hello world");

콘솔에 인쇄됩니다 :

MY_TAG 클래스 : MainActivity meth : onComm : Hello world

0
Choletski

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

Eclipse를 IDE로 사용하는 경우 Log4e 사용을 고려하십시오. 이 편리한 플러그인은 선호하는 로깅 프레임 워크를 사용하여 로거 선언을 생성합니다. 코딩 시간에는 훨씬 더 많은 노력이 필요하지만 런타임에 많은 적은 작업.

0
Bill Michell

롬복 로그 주석 중 하나를 사용하는 것이 좋습니다. https://projectlombok.org/features/Log.html

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

0
user2189998

Java 7 이후부터) :

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

로거는 static이 될 수 있습니다. 여기에 SLF4J API 사용

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

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

0
James Mudd

실제 Logger가 정적이어야하는 경우가 아니면

final Logger logger = LoggerFactory.getLogger(getClass());
0
Asgeir S. Nilsen

jcabi-log 에서 Logger 클래스를 살펴보십시오. 그것은 당신이 찾고있는 것을 정확하게 수행하여 정적 메소드 모음을 제공합니다. 로거를 더 이상 클래스에 포함시킬 필요가 없습니다.

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

Logger는 모든 로그를 SLF4J로 전송하며 런타임에 다른 로깅 기능으로 리디렉션 할 수 있습니다.

0
yegor256

왜 안돼?

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")
0
Mario Ortegón

내 정적 getLogger () 구현을 참조하십시오 (JDK 7에서 동일한 "Sun. *"매직을 기본값으로 사용하십시오 Java Logger doit)

  • 추악한 로그 속성이없는 정적 로깅 방법 (정적 가져 오기 사용) ...

    정적 my.pakg.Logger를 가져옵니다. *;

그리고 그들의 속도는 native Java 구현 (백만 로그 추적으로 확인))과 같습니다.

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);
}

}
0
joseaio