Pergunta

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

Este método retorna um agente que conhece a classe é o log.Qualquer idéias contra ele?

Muitos anos mais tarde: https://github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.java

Foi útil?

Solução

Eu acho que isso adiciona uma grande quantidade de sobrecarga para cada classe.Cada classe tem de ser 'olhou para cima'.Criar novos objetos Throwable para fazer isso...Estes throwables não vêm de graça.

Outras dicas

A criação de um rastreamento de pilha é relativamente lento operação.O seu interlocutor já sabe qual a classe e o método é, portanto, o esforço é inútil.Este aspecto de sua solução é ineficiente.

Mesmo se você usar a classe estática informações, você não deve buscar o Madeireiro, novamente, para cada mensagem. Do autor do Log4j,Ceki Gülcü:

O erro mais comum em classes de wrapper é a invocação do Registador.método getLogger em cada pedido de registo.Isto é garantido para causar estragos no seu desempenho do aplicativo.Realmente!!!

Este é o convencional, eficiente expressão para a obtenção de um Logger é, durante a inicialização de classe:

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

Note que isso dá a você um separado Logger para cada tipo em uma hierarquia.Se você vir acima com um método que invoca getClass() em uma instância, você vai ver as mensagens registradas por um tipo de base, mostrando-se sob o subtipo do logger.Talvez isso é desejável em alguns casos, mas acho que é confuso (e eu tendem a favorecer composição sobre a herança de qualquer maneira).

Obviamente, o uso do dynamic tipo de via getClass() vai exigir que você a obter o madeireiro, pelo menos uma vez por exemplo, em vez de uma vez por classe, como o recomendado idioma usando o estático tipo de informação.

O MethodHandles de classe (como a do Java 7) inclui um Pesquisa de classe que, a partir de um contexto estático, pode localizar e retornar o nome da classe corrente.Considere o seguinte exemplo:

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

Quando executar este produz:

Main

Para um registrador, você poderia usar:

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

Na verdade, temos algo muito semelhante em um LogUtils classe.Sim, é uma espécie de icky, mas as vantagens são a pena tanto quanto eu estou preocupado.Queríamos ter certeza de que nós não temos nenhum sobrecarga de ele ser chamado repetidamente, porém, assim que os nossos (um pouco hackily) garante que ele SÓ pode ser chamado a partir de um inicializador estático contexto, la:

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

Ele irá falhar se a chamada a partir de um método normal, ou a partir de uma instância do inicializador (i.e.se o 'estático', foi deixado de fora acima) para reduzir o risco de sobrecarga de desempenho.O método é:

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

Quem pergunta o que vantagem isso tem mais de

= Logger.getLogger(MyClass.class);

provavelmente nunca teve que lidar com alguém que copia e cola essa linha de algum outro lugar e esquece-se de alterar o nome da classe, deixando-o a lidar com uma classe que envia todas as suas coisas para outro registrador.

Supondo que você está mantendo estática árbitros para os madeireiros, aqui está uma autônomo autônomo estático:

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

O uso é agradável e limpo:

Logger logger = LoggerUtils.getLogger();

Para cada classe que você use isso com você, você vai ter que olhar para cima, o Registrador de qualquer maneira, então você pode muito bem usar um estático Logger dessas classes.

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

Então você acabou de referência que logger quando você precisa para fazer seu log de mensagens.O método faz a mesma coisa que o estático Log4J Logger já então, por que reinventar a roda?

Então a melhor coisa é a mistura dos dois .

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

E, em seguida, em cada classe:

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

em código :

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

Você obter estático logger que você pode simplesmente copiar e colar em cada classe e sem sobrecarga ...

Alaa

De ler todos os outros comentários sobre este site, eu criei o seguinte para usar com o 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);
}

}

Agora, em seu código, tudo o que você precisa é de

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

ou

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

Se você precisa de mais exposição para o log4j métodos, apenas delegá-los a partir do Registrador de classe listados acima.

Você poderia, claro, é só usar o Log4J com o apropriado padrão de layout:

Por exemplo, para o nome de classe "org.apache.xyz.SomeClass", o padrão de %C{1} vai de saída "SomeClass".

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

Eu prefiro a criação de um (estático) Logger para cada classe (com explicito o nome da classe).Eu que uso o madeireiro como é.

Você não precisa criar um novo objeto Throwable.Você pode apenas chamar Thread.currentThread().getStackTrace()[1]

Eu só tenho a seguinte linha no início da maioria das minhas aulas.

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

sim, há alguma sobrecarga a primeira vez que um objeto dessa classe é criado, mas eu trabalho principalmente em webapps, assim, a adição de microssegundos para um segundo 20 de inicialização não é realmente um problema.

O Google Flogger API de log de suporte a este exemplo:

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

Ver https://github.com/google/flogger para obter mais detalhes.

Por que não?

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

E, em seguida, quando você precisa de um registrador para a classe:

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

Esse mecanismo coloca em um monte de esforço extra em tempo de execução.

Se você usar o Eclipse como IDE, considerar o uso de Log4e.Este prático plugin irá gerar logger declarações por você, usando o seu favorito logging framework.Uma fração mais esforço na codificação de tempo, mas muito menos trabalho em tempo de execução.

A menos que você realmente preciso de sua Logger para ser estático, você pode usar

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

Por favor, veja o meu estático getLogger() implementação (use a mesma do sol.*" magia no JDK 7 como padrão java Logger doit)

  • nota estáticos métodos de registro (com a estática de importação) sem feia de registo de propriedade...

    import static meu.pakg.Logger.*;

E sua velocidade é equivalente nativo implementação de Java (marcada com 1 milhão de log de rastreios)

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

}

Dê uma olhada no Logger classe de jcabi-log.Ele faz exatamente o que você está procurando, fornecendo um conjunto de métodos estáticos.Você não precisa incorporar madeireiros em classes mais:

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

Logger envia todos os logs para o SLF4J, que você pode redirecionar para qualquer outra facilidade de registro, em tempo de execução.

Uma boa alternativa é usar o (um dos) o lombok logs de anotações :https://projectlombok.org/features/Log.html

Gerar o correspondente registo de instrução com a classe corrente.

Uma boa forma de fazer isso a partir do Java 7 em diante:

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

O registrador pode ser static e que bem.Aqui sua usando a API do SLF4J

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

Mas, em princípio, pode ser usado com qualquer logging framework.Se o registrador precisa de um argumento de seqüência de caracteres adicionar toString()

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top