2009-08-28 13 views
15

Sto cercando un modo per includere __LINE__ come costante in fase di compilazione nei messaggi emessi.__LINE__ equivalente in Java?

Diverse soluzioni sembrano esistere, ma con una grande penalità di runtime come suggerito in __LINE__ in JS e __LINE__ in C#. Solitamente si basano sempre su un oggetto runtime StackFrame come log4j.

L'utilizzo della possibilità log4j di abilitazione/disabilitazione su una base necessaria non è un'opzione, poiché solitamente quando si verifica un errore, è troppo tardi per abilitare i numeri di riga e il codice inserito non sembra avere numeri di linea più. . Sarebbe possibile, a:

  1. Pre-processo i file sorgente Java prima della compilazione, idealmente con qualcosa di integrato con Eclipse , così la si può essere testato sulla piattaforma DEVELOPPEMENT anche.
  2. Essere in grado di pre-processo la classe al momento del caricamento. L'overhead sarebbe quindi trascurabile essendo ammortizzato.

1. In realtà io uso un brutto hack: chiamando un preprocessore personalizzato solo dopo la partenza sul server di build tramite trucchi ANT

+0

Solo per la mia curiosità: perché è necessario il numero di riga nei registri? Quando si verifica un errore, si ha lo stacktrace completo, che indica il numero di linea ... – romaintaz

+3

A volte nell'eccezione, invece del numero di riga ho qualcosa come 'Util.java (Inline Compiled Code)'. E a volte non ho alcuna eccezione, solo la registrazione delle informazioni: "essere qui", "essere qui", non volevo preoccuparmi di avere messaggi univoci (il numero di linea li rende comunque unici) –

+0

La JVM dovrebbe essere in grado di gestire questa situazione. Quale versione di Java usi? –

risposta

8

Se si compila con l'opzione debug=line, le informazioni riga esiste nel file di classe, ma la VM può buttare via tutto in fase di esecuzione . Questo dipende da alcune opzioni che è possibile specificare quando si avvia il programma Java. Di solito, la penalizzazione delle prestazioni per l'esecuzione delle informazioni di debug è di circa il 5% più un po 'più di memoria nello spazio dei perm gen. Poiché queste informazioni sono così preziose, non vedo alcun motivo per eliminare queste informazioni.

Il tuo commento (Util.java(Inlined Compiled Code)) suggerisce che stai utilizzando ottimizzazioni aggressive. Se puoi, disattivali. In questo modo, si può semplicemente:

// For Java 1.4, use new Exception().getStackTrace() 
int line = Thread.currentThread().getStackTrace()[0].getLineNumber(); 

quando serve (cioè all'interno del catch o if (log.isInfoEnabled())).

Per quanto riguarda __LINE__, il compilatore Java non supporta questo. L'unica opzione è usare alcuni hack per filtrare la fonte. Suggerisco di definire una variabile int __LINE__ da qualche parte e impostarla su un valore casuale (0 è abbastanza casuale) quando è necessario. Quindi scrivi un filtro che sostituisce il numero in __LINE__ = \d+ con il numero di riga corrente. Ciò consente di correggere il numero di riga in posizione.

+0

Perché 'new Exception(). GetStackTrace()' piuttosto che 'Thread.currentThread(). GetStackTrace()'? –

+0

Nessun motivo tranne il fatto che non mi sono preoccupato di cercare nella classe Thread per come ottenere lo stack corrente e sapevo che c'era un'eccezione :) –

+0

+1 per la soluzione che poteva essere utilizzata anche sul mio ambiente di sviluppo (cerca e sostituisci 'Thread ....' con il numero di riga nel processo di compilazione) –

13

E 'impossibile per ottenere l'effetto di __LINE__ in C che avviene in fase di compilazione tempo.

È possibile ottenere il numero di riga chiamando una funzione come questa in fase di esecuzione,

public static int lineNumber() { 
    return Thread.currentThread().getStackTrace()[2].getLineNumber(); 
} 
+2

Le informazioni di debug sulla linea devono essere compilate nel file di classe, per accedere a queste informazioni. – Mnementh

0

Fuori dalla scatola, non credo che Java offra ciò di cui hai bisogno.

Tuttavia se si dovesse scrivere il proprio processore di annotazione e utilizzare Java 6.0 compiler APIs, penso che si possa risolvere questo problema. Non mi interesserebbe indovinare quanto lavoro sarebbe fare per farlo.

Si noti che Eclipse consente di includere l'elaborazione della propria annotazione nel suo meccanismo di compilazione.

0

Non so una cosa del genere nel compilatore Java. Ma potresti scrivere un semplice programma, che sostituisce un token come __LINE__ con il numero di telefono nel file e configurare il tuo processo di build per eseguire questo strumento prima della compilazione. Una specie di preprocessore.

+0

Questo è esattamente quello che vorrei sostituire (vedi nota 1). –

1

Vorrei utilizzare un framework di registrazione per questo e lasciarlo gestire i dettagli disordinati. Sia java.util.logging che il logback possono mostrare facilmente le informazioni sul chiamante in modo simile a quanto può fornire la LINE.

Il vantaggio principale è che l'informazione viene calcolata solo se necessario, quindi non emettere significa non sovraccaricare.

5

Che vero che fuori dagli schemi, queste macro non sono disponibili. Tuttavia, utilizzando la strumentazione e le informazioni di debug è possibile implementarle. check http://www.gallot.be/?p=85

4

Ho trovato questa classe che semplifica le cose se stai cercando la registrazione del tipo "arrivato qui, arrivato qui". Ho un Here.java file aggiungo ai miei progetti che contiene solo la seguente definizione di classe:

public class Here { 
    public static String at() { 
     StackTraceElement ste = Thread.currentThread().getStackTrace()[3]; 
     String where = ste.getClassName() + " " + ste.getMethodName() + " " + ste.getLineNumber() + " "; 
     return where; 
    } 
} 

Per utilizzarlo nella sua forma più semplice:

Log.v(TAG, Here.At()); 

O, se si vuole vedere altre cose:

Log.v(TAG, Here.At() + String.format("interesting value = %d", my_val)); 

Ciò darebbe "com.otherpackagenamestuff.MyClass myMethod 225" nel primo caso, e lo stesso ma con "interessante valore = 123" aggiunto nel secondo caso.