Bibliothèque Java Open Source avec filtrage stacktrace, analyse de chaîne silencieuse et comparaison de version

Au fil du temps dans différents emplois, je suis tombé sur un besoin de plusieurs utilitaires que je ne pouvais pas trouver disponibles à l'époque. Et j'ai vu que j'en avais plusieurs fois besoin. J'ai donc écrit ma propre petite bibliothèque que j'ai trouvée très utile. Je viens donc de le publier en tant que bibliothèque java open-source.

Voici le lien Github

Javadoc en ligne est disponible ici

De plus, cette bibliothèque est disponible sur Maven Central. Voici les artefacts Maven (la version 1.5.0.8 est la dernière au moment de la rédaction de cet article mais pourrait changer à l'avenir. Pour rechercher la dernière version, recherchez l'artefact "MgntUtils" sur http: //search.maven. org / ):

<dependency> <groupId>com.github.michaelgantman</groupId> <artifactId>MgntUtils</artifactId> <version>1.5.0.8</version> </dependency> <dependency> <groupId>com.github.michaelgantman</groupId> <artifactId>MgntUtils</artifactId> <version>1.5.0.8</version> <classifier>javadoc</classifier> </dependency> <dependency> <groupId>com.github.michaelgantman</groupId> <artifactId>MgntUtils</artifactId> <version>1.5.0.8</version> <classifier>sources</classifier> </dependency> 

Vous trouverez ci-dessous une brève explication de ce qui s'y trouve. La bibliothèque est livrée avec un JavaDoc joliment écrit (j'espère) avec une description détaillée. Voici donc la liste des fonctionnalités:

Filtre de bruit Stacktrace


D'après mon expérience, cette fonctionnalité était la plus générique et la plus utile pour moi. Stacktrace est une bouée de sauvetage lorsque vous déboguez ou essayez de comprendre ce qui s'est mal passé dans votre application. Cependant, lorsque vous travaillez avec des journaux côté serveur, vous pouvez rencontrer une trace de pile énorme qui contient la plus longue queue inutile de divers cadres et packages liés au serveur d'applications. Et quelque part dans cette pile, il y a plusieurs lignes d'une trace pertinente et elles peuvent être dans différents segments séparés par des informations inutiles. Cela devient un cauchemar de rechercher une substance pertinente. Voici un lien qui décrit le même problème avec des exemples réels (pas pour les plus timides) https://dzone.com/articles/filtering-stack-trace-hell . Donc dans ma bibliothèque, il y a une classe qui s'appelle TextUtils et elle a la méthode getStacktrace () avec plusieurs signatures surchargées. Il prend une instance Throwable et permet de définir un préfixe de package des packages pertinents.

De plus, le même utilitaire (à partir de la version 1.5.0.3) a la méthode getStacktrace () qui prend l'interface CharSequence au lieu de Throwable et permet ainsi de filtrer et de raccourcir stacktrace stocké sous forme de chaîne de la même manière qu'un stacktrace extrait de Throwable. Ainsi, essentiellement les traces de pile peuvent être filtrées "à la volée" au moment de l'exécution ou ultérieurement à partir de n'importe quelle source de texte telle qu'un journal. (Juste pour clarifier - l'utilitaire ne prend pas en charge l'analyse et la modification de l'intégralité du fichier journal. Il prend en charge le filtrage uniquement d'une trace de pile transmise sous forme de chaîne. Donc, si quelqu'un veut filtrer les exceptions dans le fichier journal, il devra analyser le fichier journal et extraire les traces de pile en tant que chaînes distinctes, puis peut utiliser cet utilitaire pour filtrer chaque trace de pile individuelle).

Voici un exemple d'utilisation. Supposons que votre code d'entreprise réside toujours dans des packages commençant par "com.plain. *". Vous définissez donc un tel préfixe et procédez ainsi

 logger.info(TextUtils.getStacktrace(e,true,"com.plain.")); 

