Java logger, который автоматически определяет имя класса вызывающего - PullRequest
35 голосов
/ 17 сентября 2008
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

Ответы [ 20 ]

2 голосов
/ 17 сентября 2008

Конечно, вы можете просто использовать Log4J с соответствующим макетом шаблона:

Например, для имени класса «org.apache.xyz.SomeClass» шаблон% C {1} выведет «SomeClass».

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

1 голос
/ 10 октября 2018

API ведения журнала Google Flogger поддерживает это, например,

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

Подробнее см. https://github.com/google/flogger.

1 голос
/ 14 августа 2015

У меня просто есть следующая строка в начале большинства моих занятий.

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

Да, в первый раз, когда создается объект этого класса, возникают некоторые накладные расходы, но я работаю в основном в веб-приложениях, поэтому добавление микросекунд в 20-секундный запуск не является проблемой.

0 голосов
/ 20 февраля 2019

Хороший способ сделать это с Java 7 и выше:

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

Регистратор может быть static и это нормально. Здесь используется API SLF4J

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

Но в принципе может использоваться с любым каркасом регистрации. Если регистратору требуется строковый аргумент, добавьте toString()

0 голосов
/ 12 сентября 2016

Хорошей альтернативой является использование (одной из) аннотаций lombok logs: https://projectlombok.org/features/Log.html

Создает соответствующий лог-оператор с текущим классом.

0 голосов
/ 17 сентября 2008

Почему бы и нет?

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 голосов
/ 03 февраля 2013

Взгляните на Logger класс из jcabi-log . Он делает именно то, что вы ищете, предоставляя набор статических методов. Вам больше не нужно встраивать регистраторы в классы:

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

Logger отправляет все журналы в SLF4J, которые вы можете перенаправить в любое другое средство ведения журнала во время выполнения.

0 голосов
/ 13 августа 2012

Пожалуйста, ознакомьтесь с моей статической реализацией getLogger () (используйте ту же магию "sun. *" На JDK 7, что и по умолчанию для java Logger)

  • обратите внимание на методы статического ведения журнала (со статическим импортом) без некрасивого свойства журнала ...

    импорт статических my.pakg.Logger. *;

И их скорость эквивалентна собственной реализации Java (проверено с 1 миллионом трассировок журнала)

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 голосов
/ 17 сентября 2008

Этот механизм требует много дополнительных усилий во время выполнения.

Если вы используете Eclipse в качестве IDE, рассмотрите возможность использования Log4e . Этот удобный плагин будет генерировать для вас объявления регистратора, используя вашу любимую среду ведения журналов. Немного больше усилий во время кодирования, но намного меньше работы во время выполнения.

0 голосов
/ 17 сентября 2008

Если вам действительно не нужен статический логгер, вы можете использовать

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