web-dev-qa-db-ja.com

Java発信者のクラス名を自動的に決定するロガー

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

35
yanchenko

すべてのクラスに多くのオーバーヘッドが追加されると思います。すべてのクラスは「ルックアップ」する必要があります。それを行うために新しいThrowableオブジェクトを作成します...これらのthrowableは無料ではありません。

15
Daan

スタックトレースの作成は、比較的遅い操作です。呼び出し元は、それがどのクラスとメソッドであるかをすでに知っているため、労力が無駄になります。ソリューションのこの側面は非効率的です。

静的クラス情報を使用する場合でも、メッセージごとにロガーを再度フェッチしないでください。 著者から Log4j、CekiGülcüの:

ラッパークラスで最も一般的なエラーは、各ログリクエストでのLogger.getLoggerメソッドの呼び出しです。これにより、アプリケーションのパフォーマンスが大混乱することが保証されます。本当に!!!

これは、クラスの初期化中にロガーを取得するための従来の効率的なイディオムです。

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

これにより、階層のタイプごとに個別のロガーが提供されることに注意してください。インスタンスでgetClass()を呼び出すメソッドを考え出すと、サブタイプのロガーの下に表示されるベースタイプによって記録されたメッセージが表示されます。たぶんこれは望ましい場合もありますが、私はそれが混乱していると思います(そして、とにかく継承よりも合成を好む傾向があります)。

明らかに、getClass()を介して動的型を使用するには、静的型情報を使用する推奨イディオムのように、クラスごとに1回ではなく、インスタンスごとに少なくとも1回ロガーを取得する必要があります。

23
erickson

MethodHandles クラス(Java 7の時点)には、静的コンテキストからの名前を検索して返すことができる Lookup クラスが含まれています現在のクラス次の例を考えてみましょう:

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

実行すると、以下が生成されます。

Main

ロガーの場合、次を使用できます。

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

LogUtilsクラスにも実際には非常に似たようなものがあります。はい、それはちょっとうるさいですが、私が懸念している限り、利点はそれだけの価値があります。ただし、繰り返し呼び出されることによるオーバーヘッドがないようにしたかったので、私たちのものは(多少ハック的に)静的初期化コンテキスト、laからのみ呼び出せることを保証します。

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

パフォーマンスのオーバーヘッドのリスクを減らすために、通常のメソッドまたはインスタンス初期化子から呼び出された場合(つまり、「静的」が上に残っていた場合)、失敗します。メソッドは次のとおりです。

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

これにはどんな利点があるのか​​と尋ねる人

= Logger.getLogger(MyClass.class);

おそらく他の場所からその行をコピーして貼り付け、クラス名を変更するのを忘れて、すべてのものを別のロガーに送信するクラスを処理する人を扱う必要はありません。

18
Cowan

ロガーへの静的参照を保持していると仮定すると、スタンドアロンの静的シングルトンは次のようになります。

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

使い方はすてきできれいです:

Logger logger = LoggerUtils.getLogger();
8
EGB

これを使用するすべてのクラスについて、とにかくLoggerを検索する必要があるため、これらのクラスで静的Loggerを使用することもできます。

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

次に、ログメッセージを実行する必要があるときに、そのロガーを参照します。あなたのメソッドは静的なLog4J Loggerと同じことをするので、なぜ車輪を再発明するのですか?

4
18Rabbit

そして、最高のものは2つのミックスです。

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

そして、すべてのクラスで:

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

コード内:

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

すべてのクラスでオーバーヘッドなしでコピー&ペーストできる静的ロガーを取得します...

アラア

3
Alaa Murad

このサイトの他のすべてのフィードバックを読んで、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);
}

}

これで、コードに必要なのは

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

または

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

Log4jメソッドをさらに公開する必要がある場合は、上記のLoggerクラスからそれらを委任するだけです。

3
Ed Sarrazin

クラスごとに(静的な)ロガーを作成することを好みます(明示的なクラス名を使用)。ロガーをそのまま使用するよりも。

2
Philip Helger

もちろん、適切なパターンレイアウトでLog4Jを使用することもできます。

たとえば、クラス名「org.Apache.xyz.SomeClass」の場合、パターン%C {1}は「SomeClass」を出力します。

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

2
Ian

新しいThrowableオブジェクトを作成する必要はありません。単にThread.currentThread().getStackTrace()[1]を呼び出すことができます

2
ykaganovich

ほとんどのクラスの冒頭に次の行があります。

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

はい、そのクラスのオブジェクトが最初に作成されるときにオーバーヘッドがありますが、私は主にwebappsで作業しているため、20秒のスタートアップにマイクロ秒を追加することは実際には問題ではありません。

1
muttonUp

Google FloggerロギングAPIはこれをサポートしています。

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

詳細については、 https://github.com/google/flogger を参照してください。

1
James Mudd

シンプルでつまらないOLD SCHOOL:

独自のクラスを作成して、クラス名、メソッド名+コメントを渡すだけです(クラス/ methodが変更された場合、それらは自動的にリファクタリングされます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);
    }
}

アプリ内の任意の場所で使用するだけです(コンテキスト不要、初期化なし、追加のライブラリなし、ルックアップなし)-任意のプログラミング言語で使用できます!

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

これはコンソールに印刷されます:

MY_TAGクラス:MainActivity meth:onCreate comm:Hello world

0
Choletski

このメカニズムは、実行時に多くの余分な努力をします。

IDEとしてEclipseを使用する場合は、 Log4e の使用を検討してください。この便利なプラグインは、お気に入りのロギングフレームワークを使用してロガー宣言を生成します。コーディング時の労力は少し増えますが、much実行時の作業は少なくなります。

0
Bill Michell

適切な代替方法は、ロンボクログアノテーション(の1つ)を使用することです。 https://projectlombok.org/features/Log.html

現在のクラスに対応するログステートメントを生成します。

0
user2189998

Java 7以降:

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

ロガーはstaticでもかまいません。ここでは、SLF4J APIを使用しています

_import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
_

ただし、原則として、任意のロギングフレームワークで使用できます。ロガーに文字列引数が必要な場合は、toString()を追加します

0
James Mudd

本当に Loggerを静的にする必要がない限り、

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

Loggerjcabi-log のクラスを見てください。探しているものを正確に実行し、静的メソッドのコレクションを提供します。ロガーをクラスに埋め込む必要はもうありません。

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

LoggerはすべてのログをSLF4Jに送信します。SLF4Jは実行時に他のログ機能にリダイレクトできます。

0
yegor256

何故なの?

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
Mario Ortegón

私の静的getLogger()実装を参照してください(JDK 7でデフォルトと同じ「Sun. *」マジックを使用してくださいJava Logger doit)

  • ugいログプロパティなしの静的ロギングメソッド(静的インポートを使用)に注意してください...

    import static my.pakg.Logger。*;

そして、それらの速度は、ネイティブJava実装(100万のログトレースで確認)と同等です)

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