cela filtrera très intelligemment toutes les parties inutiles de la trace, vous laissant un stacktrace très concis. De plus, j'ai trouvé très pratique de prédéfinir le préfixe, puis d'utiliser simplement la méthode pratique

 TextUtils.getStacktrace(e); 

Il en sera de même. Pour prédéfinir le préfixe, utilisez simplement la méthode

 setRelevantPackage("com.plain."); 

Si vous souhaitez prédéfinir cette valeur par configuration, à partir de la version 1.1.0.1 de la bibliothèque, vous pouvez définir la variable d'environnement " MGNT_RELEVANT_PACKAGE " ou la propriété système " mgnt.relevant.package " sur la valeur " com.plain " . Et la propriété sera défini sur cette valeur sans que vous appeliez la méthode TextUtils.setRelevantPackage ("com.plain."); explicitement dans votre code. Notez que la valeur de la propriété System aurait priorité sur la variable d'environnement si les deux étaient définies. Juste un rappel qu'avec la propriété System vous pouvez l'ajouter dans votre ligne de commande en utilisant l'option -D:

"-Dmgnt.relevant.package = com.plain."

De plus, si vous utilisez une version antérieure à 1.1.0.1 de cette bibliothèque ou si vous ne souhaitez pas utiliser la variable d'environnement ou la propriété système mentionnée ci-dessus et que vous utilisez l'environnement Spring, vous pouvez prédéfinir le préfixe en ajoutant le segment suivant à votre configuration Spring:

 <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetClass" value="com.mgnt.utils.TextUtils"/> <property name="targetMethod" value="setRelevantPackage"/> <property name="arguments" value="com.plain."/> </bean> 

Javadoc explique tout en détail. Mais voici un petit teaser: vous obtiendrez un stacktrace suivant:

 at com.plain.BookService.listBooks() at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke() at net.sf.cglib.proxy.MethodProxy.invoke() ... at com.plain.LoggingAspect.logging() at sun.reflect.NativeMethodAccessorImpl.invoke0() ... at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks() at com.plain.web.BookController.listBooks() 

au lieu de

 at com.plain.BookService.listBooks() at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke() at net.sf.cglib.proxy.MethodProxy.invoke() at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed() at com.plain.LoggingAspect.logging() at sun.reflect.NativeMethodAccessorImpl.invoke0() at sun.reflect.NativeMethodAccessorImpl.invoke() at sun.reflect.DelegatingMethodAccessorImpl.invoke() at java.lang.reflect.Method.invoke() at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs() at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod() at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.transaction.interceptor.TransactionInterceptor.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept() at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks() at com.plain.web.BookController.listBooks() 

Analyse silencieuse des chaînes en entier, long, etc.


