Se connecter en Java et en général: Meilleures pratiques?


Parfois, quand je vois mon code de journalisation, je me demande si je le fais correctement. Il n'y a peut-être pas de réponse définitive à cela, mais j'ai les préoccupations suivantes:

Cours de bibliothèque

J'ai plusieurs classes de bibliothèque qui pourraient enregistrer des messages INFO. Les erreurs fatales sont signalées comme exceptions. Actuellement, j'ai une instance d'enregistreur statique dans mes classes avec le nom de classe comme nom de journalisation. (Log4j's: Logger.getLogger(MyClass.class))

Est-ce la bonne façon? Peut être l'utilisateur de cette bibliothèque la classe ne veut aucun message de mon implémentation ou veut les rediriger vers un journal spécifique à l'application. Dois-je permettre à l'utilisateur de définir un enregistreur à partir du "monde extérieur"? Comment gérez-vous de tels cas?

Général journaux

, Dans certaines applications, mes classes pourriez écrire un message de journal d'un journal non identifié par le nom. (I. e.: HTTP Request log) Quelle est la meilleure façon de faire une telle chose? Un service de recherche vient à l'esprit...

Author: bnjmn, 2009-05-25

8 answers

Vos conventions sont assez standard et assez fines (à mon humble avis).

La seule chose à surveiller est la fragmentation de la mémoire à partir d'appels de débogage excessifs non résolus, donc, avec Log4J (et la plupart des autres frameworks de journalisation Java), vous vous retrouvez avec quelque chose comme ceci:

if (log.isDebugEnabled()) {
  log.debug("...");
}

