Pregunta

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 devuelve un registrador que sabe la clase es el registro.Todas las ideas en contra de ella?

Muchos años más tarde: https://github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.java

¿Fue útil?

Solución

Supongo que también añade una gran cantidad de la carga para cada clase.Cada clase tiene que ser 'miró'.Crear nuevos Arrojar objetos a hacer...Estos throwables no vienen gratis.

Otros consejos

La creación de una traza de la pila es una operación relativamente lenta.Su interlocutor ya se sabe lo de la clase y el método tiene, por lo que el esfuerzo es en vano.Este aspecto de la solución es ineficiente.

Incluso si utiliza la clase estática de la información, no debe coger el Registrador de nuevo para cada mensaje. Del autor de Log4j,Ceki Gülcü:

El error más común en las clases de contenedor es la invocación de la bitácora.getLogger método en cada solicitud de registro.Esto está garantizado para causar estragos en el rendimiento de la aplicación.De verdad!!!

Este es el convencional, eficiente modismo para conseguir un Registrador durante la inicialización de clase:

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

Tenga en cuenta que esto le da a usted por separado un Registrador para cada tipo en una jerarquía.Si usted viene para arriba con un método que invoca getClass() en una instancia, verá mensajes registrados por un tipo de base que muestra bajo el subtipo del registrador.Tal vez esto es deseable en algunos casos, pero me resulta confuso (y tiendo a favor de composición a lo largo de la herencia de todos modos).

Obviamente, el uso de la dinámica de la clase a través de los getClass() se requerirá obtener el registrador, al menos, una vez por ejemplo, en lugar de una vez por clase como la que se recomienda el uso de lenguaje de tipo estático de la información.

El MethodHandles clase (a partir de Java 7) incluye un Búsqueda clase que, a partir de un contexto estático, se puede encontrar y devolver el nombre de la clase actual.Considere el siguiente ejemplo:

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

Cuando se ejecuta esta produce:

Main

Por un registrador, puedes usar:

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

En realidad tenemos algo bastante similar en un LogUtils clase.Sí, es un poco espeluznante, pero las ventajas son vale la pena, ya que a mí respecta.Queríamos asegurarnos de que no tenemos ninguna sobrecarga de ser llamado repetidamente a pesar de que, así, la nuestra (algo hackily) se asegura de que SÓLO puede ser llamado desde un inicializador estático contexto, la:

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

Se producirá un error si se invoca desde un método normal, o de una instancia de inicializador (es decir,si el 'estática' quedó fuera de arriba) para reducir el riesgo de sobrecarga de rendimiento.El método es el siguiente:

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

Cualquier persona que pregunta ¿qué ventaja tiene esto sobre

= Logger.getLogger(MyClass.class);

probablemente nunca tuvo que lidiar con alguien que copia y pega de que la línea de otro lugar y se olvida de cambiar el nombre de la clase, dejando que tratar con una clase que envía todas sus cosas a otro registrador.

Suponiendo que se mantiene estática referencias a los madereros, he aquí una independiente estática singleton:

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

El uso es agradable y limpio:

Logger logger = LoggerUtils.getLogger();

Para cada clase que usted utilice este con el, vas a tener que buscar el Registrador de todos modos, así que usted puede ser que también acaba de uso estático de un Registrador en esas clases.

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

A continuación, sólo de referencia que el logger cuando usted necesita hacer su registro de mensajes.Su método hace lo mismo que la estática Log4J Registrador hace ya entonces, ¿por qué reinventar la rueda?

A continuación, lo mejor es una mezcla de los dos .

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

Y, a continuación, en cada clase:

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

en el código :

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

Usted obtener estáticos registrador que usted puede simplemente copiar y pegar en cada clase y con ninguna sobrecarga ...

Alaa

A partir de la lectura a través de todos los otros comentarios en este sitio, he creado el siguiente para el uso con 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);
}

}

Ahora en el código todo lo que necesita es

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

o

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

Si usted necesita más exposición a log4j métodos delegado de ellos de la clase Logger mencionadas anteriormente.

Por supuesto puedes usar Log4J con el correspondiente patrón de diseño:

Por ejemplo, para el nombre de clase "org.apache.xyz.SomeClass", el patrón %C{1} la salida "SomeClass".

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

Yo prefiero la creación de un (estático) Registrador para cada clase (con el explícito nombre de la clase).Yo que uso el registrador como es.

Usted no necesita crear un nuevo Arrojar objetos.Usted puede llamar Thread.currentThread().getStackTrace()[1]

Sólo tengo la siguiente línea al principio de la mayoría de mis clases.

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

sí hay cierta sobrecarga de la primera vez que un objeto de esa clase se crea, pero yo trabajo principalmente en webapps, así que la adición de microsegundos en un 20 segundo de inicio no es realmente un problema.

Google Flogger registro de la API admite esta por ejemplo

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

Ver https://github.com/google/flogger para obtener más detalles.

¿Por qué no?

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

Y luego, cuando usted necesita un registrador para una clase:

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

Este mecanismo se pone en un montón de esfuerzo adicional en tiempo de ejecución.

Si usas Eclipse como IDE, considere el uso de Log4e.Este útil plugin generará registrador de declaraciones para usted con su favorito de registro de marco.Una fracción más de esfuerzo en el tiempo de codificación, pero mucho menos trabajo en tiempo de ejecución.

A menos que usted realmente necesitamos de tu Registrador de ser estática, puede utilizar

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

Por favor, ver a mi estático getLogger() aplicación (uso de la misma "sol.*" la magia en el JDK 7 como java predeterminado Registrador de doit)

  • nota estática métodos de registro (con estática de importación) sin fea registro de la propiedad...

    importación estática mi.pakg.Logger.*;

Y su velocidad es equivalente a los nativos de implementación de Java (marcada con 1 millón de registro de huellas)

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

}

Echa un vistazo a Logger clase de jcabi-registro.Hace exactamente lo que usted está buscando, proporcionando un conjunto de métodos estáticos.Usted no será necesario incorporar los registradores en las clases más:

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

Logger envía a todos los registros de SLF4J, que usted puede redirigir a cualquier otra facilidad de registro, en tiempo de ejecución.

Una buena alternativa es el uso de (uno de) los lombok registros de anotaciones :https://projectlombok.org/features/Log.html

Crea el registro correspondiente declaración con la clase actual.

Una buena manera de hacer esto a partir de Java 7 en adelante:

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

El registrador se puede static y que bien.Aquí su uso de la API SLF4J

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

Pero en principio puede ser utilizado con cualquier marco de registros.Si el registrador se necesita un argumento de cadena agregar toString()

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top