JavaRush /Java Blog /Random-IT /Accedere a Java: cosa, come, dove e con cosa?
Roman Beekeeper
Livello 35

Accedere a Java: cosa, come, dove e con cosa?

Pubblicato nel gruppo Random-IT
Ciao a tutti, comunità JavaRush! Oggi parleremo del logging Java:
  1. Cos'è questo, perché è così? In quali casi è meglio usare, in quali casi no?
  2. Quali sono le diverse implementazioni del login in Java e cosa dovremmo fare con questa diversità?
  3. Livelli di registrazione. Parliamo di cos'è l'appender e di come configurarlo correttamente.
  4. Nodi di registrazione e come configurarli correttamente in modo che tutto funzioni come vogliamo.
Questo materiale è destinato a un vasto pubblico. Sarà chiaro sia a chi ha appena familiarizzato con Java, sia a chi sta già lavorando, ma l'ha capito solo con logger.info(“log something”); Let's Go!

Perché è necessaria la registrazione?

Diamo un'occhiata a casi reali in cui la registrazione risolverebbe il problema. Ecco un esempio dal mio lavoro. Esistono punti applicativi che si integrano con altri servizi. Io utilizzo la registrazione di questi punti come un “alibi” : se l'integrazione non funziona, sarà facile capire da che parte è nato il problema. Si consiglia inoltre di registrare le informazioni importanti salvate nel database. Ad esempio, creando un utente amministratore. Questo è esattamente ciò che sarebbe bene registrare.

Strumenti di registrazione Java

Logging: cosa, come, dove e con cosa?  - 2Le soluzioni più note per l'accesso in Java includono:
  • log4j
  • LUGLIO - java.util.logging
  • JCL - registrazione dei beni comuni di Jakarta
  • Logback
  • SLF4J - facciata di registrazione semplice per Java
Diamo uno sguardo veloce a ciascuno di essi e nella parte pratica del materiale prenderemo come base la connessione Slf4j - log4j . Adesso questo potrà sembrarti strano, ma non preoccuparti: alla fine dell’articolo sarà tutto più chiaro.

System.err.println

Inizialmente, ovviamente, c'era System.err.println (registra l'output sulla console). Viene ancora utilizzato per ottenere rapidamente un registro durante il debug. Naturalmente, non è necessario parlare di alcuna impostazione qui, quindi ricordiamocelo e andiamo avanti.

Log4j

Questa era già una soluzione a tutti gli effetti, creata dalle esigenze degli sviluppatori. Si è rivelato uno strumento davvero interessante da utilizzare. A causa di varie circostanze, questa soluzione non è mai arrivata al JDK, cosa che ha fortemente turbato l’intera comunità. log4j aveva opzioni di configurazione in modo che la registrazione potesse essere attivata in un pacchetto com.example.typee disattivata in un sottopacchetto com.example.type.generic. Ciò ha reso possibile separare rapidamente ciò che doveva essere registrato da ciò che non era necessario. È importante notare qui che esistono due versioni di log4j: 1.2.x e 2.x.x, che sono incompatibili tra loro . log4j ha aggiunto un concetto come appender , ovvero uno strumento con cui vengono registrati i log e layout: formattazione dei log. Ciò ti consente di registrare solo ciò di cui hai bisogno e come ne hai bisogno. Parleremo più approfonditamente dell'appender un po' più tardi.

LUGLIO - java.util.logging

Uno dei principali vantaggi è la soluzione: JUL è incluso nel JDK (kit di sviluppo Java). Sfortunatamente, durante lo sviluppo, non è stato preso come base il popolare log4j, ma una soluzione IBM, che ne ha influenzato lo sviluppo. Infatti al momento c'è JUL, ma nessuno lo usa. Dal “così così”: in JUL i livelli di logging sono diversi da quanto c'è in Logback, Log4j, Slf4j, e questo peggiora la comprensione tra loro. La creazione di un logger è più o meno simile. Per fare ciò è necessario importare:
java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
Il nome della classe viene passato specificatamente per sapere da dove proviene la registrazione. A partire da Java 8, è possibile passare Supplier<String>. Questo aiuta a contare e creare una stringa solo nel momento in cui è veramente necessario, e non ogni volta, come prima. Solo con il rilascio di Java 8 gli sviluppatori hanno risolto problemi importanti, dopodiché JUL è diventato veramente utilizzabile. Vale a dire, metodi con argomento Supplier<String> msgSuppliercome mostrato di seguito:
public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL - registrazione dei beni comuni di Jakarta