Parce que la construction de ce message de journal (que vous n'utilisez probablement pas) pourrait être coûteuse, surtout si elle est effectuée des milliers ou des millions de fois.

Votre journalisation de niveau d'INFORMATION ne devrait pas être trop "bavarde" (et de ce que vous dire, on dirait qu'elle n'est pas). Les messages d'information doivent être généralement significatifs et significatifs, comme l'application en cours de démarrage et d'arrêt. Choses que vous pourriez vouloir savoir si vous rencontrez un problème. La journalisation de niveau débogage / fin est plus utilisée lorsque vous avez réellement un problème que vous essayez de diagnostiquer. La journalisation de débogage/fin n'est généralement activée qu'en cas de besoin. Info est généralement sur tout le temps.

Si quelqu'un ne veut pas de messages d'information spécifiques de vos classes, ils le sont bien sûr libre de changer votre configuration log4j pour ne pas les obtenir. Log4j est magnifiquement simple dans ce département (par opposition à la journalisation Java 1.4).

En ce qui concerne votre chose HTTP, je n'ai généralement pas trouvé cela comme un problème avec la journalisation Java car généralement une seule classe est responsable de ce qui vous intéresse, vous n'avez donc besoin que de le mettre au même endroit. Dans le (rare dans mon expérience) lorsque vous voulez des messages de journal communs dans des classes apparemment sans rapport, mettez simplement un jeton qui peut facilement être grapped pour.

 35
Author: cletus, 2009-05-25 10:48:50

Dans la réponse de@cletus , il a écrit sur le problème de

if (log.isDebugEnabled()) {
  log.debug("val is " + value);
}

Qui pourrait être surmonté en utilisant SL4J. Il fournit une aide au formatage

log.debug("val is {}", value);

Où le message n'est construit que si le niveau est debug.

De nos jours, l'utilisation de SL4J et de son enregistreur compagnon, Logback, est donc conseillée pour des raisons de performances et de stabilité.

 7
Author: serv-inc, 2017-05-23 12:02:39

En ce qui concerne l'instanciation des enregistreurs, j'ai eu un certain succès en utilisant un modèle Java Eclipse pour configurer mes enregistreurs:

private static Logger log = Logger.getLogger(${enclosing_type}.class);

Cela évite le problème d'une JVM qui s'occupe de votre trace de pile et réduit (trivialement, peut-être) la surcharge de la création de la trace de pile en premier lieu.

La grande chose à propos de l'utilisation d'un modèle comme celui-ci est que vous pouvez le partager avec votre équipe si vous souhaitez définir une norme cohérente pour les enregistreurs.

Il on dirait qu'IntelliJ prend en charge le même concept pour une variable de modèle représentant le nom du type englobant. Je ne vois pas de moyen de le faire facilement dans NetBeans.

 6
Author: justinpitts, 2012-11-14 14:18:35

L'option préférée pour le type de configuration log4j que vous décrivez est d'utiliser le fichier de configuration log4j. Cela permet aux utilisateurs de votre implémentation de faire exactement ce que vous demandez, car ils peuvent remplacer votre configuration plus tard avec quelque chose de plus adapté à leur propre implémentation. Voir ici pour un travail très complet d'apprêt.

 4
Author: John Feminella, 2009-05-25 10:48:54

J'ai probablement volé ça quelque part, mais c'est sympa.

Il réduit le risque de mélanger les enregistreurs lors de la copie et du refactoring pasti^h^h^h, et il est moins à taper.

Dans votre code:

private final static Logger logger = LoggerFactory.make();

...et dans LoggerFactory:

public static Logger make() {
    Throwable t = new Throwable();
    StackTraceElement directCaller = t.getStackTrace()[1];
    return Logger.getLogger(directCaller.getClassName());
}

(Notez que le stackdump est effectué lors de l'initialisation. La stacktrace ne sera probablement pas optimisée par la JVM mais il n'y a en fait aucune garantie)

 4
Author: KarlP, 2015-11-20 18:33:20

Je passe en revue les niveaux de journal d'une application et je détecte actuellement un modèle:

private static final Logger logger = Logger.getLogger(Things.class)

public void bla() {
  logger.debug("Starting " + ...)
  // Do stuff
  ...
  logger.debug("Situational")

  // Algorithms
  for(Thing t : things) {
    logger.trace(...)
  }

  // Breaking happy things
  if(things.isEmpty){
    logger.warn("Things shouldn't be empty!")
  }

  // Catching things
  try {
    ...
  } catch(Exception e) {
    logger.error("Something bad happened")
  }

  logger.info("Completed "+...)
}

Un log4j2-fichier définit une prise appender, avec un basculement de fichier appender. Et un appender de console. Parfois, j'utilise des marqueurs log4j2 lorsque la situation l'exige.

Pensait qu'une perspective supplémentaire pourrait aider.

 4
Author: Patrick, 2016-05-12 09:56:11

Voici les lignes directrices que je suis dans tous mes projets pour assurer une bonne performance. Je suis venu pour former cet ensemble de lignes directrices basées sur les entrées de diverses sources dans l'Internet.

Comme aujourd'hui, je crois que Log4j 2 est de loin la meilleure option pour se connecter en Java.

Les points de référence sont disponibles ici. La pratique que je suis pour obtenir les meilleures performances est la suivante:

  1. J'évite d'utiliser SLF4J pour le moment pour ce qui suit raisons:
  2. Faites toute la journalisation régulière en utilisant un enregistreur asynchrone pour de meilleures performances
  3. Erreur de journal messages dans un fichier séparé en utilisant synchrone logger parce que nous voulons voir les messages d'erreur dès qu'il se produit
  4. N'utilisez pas les informations de localisation, telles que le nom de fichier, le nom de classe, le nom de méthode, le numéro de ligne dans la journalisation régulière car pour dériver ces informations, le framework prend un instantané de la pile et la parcourt. Ceci a des répercussions sur la performance. Par conséquent, utilisez les informations de localisation uniquement dans le journal des erreurs et non dans le journal normal
  5. Puisque nous enregistrons les erreurs dans un fichier séparé, il est très important que nous enregistrons les informations de contexte également dans le journal des erreurs. Par exemple, si l'application a rencontré une erreur lors du traitement d'un fichier, imprimez le nom de fichier et l'enregistrement de fichier en cours de traitement dans le fichier journal des erreurs avec la stacktrace
  6. Le fichier journal doit être grep-able et facile à comprendre. Par exemple, si une application traite les enregistrements client dans plusieurs fichiers, chaque message de journal doit être comme ci-dessous:
12:01:00,127 INFO FILE_NAME=file1.txt - Processing starts
12:01:00,127 DEBUG FILE_NAME=file1.txt, CUSTOMER_ID=756
12:01:00,129 INFO FILE_NAME=file1.txt - Processing ends
  1. Enregistrez toutes les instructions SQL à l'aide d'un marqueur SQL comme indiqué ci-dessous et utilisez un filtre pour l'activer ou le désactiver:
private static final Marker sqlMarker = 
  MarkerManager.getMarker("SQL");

private void method1() {
    logger.debug(sqlMarker, "SELECT * FROM EMPLOYEE");
}
  1. Consigner tous les paramètres à l'aide de Java 8 Lambdas. Cela sauvera l'application du message de formatage lorsque le niveau de journal donné est désactivé:
int i=5, j=10;
logger.info("Sample output {}, {}", ()->i, ()->j);
  1. N'utilisez pas la concaténation de chaînes. Utilisez le message paramétré comme indiqué ci-dessus

  2. Utiliser dynamique rechargement de la configuration de journalisation afin que l'application recharge automatiquement les modifications de la configuration de journalisation sans avoir besoin de redémarrer l'application

  3. Ne pas utiliser printStackTrace() ou System.out.println()

  4. La demande doit arrêter l'enregistreur avant de sortir:

LogManager.shutdown();
  1. Enfin, pour la référence de tout le monde, j'utilise la configuration suivante:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorinterval="300" status="info" strict="true">
    <Properties>
        <Property name="filePath">${env:LOG_ROOT}/SAMPLE</Property>
        <Property name="filename">${env:LOG_ROOT}/SAMPLE/sample
        </Property>
        <property name="logSize">10 MB</property>
    </Properties>
    <Appenders>
        <RollingFile name="RollingFileRegular" fileName="${filename}.log"
            filePattern="${filePath}/sample-%d{yyyy-dd-MM}-%i.log">
            <Filters>
                <MarkerFilter marker="SQL" onMatch="DENY"
                    onMismatch="NEUTRAL" />
            </Filters>
            <PatternLayout>
                <Pattern>%d{HH:mm:ss,SSS} %m%n
                </Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy
                    interval="1" modulate="true" />
                <SizeBasedTriggeringPolicy
                    size="${logSize}" />

            </Policies>
        </RollingFile>
        <RollingFile name="RollingFileError" 
            fileName="${filename}_error.log"
            filePattern="${filePath}/sample_error-%d{yyyy-dd-MM}-%i.log"
            immediateFlush="true">
            <PatternLayout>
                <Pattern>%d{HH:mm:ss,SSS} %p %c{1.}[%L] [%t] %m%n
                </Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy
                    interval="1" modulate="true" />
                <SizeBasedTriggeringPolicy
                    size="${logSize}" />
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <AsyncLogger name="com"
            level="trace">
            <AppenderRef ref="RollingFileRegular"/>
        </AsyncLogger>
        <Root includeLocation="true" level="trace">
            <AppenderRef ref="RollingFileError" level="error" />
        </Root>
    </Loggers>
</Configuration>
  1. Les dépendances Maven requises sont ici:
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.8.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.8.1</version>
</dependency>
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.6</version>
</dependency>
<!-- (Optional)To be used when working 
with the applications using Log4j 1.x -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-1.2-api</artifactId>
    <version>2.8.1</version>
</dependency>
 3
Author: Saptarshi Basu, 2018-01-21 05:40:17

En plus, je pense qu'il est important de signifier une façade de journalisation simple pour Java (SLF4J) (http://www.slf4j.org / ). En raison de certains problèmes d'utilisation de différents frameworks de journalisation dans des parties diversifiées d'un grand projet, SLF4J est la norme de facto pour résoudre un problème pour gérer ces parties avec succès, n'est-ce pas?

La deuxième notion: il semble que certaines tâches de la vieille école puissent être substituées par Aspect-Oriented-Programming, Spring frmwrk a sa propre implémentation , AOP-approche pour la journalisation considéréeici à StackOverflow etici sur Spring blog.

 1
Author: Yauhen, 2017-05-23 12:26:17