it-swarm-tr.com

Arayanın sınıf adını otomatik olarak belirleyen Java günlüğü

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

Bu yöntem, günlüğe kaydettiği sınıfı bilen bir günlüğe geri döndürür . Buna karşı bir fikrin var mı?

Yıllar sonra: https://github.com/yanchenko/droidparts/blob/master/droidparts/src/org/droidparts/util/L.Java

33
yanchenko

Her sınıf için ek yükü çok fazla tahmin ediyorum. Her sınıfa 'bakmak' gerekir. Bunu yapmak için yeni Atılabilir nesneler yaratıyorsun ... Bu atılabilirler bedava gelmiyor.

15
Daan

Bir yığın izi oluşturmak nispeten yavaş bir işlemdir. Arayan kişi hangi sınıfta ve yöntemde olduğunu zaten biliyor, bu yüzden çaba harcanıyor. Çözümünüzün bu yönü yetersizdir.

Statik sınıf bilgisi kullanıyor olsanız bile, her bir mesaj için Logger'ı tekrar getirmemelisiniz. Yazardan Log4j'den, Ceki Gülcü: 

Sarıcı sınıflarındaki en yaygın hata, her bir günlük isteğinde Logger.getLogger yönteminin çağrılmasıdır. Bu, uygulamanızın performansını olumsuz etkileyeceği garantilidir. Gerçekten mi!!! 

Bu bir Logger almak için kullanılan geleneksel ve verimli deyimdir, sınıf başlatma sırasında:

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

Bunun size bir hiyerarşideki her tür için ayrı bir Kaydedici sağladığını unutmayın. Bir örnekte getClass() işlevini çağıran bir yöntem bulursanız, alt türün günlüğünün altında gösterilen bir temel tür tarafından kaydedilen mesajları görürsünüz. Belki bu bazı durumlarda arzu edilir, ancak kafa karıştırıcı buluyorum (ve yine de miras üzerindeki kompozisyonu tercih etme eğilimindeyim). 

Açıkçası, getClass() yoluyla dinamik türün kullanılması, kaydediciyi statik tür bilgisini kullanarak önerilen deyim gibi sınıf başına bir kez yerine, en az bir kere edinmenizi gerektirir.

22
erickson

MethodHandles class (Java 7'den itibaren), statik bir bağlamdan geçerli sınıfın adını bulabilen ve döndürebilen bir Lookup sınıfını içerir. Aşağıdaki örneği düşünün:

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

Çalıştırdığınızda bu üretir:

Main

Bir kayıt cihazı için şunları kullanabilirsiniz:

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

LogUtils sınıfında aslında benzer bir şeyimiz var. Evet, bu biraz zor, ama avantajlar endişelendiğim kadarıyla buna değer. Tekrar tekrar çağrılmasından dolayı hiçbir ek yükümüz olmadığından emin olmak istedik, bu yüzden bizim (biraz hacki) SADECE statik bir başlatıcı bağlamından çağrılabilir:

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

Performans yükü riskini azaltmak için normal bir yöntemle veya bir örnek başlatıcıdan (yani, 'statik' yukarıda bırakılmışsa) çağrılırsa başarısız olur. Yöntem:

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

Bunun ne gibi avantajlara sahip olduğunu soran herkes 

= Logger.getLogger(MyClass.class);

muhtemelen hiç bir zaman bu satırları başka bir yerden kopyalayıp yapıştıran ve sınıf adını değiştirmeyi unutan biriyle uğraşmak zorunda kalmamış, sizi tüm eşyalarını başka bir logger'a gönderen bir sınıfla başa çıkmayı bırakmıştır.

17
Cowan

Kaydedicilere statik destek verdiğinizi varsayalım, işte bağımsız bir statik 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();
    }
}

Kullanımı Güzel ve Temiz:

Logger logger = LoggerUtils.getLogger();
8
EGB

Bunu kullandığınız her sınıf için, yine de Logger'a bakmak zorunda kalacaksınız, bu yüzden bu sınıflarda sadece statik bir Logger kullanabilirsiniz.

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

Ardından, günlük mesajlarınızı yapmanız gerektiğinde bu kaydediciye başvurursunuz. Metodunuz statik Log4J Logger'ın zaten yaptığı şeyi yapıyor, neden tekerleği yeniden icat ettin?

4
18Rabbit

O zaman en iyi şey, ikisinin karışımıdır. 

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

Ve sonra her sınıfta:

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

kodda:

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

Her sınıfa kopyalayıp yapıştırabileceğiniz ve ek yükü olmadan yapabileceğiniz statik kayıt cihazı ...