La même classe TextUtils fournit des méthodes pour analyser silencieusement String (sans exception jamais jetée) en types Double, Long, Integer, Short et Byte. Les méthodes sont appelées parseStringToLong () parseStringToInteger () etc. Ils prennent tous 4 arguments:

  1. Une chaîne à analyser
  2. Une implémentation de Number (Double, Long, Integer, Short ou Byte) pour servir de valeur par défaut en cas de problème d'analyse
  3. Une chaîne à imprimer en tant que message d'erreur dans le journal si le premier argument est nul (peut être nul, puis aucune erreur n'est imprimée)
  4. Une chaîne à imprimer en tant que message d'erreur si NumberFormatException s'est produite (peut être nulle, puis aucune erreur n'est imprimée)

Analyse de la chaîne à l'intervalle de temps


Dans la même classe TextUtils , il existe une méthode parseStringToTimeInterval (valeur de chaîne) . Cette méthode analyse une chaîne qui devrait contenir une valeur d'intervalle de temps - une valeur numérique avec un suffixe d'unité de temps facultatif. Par exemple, la chaîne "38s" sera analysée en 38 secondes, "24m" - 24 minutes "4h" - 4 heures, "3d" - 3 jours et "45" en 45 millisecondes. Les suffixes pris en charge sont " s " pour les secondes, " m " pour les minutes, " h " pour les heures et " d " pour les jours. Une chaîne sans suffixe est considérée comme contenant une valeur en millisecondes. Les suffixes ne sont pas sensibles à la casse. Si la chaîne fournie contient un suffixe non pris en charge ou contient une valeur numérique négative ou zéro ou contient une valeur non numérique, alors IllegalArgumentException est levée. Cette méthode renvoie la classe TimeInterval - une classe également définie dans cette bibliothèque. Essentiellement, il contient deux propriétés avec des getters et setters pertinents: long "value" et java.util.concurrent.TimeUnit. Mais en plus des getters et setters, cette classe possède les méthodes toMillis () , toSeconds () , toMinutes () , toHours () toDays () . Ces méthodes renvoient une valeur longue dans l'échelle de temps spécifiée (de la même manière que les méthodes correspondantes dans la classe java.util.concurrent.TimeUnit )

Cette méthode peut être très utile pour analyser les propriétés d'intervalle de temps telles que les délais d'expiration ou les périodes d'attente à partir des fichiers de configuration. Il élimine les calculs inutiles de différentes échelles de temps aux millisecondes dans les deux sens. Considérez que vous avez une propriété methodInvokingInterval que vous devez définir pour 5 jours. Donc, pour définir la valeur en millisecondes, vous devrez calculer que 5 jours correspondent à 432000000 millisecondes (évidemment pas une tâche impossible mais ennuyeuse et sujette aux erreurs), puis toute personne qui voit la valeur 432000000 devra la calculer à nouveau à 5 jours qui est frustrant. Mais en utilisant cette méthode, vous aurez une valeur de propriété définie sur "5d" et en invoquant le code

 long milliseconds = TextUtils.parsingStringToTimeInterval("5d").toMillis(); 

résoudra votre problème de conversion. Évidemment, ce n'est pas une fonctionnalité trop complexe, mais cela pourrait ajouter de la simplicité et de la clarté dans vos fichiers de configuration et sauver de la frustration et des erreurs de calcul "stupides" en bogues de millisecondes.

Comparer les versions


Cet utilitaire permet de convertir String en version et vice-versa et de comparer correctement les versions et les plages de versions. Souvent, si vous devez comparer des versions, vous comparez simplement des chaînes. Disons donc que la version "1.5.3" sera supérieure à la version "1.3.1". Cependant, si vous comparez les chaînes "1.4.2" et "1.12.3", la chaîne "1.4.2" sera par erreur plus grande. Cet utilitaire s'occupe donc d'un tel problème et, en plus, présente la classe VersionRange et autorise les opérations sur les plages de versions. (Voir les méthodes compareVersions dans la classe TextUtils et la classe VersionRange )

Convertisseur Unicode de chaîne


La classe StringUnicodeEncoderDecoder a des méthodes qui peuvent convertir une chaîne (dans n'importe quelle langue) en une séquence de caractères Unicode et vice versa. Par exemple, une chaîne "Hello World" sera convertie en

"\ u0048 \ u0065 \ u006c \ u006c \ u006f \ u0020 \ u0057 \ u006f \ u0072 \ u006c \ u0064"

et peut être restauré en arrière.

Gestion du cycle de vie (usines auto-instanciables)


Cette fonctionnalité est un package qui contient une petite infrastructure qui simplifie et automatise le travail avec des usines qui fournissent des implémentations concrètes d'une interface. Le package contient seulement 2 classes: BaseEntityFactory et BaseEntity . En bref, ce que fait cette infrastructure, c'est que si vous créez une fabrique qui étend BaseEntityFactory et une interface avec toutes ses implémentations concrètes étendant BaseEntity, chacune de vos instances de classe de classe d'implémentation concrète sera automatiquement insérée dans votre fabrique. Vous n'aurez pas à vous soucier de savoir comment et quand remplir votre usine. L'infrastructure le fera pour vous lorsque le constructeur de votre classe d'implémentation concrète sera invoqué. Donc, tout ce que vous aurez à faire est de créer un nombre quelconque de classes d'implémentation concrètes et de vous assurer que pour chaque constructeur est invoqué. Après cela, vous pouvez utiliser votre usine pour obtenir n'importe laquelle de vos classes d'implémentation concrètes n'importe où dans votre code. Ceci est une courte explication. Il y a quelques détails supplémentaires mais pas tant que ça. Pour une description détaillée de ce package, reportez-vous à la description de l'API Javadoc du package com.mgnt.lifecycle.management . De plus, le code source contient le package com.mgnt.lifecycle.management.example qui contient un exemple de code bien commenté et détaillé sur la façon d'utiliser cette fonctionnalité.

Quant à l'utilisation pratique, je l'ai trouvée très utile pour le framework Spring. N'oubliez pas que Spring instancie tous ses beans définis lors de son initialisation. Donc, dans le contexte de Spring, si nous déclarons simplement nos implémentations concrètes en tant que beans Spring, Spring les instancierait pour nous, initialisant ainsi automatiquement leur usine. Cela pourrait être très pratique. Imaginez que vous ayez un bean qui possède une propriété du type d'interface définie par l'utilisateur qui a plusieurs implémentations, mais quelle implémentation réelle serait nécessaire est déterminée lors de l'exécution. Ainsi, à ce moment-là, vous pouvez utiliser la méthode getInstance (java.lang.String) de votre usine pour accéder à l'implémentation requise. Cela vous permettra de ne pas injecter TOUTES vos instanciations concrètes dans votre bean et vous n'aurez pas à utiliser Spring Bean Factory pour accéder à un bean défini par Spring car cela violerait la non-intrusion de Spring (ce qui signifie que vous pouvez écrire des composants qui ne dépendent pas de Printemps). De plus, si, à un stade ultérieur, vous devrez ajouter des implémentations plus concrètes, tout ce que vous aurez à faire est d'ajouter vos classes d'implémentation à votre code et de les déclarer comme des beans Spring. Le reste se fera d'ici le printemps et cette infrastructure!

Utilitaires de fichier


Cet utilitaire permet de lire un fichier sous forme de chaîne avec ou sans spécifier de jeu de caractères ou simplement de le lire sous forme de tableau d'octets. Cet utilitaire utilise le package nio et les tampons pour des performances plus rapides. La taille de fichier maximale pour cet utilitaire est de 2G.

Utilisation du temps


Il s'agit simplement d'une méthode simple qui offre les mêmes fonctionnalités que Thread.sleep () mais elle est silencieuse. C'est à dire qu'il "avale" IterruptedException. En outre, il faut 2 arguments: le temps de sommeil et l'unité de mesure. Donc au lieu de

 try { Thread.sleep(2000); } catch (InterruptedException ie) { } 

Vous pouvez simplement écrire:

 TimeUtils.sleepFor(2, TimeUnit.SECONDS); 

Je pensais que c'était mignon

C'est donc ça. N'hésitez pas à télécharger cette bibliothèque. Il est livré avec une licence MIT - l'une des licences les plus permissives que je connaisse. Le code source, Javadoc et la version binaire sont disponibles sur le lien ci-dessus. Le code a été compilé par JDK 8 mais n'a aucune fonctionnalité de la version 8. Cela devrait fonctionner avec java 7, je pense que cela fonctionnera avec java 6 et même 5, mais je ne l'ai pas testé avec ces versions. N'hésitez pas à l'utiliser comme bon vous semble, parlez-en aux autres si vous l'aimez et n'hésitez pas à m'envoyer une note à michael_gantman@yahoo.com si vous avez des commentaires.

Source: https://habr.com/ru/post/fr480268/


All Articles