sirve - settitle java
Registrador de Java que determina automáticamente el nombre de la clase del llamante (18)
A menos que realmente necesite que su Logger sea estático, podría usar
final Logger logger = LoggerFactory.getLogger(getClass());
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 devolvería un registrador que conoce la clase para la que está registrando. Alguna idea en contra?
Muchos años después: https://github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.java
Crear una traza de pila es una operación relativamente lenta. Su interlocutor ya sabe en qué clase y método se encuentra, por lo que se desperdicia el esfuerzo. Este aspecto de su solución es ineficiente.
Incluso si usa información de clase estática, no debe buscar el registrador nuevamente para cada mensaje. Del autor de Log4j, Ceki Gülcü:
El error más común en las clases contenedoras es la invocación del método Logger.getLogger en cada solicitud de registro. Esto garantiza que causará estragos en el rendimiento de su aplicación. ¡¡¡De Verdad!!!
Esta es la expresión convencional y eficiente para obtener un Logger durante la inicialización de la clase:
private static final Logger log = Logger.getLogger(MyClass.class);
Tenga en cuenta que esto le proporciona un Logger separado para cada tipo en una jerarquía. Si se le ocurre un método que invoca getClass()
en una instancia, verá los mensajes registrados por un tipo base que aparecen bajo el registrador del subtipo. Tal vez esto sea deseable en algunos casos, pero me parece confuso (y de todos modos tiendo a favorecer la composición sobre la herencia).
Obviamente, el uso del tipo dinámico a través de getClass()
requerirá que obtenga el registrador al menos una vez por instancia, en lugar de una vez por clase, como la expresión recomendada utilizando información de tipo estático.
De hecho, tenemos algo bastante similar en una clase LogUtils. Sí, es un poco asqueroso, pero las ventajas valen la pena en lo que a mí respecta. Sin embargo, queríamos asegurarnos de que no tuviéramos ninguna sobrecarga por haber sido repetidamente llamada, por lo que la nuestra (de forma algo halagüeña) asegura que SOLO se puede invocar desde un contexto de inicializador estático, a la la:
private static final Logger LOG = LogUtils.loggerForThisClass();
Fallará si se invoca desde un método normal, o desde un inicializador de instancias (es decir, si el ''estático'' se dejó arriba) para reducir el riesgo de sobrecarga de rendimiento. El método es:
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());
}
Cualquiera que pregunte qué ventaja tiene esto sobre
= Logger.getLogger(MyClass.class);
probablemente nunca haya tenido que lidiar con alguien que copie y pegue esa línea desde otro lugar y olvide cambiar el nombre de la clase, dejándote lidiando con una clase que envía todo su material a otro registrador.
Después de leer todos los otros comentarios en este sitio, creé lo siguiente para usar 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 tu código todo lo que necesitas es
Logger.debug("This is a test");
o
Logger.error("Look what happened Ma!", e);
Si necesita más exposición a los métodos de log4j, simplemente delegúelos de la clase Logger listada arriba.
Echa un vistazo a la clase Logger
de jcabi-log . Hace exactamente lo que estás buscando, proporcionando una colección de métodos estáticos. Ya no es necesario incrustar registradores en las clases:
import com.jcabi.log.Logger;
class Foo {
public void bar() {
Logger.info(this, "doing something...");
}
}
Logger
envía todos los registros a SLF4J, que puede redirigir a cualquier otra instalación de registro, en tiempo de ejecución.
Entonces lo mejor es la mezcla de 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 luego en cada clase:
private static final Logger LOG = LoggerUtil.getLogger();
en codigo :
LOG.fine("debug that !...");
Obtienes un registrador estático que puedes copiar y pegar en todas las clases y sin gastos generales ...
Alaa
Este mecanismo requiere mucho esfuerzo adicional en tiempo de ejecución.
Si usa Eclipse como su IDE, considere usar Log4e . Este útil complemento generará declaraciones de registrador para usted utilizando su marco de trabajo de registro favorito. Una fracción más de esfuerzo en el tiempo de codificación, pero mucho menos trabajo en tiempo de ejecución.
La clase MethodHandles (a partir de Java 7) incluye una clase de Lookup que, desde un contexto estático, 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 esto produce:
Main
Para un registrador, puede usar:
private static Logger LOGGER =
Logger.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
No es necesario crear un nuevo objeto Throwable. Simplemente puede llamar a Thread.currentThread().getStackTrace()[1]
Para cada clase con la que use esto, tendrá que buscar el registrador de todos modos, así que también podría usar un registrador estático en esas clases.
private static final Logger logger = Logger.getLogger(MyClass.class.getName());
Luego solo hace referencia a ese registrador cuando necesita hacer sus mensajes de registro. Su método hace lo mismo que el Log4J Logger estático ya, ¿por qué reinventar la rueda?
Por favor vea mi implementación estática de getLogger () (use la misma magia "sun. *" En JDK 7 como doit Java Logger predeterminado)
tenga en cuenta los métodos de registro estáticos (con importación estática) sin la propiedad de registro feo ...
import static my.pakg.Logger. *;
Y su velocidad es equivalente a la implementación nativa de Java (comprobada con 1 millón de trazas de registro)
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);
}
}
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 necesitas un registrador para una clase:
getLogger(this).debug("Some log message")
Por supuesto, puede usar Log4J con el diseño de patrón apropiado:
Por ejemplo, para el nombre de clase "org.apache.xyz.SomeClass", el patrón% C {1} dará como resultado "SomeClass".
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
Prefiero crear un registrador (estático) para cada clase (con su nombre de clase explícito). Yo que uso el registrador como está.
Solo tengo la siguiente línea al comienzo de la mayoría de mis clases.
private static final Logger log =
LoggerFactory.getLogger(new Throwable().getStackTrace()[0].getClassName());
sí, hay algo de sobrecarga la primera vez que se crea un objeto de esa clase, pero trabajo principalmente en webapps, por lo que agregar microsegundos en un inicio de 20 segundos no es realmente un problema.
Supongo que agrega mucha sobrecarga para cada clase. Cada clase tiene que ser ''buscada''. Usted crea nuevos objetos Throwable para hacer eso ... Estos throwables no vienen gratis.
Suponiendo que mantiene referencias estáticas a los registradores, aquí hay un singleton estático independiente:
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();
Una buena alternativa es usar (una de) las anotaciones de los registros de lombok: https://projectlombok.org/features/Log.html
Genera la declaración de registro correspondiente con la clase actual.