Dato che per molto tempo non è esistito uno standard industriale per il logging e c'è stato un periodo in cui molte persone creavano il proprio logger personalizzato, hanno deciso di rilasciare JCL, un wrapper comune che sarebbe stato utilizzato rispetto ad altri. Perché? Quando alcune dipendenze venivano aggiunte al progetto, potevano utilizzare un logger diverso da quello del progetto. Per questo motivo sono stati aggiunti in modo transitorio al progetto, il che ha creato seri problemi nel tentativo di mettere insieme il tutto. Sfortunatamente, il wrapper era molto povero di funzionalità e non introduceva alcuna aggiunta. Probabilmente sarebbe conveniente se tutti utilizzassero JCL per svolgere il proprio lavoro. Ma in realtà non è andata così, quindi utilizzare JCL al momento non è una buona idea.

Logback

Quanto è spinoso il percorso dell'open source... Logback è stato scritto dallo stesso sviluppatore di log4j per crearne un successore. L'idea era la stessa di log4j. Le differenze erano che nel logback:
  • prestazione migliorata;
  • aggiunto il supporto nativo per slf4j;
  • L'opzione di filtraggio è stata ampliata.
Per impostazione predefinita, il logback non richiede alcuna impostazione e registra tutti i registri dal livello DEBUG e superiore. Se è necessaria la configurazione, è possibile eseguirla tramite la configurazione xml:
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
    <root level="info">
        <appender-ref ref="FILE" />
    </root>
</configuration>

SLF4J - facciata di registrazione semplice per Java

Intorno al 2006, uno dei padri fondatori di log4j lasciò il progetto e creò slf4j - Simple Logging Facade for Java - un wrapper attorno a log4j, JUL, common-loggins e logback. Come puoi vedere, i progressi sono arrivati ​​al punto che è stato creato un wrapper sopra il wrapper... Inoltre, è diviso in due parti: l'API, che viene utilizzata nell'applicazione, e l'implementazione, che viene aggiunta come dipendenze separate per ciascun tipo di registrazione. Per esempio, slf4j-log4j12.jar, slf4j-jdk14.jar. Basta collegare la corretta implementazione e il gioco è fatto: l’intero progetto funzionerà con essa. Slf4j supporta tutte le nuove funzionalità come la formattazione delle stringhe per la registrazione. C'era già un problema del genere. Diciamo che c'è una voce di log:
log.debug("User " + user + " connected from " + request.getRemoteAddr());
userEsiste una conversione implicita nell'oggetto user.toString()dovuta alla concatenazione di stringhe e ciò richiede tempo, il che rallenta il sistema. E tutto va bene se eseguiamo il debug dell'applicazione. I problemi iniziano se il livello di registrazione per questa classe è INFO e superiore. Cioè, questo registro non dovrebbe essere scritto e non dovrebbe essere eseguita nemmeno la concatenazione di stringhe. In teoria, ciò avrebbe dovuto essere deciso dalla stessa libreria di registrazione. Inoltre, questo si è rivelato il problema più grande della prima versione di log4j. Non hanno fornito una soluzione normale, ma hanno suggerito di farlo in questo modo:
if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Cioè, invece di una riga di registrazione, hanno suggerito di scrivere 3(!). La registrazione dovrebbe ridurre al minimo le modifiche al codice e tre righe contraddicono chiaramente l'approccio generale. slf4j non ha avuto problemi di compatibilità con JDK e API, quindi è emersa immediatamente una bellissima soluzione:
log.debug("User {} connected from {}", user, request.getRemoteAddr());
dove {}denotano inserimenti di argomenti passati nel metodo. Cioè, il primo {}corrisponde a user, il secondo {}- request.getRemoteAddr(). Per questo motivo, solo se il livello di logging consente la registrazione nel log, questo messaggio può essere concatenato in un unico messaggio. Successivamente, SJF4J è cresciuto rapidamente in popolarità ed è attualmente la soluzione migliore. Pertanto, prenderemo in considerazione la registrazione utilizzando l'esempio di un bundle slf4j-log4j12.

Cosa deve essere registrato

Ovviamente non dovresti registrare tutto. A volte questo non è necessario e persino pericoloso. Se, ad esempio, si mettono a disposizione i dati personali di qualcuno e questi in qualche modo vengono alla luce, ci saranno problemi reali, soprattutto nei progetti orientati all’Occidente. Ma c'è anche qualcosa che è obbligatorio registrare :
  1. Inizio/fine dell'applicazione. Dobbiamo sapere che l'applicazione è stata effettivamente avviata come previsto e terminata come previsto.
  2. Domande di sicurezza. Qui sarebbe utile registrare i tentativi di indovinare la password, registrare gli accessi di utenti importanti, ecc.
  3. Alcuni stati dell'applicazione . Ad esempio, il passaggio da uno stato all'altro in un processo aziendale.
  4. Alcune informazioni per il debug , con un livello di registrazione appropriato.
  5. Alcuni script SQL. Ci sono casi reali in cui ciò è necessario. Anche in questo caso, regolando abilmente i livelli, si possono ottenere ottimi risultati.
  6. I thread eseguiti (Thread) possono essere registrati nei casi in cui viene verificato il corretto funzionamento.

