spesometro Registrazione Java: mostra il numero della riga di origine del chiamante(non il metodo di supporto della registrazione)




fatturazione elettronica nome file non valido (7)

I numerosi (sigh ...) framework di registrazione per Java fanno un buon lavoro di mostrare il numero di riga del nome del file di origine per il metodo che ha creato il messaggio di log:

log.info("hey");

 [INFO] [Foo:413] hey

Ma se hai un metodo di supporto in mezzo, il chiamante effettivo sarà il metodo di supporto, e questo non è troppo informativo.

log_info("hey");

[INFO] [LoggingSupport:123] hey

C'è un modo per dire al sistema di registrazione di rimuovere un frame dal callstack quando si trova la posizione di origine da stampare?

Suppongo che questa sia l'implementazione specifica; quello di cui ho bisogno è Log4J tramite Commons Logging, ma sono interessato a conoscere altre opzioni.


Answer #1

Questo non è possibile fuori dalla scatola. Il meglio che puoi fare in questo caso è creare il logger nel chiamante e passarlo al metodo util. In questo modo, puoi almeno avere un'idea di dove è arrivata la chiamata.


Answer #2

Se si dispone dei propri metodi di utilità di registrazione, è possibile aggiungere biancheria e nome file all'elenco di argomenti di registrazione e prendere la rotta cpp. cioè Pre-elaborare l'origine per sostituire tag come _ LINE _ e _ FILE _ prima di eseguire la compilazione. Come bonus aggiuntivo questo non richiederebbe nerly tante risorse quanto capire a runtime.


Answer #3

Risposta alternativa

È possibile chiedere a log4j di escludere la classe helper usando il metodo

Category.log (String callerFQCN, livello di priorità, messaggio Object, Throwable t)

e specificando la classe helper come 'callerFQCN'.

Ad esempio, ecco una classe che usa un helper:

public class TheClass {
    public static void main(String...strings) {
        LoggingHelper.log("Message using full log method in logging helper.");
        LoggingHelper.logNotWorking("Message using class info method");
}}

e il codice dell'helper:

public class LoggingHelper {
private static Logger LOG = Logger.getLogger(LoggingHelper.class);

public static void log(String message) {
    LOG.log(LoggingHelper.class.getCanonicalName(), Level.INFO, message, null);
}

public static void logNotWorking(String message) {
    LOG.info(message);
} }

Il primo metodo produrrà il risultato atteso.

Line(TheClass.main(TheClass.java:4)) Message using full log method in logging helper.
Line(LoggingHelper.logNotWorking(LoggingHelper.java:12)) Message using class info method

Quando si utilizza questo metodo, Log4j funzionerà come al solito, evitando il calcolo della traccia dello stack, se non è richiesto.


Answer #4

Aggiunta di dettagli alla risposta KLE. (mi dispiace, utente noob, non conosco il modo migliore di creare una risposta separata)

Invece di attaccare il numero di riga al messaggio, è possibile inserirlo nel contesto MDC. Vedi org.apache.log4j.MDC

Per esempio:

StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
StackTraceElement stackTraceElement = ...;
int l = stackTraceElement.getLineNumber();

MDC.put("myLineNumber", l);

Ciò consente agli utenti di utilizzare mylineNumber nel loro file di configurazione log4j

<layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" 
           value="Line(%X{myLineNumber})- %m%n"/>
</layout>

Nota: ciò consente all'utente di controllare dove e come appare il numero di riga nel messaggio. Tuttavia, poiché ottenere lo stacktrace è molto costoso, è comunque necessario trovare un modo per disattivare la funzionalità.


Answer #5

Forse puoi implementare la funzione helper del registro usando l'elemento stack trace, ottieni i numeri di riga e ignora i frames con il metodo con alcune annotazioni specifiche, come,

public @interface SkipFrame {}

// helper function
@SkipFrame // not necessary on the concrete log function
void log(String... message) {
    // getStackTrace()...
    int callerDepth = 2;  // a constant number depends on implementation
    StackTraceElement callerElement = null; 
    for (StackTraceElement e: stackTrace) {
         String className, methodName = e.getClassName, getMethodName()...
         Class callClass = Class.forName(className);
         // since there maybe several methods with the same name
         // here skip those overloaded methods
         Method callMethod = guessWhichMethodWithoutSignature(callClass, methodName);
         SkipFrame skipFrame = callMethod.getAnnotation(SkipFrame.class); 
         if (skipFrame != null)
             continue; // skip this stack trace element
         if (callerDepth-- == 0) {
             callerElement = e; 
             break;
         }
     }
     assert callerDepth == 0; 
     assert callerElement != null;
     Log4j.info(callerElement.getLineNumber()... + "message... "); 
}

@SkipFrame
void logSendMail(Mail mailObject) {
    log("Send mail " + mailObject.getSubject()); 
}

Pertanto, se la funzione di supporto è nidificata o ci sono più funzioni di aiuto utilizzate, contrassegna l'annotazione SkipFrame su tutte e ottieni il numero di riga di origine corretto che desideri.


Answer #6

Viene fuori che esiste una soluzione molto semplice, basta aggiungere FQCN (il nome classe completo della classe wrapper) al proprio helper del logger:

public class MyLogger extends Logger {

private static final String FQCN = MyLogger.class.getName() + ".";

protected MyLogger(String name) {
    super(name);
}

public void info(final Object msg) {
    super.log(FQCN, Level.INFO, msg, null);
}

//etc...

Nella tua classe lavoratrice fai semplicemente:

public class MyClass {

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

private void test()
{
    LOG.info("test");
}

}

Answer #7

Si noti che dare il numero di linea è qualcosa di molto costoso , sia per ciò che si ottiene naturalmente da Log4j o quanto segue. Devi accettare quel costo ...

Puoi utilizzare le seguenti API:

    StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
    StackTraceElement stackTraceElement = ...;
    stackTraceElement.getLineNumber();

aggiornato:

Dovresti calcolarlo da solo. Così:

  • chiedere a log4j di non emetterlo (nel proprio formato di registrazione),
  • e inserisci la spiegazione del numero di riga all'inizio del messaggio (la stringa che invii a log4j).

A seconda di come preferisci i tuoi logger, il tuo metodo di supporto potrebbe:

  • utilizzare un Logger esplicito (passato come parametro credo), quando appropriato (a volte definiamo logger specifici per un contesto specifico, ad esempio disponiamo di un logger per inviare le richieste del nostro database, indipendentemente dalla classe, questo ci permette di ridurre a un posto le modifiche apportate al nostro file di configurazione, quando vogliamo (demergerle) ...)
  • usa un Logger per la classe chiamante: in questo caso, invece di passare il parametro, puoi dedurre anche il nome della classe chiamante ...




apache-commons-logging