Alaa

3
Alaa Murad

Bu sitedeki diğer tüm geri bildirimleri okuduğumda, Log4j ile kullanmak için aşağıdakileri oluşturdum:

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

}

Şimdi kodunuzda ihtiyacınız olan tek şey

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

veya

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

Log4j yöntemlerine daha fazla maruz kalmaya ihtiyacınız varsa, bunları yukarıda listelenen Logger sınıfından kurtarmanız yeterlidir.

3
Ed Sarrazin

Her sınıf için (statik) bir Logger oluşturmayı tercih ederim (açık sınıf adı ile). Kaydediciyi olduğu gibi kullanmaktan daha çok.

2
Philip Helger

Tabii ki Log4J'i uygun desen düzeni ile kullanabilirsiniz:

Örneğin, "org.Apache.xyz.SomeClass" sınıf adı için,% C {1} kalıbı "SomeClass" çıktısını verecektir. 

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

2
Ian

Yeni bir Atılabilir nesne oluşturmanıza gerek yoktur. Sadece Thread.currentThread().getStackTrace()[1] 'i çağırabilirsin.

2
ykaganovich

Basit ve önemsiz ESKİ OKULU:

Sadece kendi sınıfınızı yaratın ve oraya sınıf adı, yöntem adı + yorum yazın (eğer sınıf/yöntem değiştiyse otomatik olarak 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);
    }
}

ve sadece uygulamanın herhangi bir yerinde kullanın (bağlam gerekmez, ilklendirme yapılmaz, ekstra kütüphaneler olmaz ve aranmaz) - herhangi bir programlama dili için kullanılabilir!

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

bu konsolunuzda yazdırılacaktır:

MY_TAG sınıfı: MainActivity meth: onCreate comm: Hello world

0
Choletski

Bu mekanizma, çalışma süresinde çok fazla çaba harcar.

Eclipse'ı IDE'niz olarak kullanıyorsanız, Log4e 'yi kullanmayı düşünün. Bu kullanışlı eklenti, en sevdiğiniz günlük çerçevesini kullanarak sizin için günlük beyanları üretecektir. Kodlama zamanında çok daha fazla çaba harcar, ancak çalışma zamanında çok daha az çalışır.

0
Bill Michell

İyi bir alternatif, (biri) lombok günlüklerini ek açıklamaları kaydeder: https://projectlombok.org/features/Log.html

Geçerli sınıfa karşılık gelen log ifadesini üretir.

0
user2189998

Bunu Java 7'den itibaren yapmanın güzel bir yolu:

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

Kaydedici static ve bu para cezası olabilir . Burada SLF4J API'sini kullanıyor

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

Ancak prensipte herhangi bir kayıt çerçevesi ile kullanılabilir. Kaydedicinin bir string argümanına ihtiyacı varsa toString() ekleyin.

0
James Mudd

Sınıflarımın çoğunun başında şu satırı izliyorum.

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

evet, o sınıfın bir nesnesi ilk defa yaratıldığında bazı ek yükler var, ama çoğunlukla webapps'ta çalışıyorum, bu yüzden 20 saniyelik bir başlangıç ​​üzerine mikrosaniye eklemek gerçekten bir sorun değil.

0
muttonUp

Siz gerçekten Logger'ınızın statik olmasına ihtiyaç duymazsanız, kullanabilirsiniz

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

Google Flogger günlüğü API’sı bunu destekler.

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

Daha fazla ayrıntı için https://github.com/google/flogger adresine bakın.

0
James Mudd

Logger / 'a jcabi-log ' den bir göz atın. Tam olarak aradığınızı yapar ve statik yöntemler topluluğu sağlar. Kaydedicileri artık sınıfa yerleştirmenize gerek yok:

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

Logger, tüm günlükleri çalışma zamanında diğer herhangi bir günlük tesisine yönlendirebileceğiniz SLF4J'ye gönderir.

0
yegor256

Neden olmasın?

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

Ve sonra bir sınıf için bir kayıt cihazına ihtiyacınız olduğunda:

getLogger(this).debug("Some log message")
0
Mario Ortegón

Lütfen statik getLogger () uygulamamı görün (varsayılan Java Logger doit gibi JDK 7'de aynı "Sun. *" sihirini kullanın)

  • çirkin günlük özelliği olmadan statik günlüğe kaydetme yöntemlerini (statik içe aktarma ile birlikte) not alın ...

    statik alma statik.pakg.Logger. *;

Ve hızları, yerel Java uygulamasına eşdeğerdir (1 milyon günlük iziyle kontrol edilir)

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