Errori di registrazione frequenti

Ci sono molte sfumature, ma ecco alcuni errori comuni:
  1. Registrazione in eccesso. Non dovresti registrare ogni passaggio che teoricamente potrebbe essere importante. Esiste una regola: i log possono caricare le prestazioni non più del 10%. Altrimenti ci saranno problemi di prestazioni.
  2. Registrazione di tutti i dati in un unico file. Ciò renderà molto difficile la lettura/scrittura ad un certo punto, per non parlare dei limiti di dimensione dei file su alcuni sistemi.
  3. Utilizzo di livelli di registrazione errati. Ogni livello di registrazione ha confini chiari e deve essere rispettato. Se il confine è vago, puoi concordare quale livello utilizzare.

Livelli di registrazione

x: Visibile
FATALE ERRORE AVVISARE INFORMAZIONI DEBUG TRACCIA TUTTO
SPENTO
FATALE X
ERRORE X X
AVVISARE X X X
INFORMAZIONI X X X X
DEBUG X X X X X
TRACCIA X X X X X X
TUTTO X X X X X X X
Cosa sono i livelli di registrazione? Per classificare in qualche modo i tronchi, era necessario fornire determinate designazioni e distinzioni. A questo scopo sono stati introdotti i livelli di registrazione. Il livello è impostato nell'applicazione. Se una voce appartiene ad un livello inferiore a quello designato, non viene inserita nel registro. Ad esempio, disponiamo di log utilizzati per eseguire il debug dell'applicazione. Nel normale lavoro di produzione (quando l'applicazione viene utilizzata per lo scopo previsto), tali registri non sono necessari. Pertanto, il livello di registrazione sarà superiore a quello del debug. Diamo un'occhiata ai livelli utilizzando log4j come esempio. Altre soluzioni, tranne JUL, utilizzano gli stessi livelli. Eccoli in ordine decrescente:
  • OFF: non viene scritto nessun log, verrà tutto ignorato;
  • FATALE: un errore dopo il quale l'applicazione non sarà più in grado di funzionare e verrà interrotta, ad esempio errore di memoria esaurita JVM;
  • ERRORE: il tasso di errore quando ci sono problemi che devono essere risolti. L'errore non arresta l'applicazione nel suo insieme. Altre query potrebbero funzionare correttamente;
  • AVVISO: indica i registri che contengono un avviso. Si è verificata un'azione inaspettata, nonostante ciò il sistema ha resistito e ha completato la richiesta;
  • INFO: un registro che registra azioni importanti nell'applicazione. Questi non sono errori, non sono avvisi, sono azioni previste dal sistema;
  • DEBUG: log necessari per eseguire il debug dell'applicazione. Per garantire che il sistema faccia esattamente ciò che ci si aspetta da esso, o per descrivere l’azione del sistema: “il metodo 1 ha iniziato a funzionare”;
  • TRACE: log con priorità più bassa per il debug, con il livello di logging più basso;
  • ALL: livello al quale verranno registrati tutti i log del sistema.
Risulta che se il livello di registrazione INFO è abilitato in qualche punto dell'applicazione, verranno registrati tutti i livelli, a partire da INFO e fino a FATAL. Se il livello di registrazione è FATAL, verranno registrati solo i registri con questo livello.

Registrazione e invio dei log: Appender

Considereremo questo processo utilizzando log4j come esempio: offre ampie opportunità per la registrazione/invio di log:
  • per scrivere su una soluzione file DailyRollingFileAppender ;
  • per ricevere dati nella console dell'applicazione - ConsoleAppender ;
  • per scrivere i log nel database - JDBCAppender ;
  • per controllare la trasmissione tramite TCP/IP - TelnetAppender ;
  • per garantire che la registrazione non influisca sulle prestazioni - AsyncAppender .
Esistono diverse altre implementazioni: l'elenco completo può essere trovato qui . In ogni caso, se l'appender richiesto non è disponibile, questo non è un problema. Puoi scrivere il tuo appender implementando l' interfaccia Appender , che accetta solo log4j.

Nodi di registrazione

Per la dimostrazione utilizzeremo l'interfaccia slf4j e l'implementazione di log4j. Creare un logger è molto semplice: è necessario scrivere quanto segue in una classe denominata MainDemo, nella quale verrà effettuato il logging:
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Questo creerà un logger per noi. Per creare una voce di registro, è possibile utilizzare molti metodi che indicano a quale livello verranno effettuate le voci. Per esempio:
logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find log4j.properties. Please, provide them");
logger.error("Connection refused to host = {}", host);
Anche se stiamo superando la classe, alla fine viene scritto il nome completo della classe con i pacchetti. Questo viene fatto in modo che tu possa poi dividere la registrazione in nodi e configurare un livello di registrazione e un appender per ciascun nodo. Ad esempio, il nome della classe: com.github.romankh3.logginglecture.MainDemo- al suo interno è stato creato un logger. Ed è così che può essere suddiviso in nodi di log. Il nodo principale è il RootLogger null . Questo è il nodo che riceve tutti i log dell'intera applicazione. Il resto può essere rappresentato come mostrato di seguito: Logging: cosa, come, dove e con cosa?  - 4Gli appender configurano il loro lavoro specificamente sui nodi di registrazione. Ora, utilizzando log4j.properties come esempio , vedremo come configurarli.

Configurazione passo passo di Log4j.properties

Ora imposteremo tutto passo dopo passo e vedremo cosa si può fare:
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Questa riga dice che stiamo registrando un appender CONSOLE che utilizza l'implementazione org.apache.log4j.ConsoleAppender. Questo appender scrive i dati sulla console. Successivamente, registriamo un altro appender che scriverà su un file:
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
È importante notare che gli appender dovranno ancora essere configurati. Una volta che abbiamo già registrato gli appender, possiamo determinare quale livello di registrazione sarà nei nodi e quali appender verranno utilizzati.

log4j.rootLogger=DEBUG, CONSOLE, FILE

  • log4j.rootLogger significa che configureremo il nodo principale, che contiene tutti i log;
  • dopo il segno uguale, la prima parola indica a quale livello e superiore verranno registrati i log (nel nostro caso si tratta di DEBUG);
  • quindi dopo la virgola vengono indicati tutti gli appender che verranno utilizzati.
Per configurare un nodo di registrazione specifico, è necessario utilizzare la seguente voce:
log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
dove log4j.logger.serve per configurare un nodo specifico, nel nostro caso lo è com.github.romankh3.logginglecture. E ora parliamo di impostare l'appender CONSOLE:
# CONSOLE appender customisation
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Qui vediamo che possiamo impostare il livello dal quale verrà elaborato l'appender. Situazione reale: un messaggio con il livello info è stato ricevuto dal nodo logging e passato all'appender che gli è assegnato, ma l'appender, con il livello warn e superiore, ha accettato questo log, ma non ha fatto nulla con esso. Successivamente, devi decidere quale modello sarà presente nel messaggio. Nell'esempio sto utilizzando PatternLayout, ma ci sono molte soluzioni là fuori. Non verranno divulgati in questo articolo. Un esempio di impostazione di un appender FILE:
# File appender customisation
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Qui è possibile configurare in quale file verranno scritti i log, come si può vedere da
log4j.appender.FILE.File=./target/logging/logging.log
La registrazione va nel file logging.log. Per evitare problemi con la dimensione del file, puoi impostare il massimo: in questo caso 1 MB. MaxBackupIndex: indica quanti file di questo tipo ci saranno. Se viene creato più di questo numero, il primo file verrà eliminato. Per vedere un esempio reale in cui è configurata la registrazione, puoi andare al repository aperto su GitHub.

Consolidiamo il risultato

Prova a fare tutto ciò che hai descritto tu stesso:
  • Crea il tuo progetto simile a quello nell'esempio sopra.
  • Se sai come usare Maven, lo useremo; in caso contrario, ecco un collegamento a un articolo che descrive come connettere la libreria.

Riassumiamo

  1. Abbiamo parlato di quali soluzioni ci sono in Java.
  2. Quasi tutte le librerie di logging conosciute sono state scritte sotto il controllo di una persona :D
  3. Abbiamo imparato cosa deve essere registrato e cosa no.
  4. Abbiamo calcolato i livelli di registrazione.
  5. Abbiamo conosciuto i nodi di registrazione.
  6. Abbiamo visto cos'è un appender e a cosa serve.
  7. Abbiamo configurato il file log4j.proterties passo dopo passo.

Materiali aggiuntivi

  1. JavaRush: registrazione. Svolgi una palla di stectrace
  2. JavaRush: lezione sui logger
  3. Habr: registrazione Java. Ciao mondo
  4. Habr: Java logging: la storia di un incubo
  5. Youtube: corsi Golovach. Registrazione. Parte 1 , Parte 2 , Parte 3 , Parte 4
  6. Log4j: appender
  7. Log4j: disposizione
Vedi anche gli altri miei articoli:
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION