Bonjour, je suis Melanie Drake, ingénieure système au sein de l'équipe des opérations de développement JMP. Notre groupe fournit des processus automatisés qui génèrent les exécutables et les installateurs JMP, exécutent des tests automatisés et réalisent de nombreuses autres tâches pour soutenir la R&D de JMP.
Aujourd'hui, je vais vous expliquer comment nous collectons les informations issues des journaux de processus et comment nous utilisons JMP pour identifier les problèmes et surveiller l'état général d'un processus automatisé. Les processus génèrent une grande quantité de données : relevés d'instruments, mesures d'une ligne de production ou journaux d'état. Ces données peuvent être enregistrées au format texte brut ou structuré (XML, JSON ou CSV, par exemple). Toutes ces données offrent de nombreuses possibilités pour détecter et résoudre les problèmes.
Cependant, ces données sont souvent écrites dans de nombreux fichiers distincts, constamment créés et mis à jour. Il peut donc être très difficile de repérer et de suivre les erreurs. Je vais vous parler du flux de tests unitaires JSL nocturnes. Ce processus génère de nombreux fichiers journaux chaque jour. Nous avons constaté qu'il était très difficile de suivre et de résoudre des erreurs spécifiques. Nous étions submergés de données, mais leur exploitation était extrêmement complexe.
Qu'est-ce que le flux de tests unitaires JSL ? Il s'agit d'une suite de tests de régression JSL exécutés quotidiennement avec la version de JMP. Ce flux s'exécute chaque nuit sur toutes les versions de JMP en cours de développement, et ce, sur différentes versions de Windows et de macOS. Les testeurs utilisent cette exécution nocturne pour identifier les erreurs dans JMP afin que les développeurs puissent les corriger rapidement. Si un flux de tests échoue, les résultats correspondants ne sont pas disponibles.
Pendant quelques semaines cet été, nous développions simultanément quatre versions de JMP. Cela impliquait l'exécution de 18 flux de tests chaque nuit, sur différentes versions de JMP et de systèmes d'exploitation. L'exécution d'un flux complet pouvait prendre entre 8 et 12 heures. Nous avons divisé chaque flux de tests Windows en trois flux exécutés en parallèle afin d'accélérer considérablement l'obtention des résultats. Ainsi, notre équipe de test à Pékin peut exploiter ces résultats le jour même.
Au final, nous consultions 36 journaux de console distincts chaque jour. Nous passions un temps considérable à tenter de déterminer l'origine et la date de chaque erreur. La solution pour gérer des ensembles de données aussi disparates consiste à les centraliser dans un seul et même endroit : une table de données JMP, bien sûr.
Une fois dans JMP, vous pouvez visualiser et analyser vos données, et partager vos résultats avec d'autres utilisateurs via JMP Live. Dans notre cas, nous avons collecté nos journaux dans des tables de données JMP. Nous avons utilisé des graphiques pour suivre et résoudre tous nos problèmes, et nous pouvons surveiller en continu l'état du système en publiant sur JMP Live. Nous avons finalement obtenu deux tables de données distinctes, car nos journaux affichaient des résultats différents entre Macintosh et Windows. Bien que certaines erreurs soient communes, beaucoup d'autres étaient spécifiques à un système d'exploitation.
Je vais d'abord décrire le flux de travail général, puis je détaillerai le script et ferai une démonstration de notre processus. La première étape consiste à localiser vos données et à déterminer comment les importer dans JMP. Les fichiers journaux peuvent être enregistrés sur disque ou sur un serveur. Ils sont accessibles via le web, par exemple via une API ou une requête de base de données. Dans notre cas, nous accédons à un fichier texte via l'interface web d'un serveur Jenkins, sur lequel s'exécutent tous nos processus automatisés. Nous avons utilisé une requête HTTP pour obtenir les informations, puis l'outil d'analyse JSON pour les convertir dans un format exploitable.
La deuxième étape consiste à importer vos données dans JMP. Vous pouvez commencer par vos fichiers journaux, auxquels vous pouvez ajouter d'autres métadonnées. Vous pouvez placer l'intégralité de votre journal dans une seule cellule, ou le répartir sur plusieurs cellules, colonnes, voire lignes. Tout dépend de la nature de vos données et de la manière dont vous souhaitez les analyser. Dans notre cas, nous avons un journal par exécution de flux. Nous plaçons donc une exécution de flux par ligne et un journal complet dans une seule cellule. De plus, nous collectons également de nombreuses autres métadonnées.
La troisième étape consiste à analyser votre texte. Vous pouvez utiliser les fonctions d'analyse XML ou JSON pour obtenir les données brutes. Ensuite, vous pouvez utiliser des expressions régulières, la correspondance de modèles JSL ou des fonctions de caractères JSL pour extraire les informations. Vous pouvez également utiliser des colonnes de formules, des colonnes d'indicateurs ou des colonnes à réponses multiples pour organiser ces informations dans des formats utilisables dans vos graphiques.
Dans notre cas, nous avons utilisé la quasi-totalité des méthodes mentionnées. Nous avons utilisé des colonnes de formules pour collecter les informations spécifiques aux colonnes de métadonnées, puis des expressions régulières et des fonctions de caractères JSL pour analyser les journaux. Nous avons également utilisé des colonnes d'indicateurs et de réponses multiples pour collecter des informations et créer des graphiques clairs et précis.
La quatrième étape consiste à explorer et à représenter graphiquement vos données. JMP propose Graph Builder et de nombreuses autres plateformes de création de graphiques. Vous pouvez les utiliser pour identifier des tendances dans vos erreurs, déterminer leurs corrélations et suivre leur évolution dans le temps. Dans notre cas, nous avons largement utilisé Graph Builder. Nous avons créé des cartes thermiques pour visualiser les corrélations. Nous avons utilisé des histogrammes et des nuages de points pour suivre les erreurs en fonction du temps, des versions de JMP et des versions du système d'exploitation. Nous avons également utilisé des histogrammes empilés et des cartes thermiques pour visualiser l'état des flux et les exécutions manquantes au fil du temps. Je vous présenterai quelques exemples plus tard.
Enfin, à l'étape cinq, vous voudrez partager vos graphiques avec vos collègues. Vous pouvez présenter des résultats spécifiques à des publics ciblés. Le partage favorise la visibilité, la transparence et le travail d'équipe. Vous pouvez également masquer les données privées, personnelles ou confidentielles. Dans notre cas, nous publions un sous-ensemble des données sur un serveur JMP Live interne. Nous ne publions que les données nécessaires à la création des graphiques. Une fois publiés, ces graphiques facilitent grandement les discussions en réunion et permettent de suivre aisément l'état général de notre processus.
JMP 19 propose une nouvelle fonctionnalité appelée « Étiquettes de colonnes ». Nous les avons trouvées extrêmement utiles pour ce projet. Nous utilisons trois étiquettes de colonnes : une pour étiqueter les horodatages de certaines étapes clés, une pour étiqueter les erreurs détectées et une pour étiqueter les colonnes utilisées dans les graphiques. Je vous montrerai comment elles fonctionnent un peu plus tard.
Pourquoi avons-nous procédé ainsi ? D'abord, cela simplifie considérablement notre code JSL. Nous pouvons faire référence aux colonnes à l'aide d'une étiquette spécifique au lieu de coder en dur chaque nom de colonne. Cela signifie également que nous n'avons plus besoin de modifier les noms de colonnes lorsque nous corrigeons des erreurs, par exemple. Il nous suffit d'étiqueter la nouvelle colonne, et elle est automatiquement prise en compte. Il devient ainsi très facile de filtrer et de publier uniquement les données nécessaires.
Nous allons maintenant passer en revue une démonstration et je vous montrerai notre script JSL. Avant même de commencer, nous exécutons quelques lignes de code pour tout configurer. Nous incluons deux autres scripts contenant des fonctions et des définitions de variables. Nous indiquons le chemin d'accès au dossier où sont enregistrées nos tables principales. Celles-ci contiennent toutes les données collectées jusqu'à présent. Ensuite, nous ouvrons un fichier CSV contenant les informations de configuration.
Notre fichier CSV réel comporte davantage de colonnes, mais celles-ci contiennent des informations internes que j'ai supprimées pour cette présentation. Les informations essentielles pour chaque projet sont le nom de chaque flux de test et le tableau principal spécifique au système d'exploitation, qui regroupe toutes les données collectées jusqu'à présent pour ce système d'exploitation.
Nous devons maintenant importer nos données. Chaque combinaison de version de JMP et de système d'exploitation correspond à un projet Jenkins distinct, avec sa propre page. Chaque exécution de flux de tests est une sous-page de la page principale. Nous allons parcourir ce premier projet, JMP 19 sur Sonoma. Je vais définir le nombre d'itérations à 1. Ensuite, j'importerai le nom de chaque tâche et la table cible dans laquelle nous devons l'intégrer.
Nous commençons par utiliser une requête HTTP pour obtenir le JSON de la page principale, qui contient la liste des URL de chaque exécution de flux. Nous envoyons cette requête à Jenkins, récupérons le JSON et l'intégrons à notre liste de builds. Comme je ne peux pas exécuter ce test en direct ici, je me contente de créer une liste. Vous pouvez constater qu'elle est très longue. Cette liste contient l'identifiant de chaque exécution de flux de test effectuée jusqu'à présent pour JMP 19 sur Macintosh Sonoma.
Mais nous possédons déjà une grande partie de ces données dans la table principale et nous ne voulons pas perdre de temps à lire et traiter des données déjà disponibles. Pour contourner ce problème, nous ouvrons notre table principale. Celle-ci contient tous les résultats Macintosh, et pas seulement ceux de ce projet. Nous obtenons ensuite la liste des identifiants de compilation déjà présents pour ce projet. Autrement dit, les identifiants des lignes de la table principale correspondant à JMP 19 sur Sonoma. Nous transformons ces deux listes d'identifiants de compilation en tableaux associatifs afin de pouvoir soustraire les identifiants actuels de notre nouvelle liste. Grâce à la puissance des opérations mathématiques sur les tableaux associatifs, nous obtenons une liste concise des exécutions non encore traitées. Il sera beaucoup plus simple et rapide de traiter 3 lignes plutôt que 395, pour ensuite en supprimer la plupart.
La deuxième étape consiste à importer ces données dans JMP. Si la liste n'est pas vide, nous utilisons une fonction que nous avons développée pour extraire les données souhaitées de chaque flux de test et les importer dans un tableau. Cette fonction utilise à nouveau l'analyse JSON pour extraire les données de suivi et les ajouter au nouveau tableau, en créant une colonne et une ligne pour chaque flux de test.
Je vais ouvrir un exemple de tableau pour que vous puissiez voir à quoi il ressemble. Vous pouvez constater que nous disposons déjà de certaines métadonnées : la durée de chaque flux, son nom, son identifiant, l’état de la compilation (réussie ou non) et l’horodatage de son début. Plus important encore, nous avons l’URL du fichier journal texte d’où proviendront toutes nos informations. L’étape suivante consiste à ajouter une colonne à ce tableau pour y stocker le contenu du fichier journal. Nous utilisons ensuite la fonction « Charger un fichier texte » pour lire ce contenu depuis l’URL et l’insérer dans le tableau.
La troisième étape consiste à analyser les métadonnées et les journaux de la console pour ces lignes. Nous ajoutons de nouvelles colonnes dérivées. Par exemple, nous convertissons la durée en un temps d'exécution en minutes, plus facile à interpréter. Nous ajoutons également une colonne de date contenant uniquement la date, sans l'horodatage. Cela simplifie considérablement la création de certains graphiques. Enfin, nous ajoutons une colonne indiquant le jour de la semaine. Cette information est également utilisée dans certains de nos graphiques.
L'étape suivante consiste à préparer l'analyse du journal. Nous ajoutons des colonnes pour collecter les heures de début de certaines étapes clés. Nous définissons des colonnes de début différentes pour Windows et macOS, et lorsque nous ajoutons ces colonnes, nous les étiquetons comme « débuts ». Vous pouvez voir ici ces étiquettes vertes indiquant que toutes ces colonnes sont étiquetées de la même manière. Elles sont visibles ci-dessous.
La colonne suivante que nous ajoutons correspond à la dernière opération lancée. Si le flux de test s'interrompt en raison d'une erreur, nous pouvons récupérer la dernière étape réussie. Il s'agira de la dernière colonne comportant une étiquette « starts » pour cette ligne et un horodatage. Si le processus perd sa connexion à la machine virtuelle ou au serveur, des erreurs JavaScript seront consignées dans le journal. Nous les enregistrons systématiquement.
Enfin, nous ajoutons une colonne à réponses multiples pour recueillir les informations d'erreur. J'y reviendrai plus tard. L'étape suivante consiste à analyser le journal. Nous utilisons une boucle pour parcourir l'intégralité de la console pour chaque ligne, extraire les informations souhaitées et les ajouter aux nouvelles colonnes correspondantes. Le journal de la console est contenu dans une cellule par ligne. Nous le convertissons en une liste de chaînes de caractères, chaque ligne du journal étant une chaîne.
Nous parcourons ensuite cette liste une seule fois et comparons chaque ligne aux éléments spécifiques recherchés : heures de début, erreurs, etc. Cette méthode est bien plus efficace que d'analyser le journal pour chaque élément à extraire. Nous recherchons en premier lieu une erreur JavaScript. Si nous en trouvons une, nous la récupérons et l'ajoutons au tableau de données, puis nous passons au journal de la console de la ligne suivante. Une fois la tâche interrompue de cette manière, il n'y aura plus d'informations à récupérer.
Dans nos projets Jenkins, nous recherchons des erreurs spécifiques. Ces recherches, appelées « recherches de texte », sont consignées à la fin du journal. Dès la première occurrence d'une recherche de texte, nous arrêtons la boucle jusqu'à la fin du journal. Nous transmettons ensuite ces données à une fonction que je vous présenterai dans un instant.
Hormis ces deux éléments, nous recherchons les étapes clés et insérons l'horodatage correspondant dans le tableau. Enfin, à la fin de la boucle, nous collectons les identifiants de texte. Chaque identifiant trouvé est ajouté au tableau sous forme de colonne indicatrice : 0 si l'erreur est absente, 1 si elle est présente.
Cela laisse des données manquantes là où nous n'avons pas cherché cette erreur. Par exemple, s'il s'agit d'une nouvelle erreur que nous n'avons pas encore recherchée. Chaque colonne de recherche de texte est étiquetée comme telle. Une fois ces colonnes indicatrices remplies, nous récupérons le nom de chaque colonne étiquetée comme telle et contenant la valeur « 1 » pour cette ligne, puis nous l'ajoutons à la colonne de réponses multiples, qui servira ultérieurement à la création des graphiques.
Enfin, nous intégrons le dernier élément au tableau pour cette ligne. Les boucles pour les lignes suivantes compareront les champs de recherche de texte trouvés aux colonnes existantes et n'ajouteront que ceux qui manquent encore. Voici un exemple de ce à quoi ressemble ce tableau après l'exécution de toutes ces opérations. Nous conservons toutes les métadonnées collectées initialement, le texte du journal et toutes nos données dérivées. Désormais, toutes nos colonnes de début contiennent les horodatages, ce qui nous permet de savoir précisément quand chaque élément a commencé.
Notre dernière opération lancée a collecté le dernier élément avec succès. Nous n'avons rencontré aucune erreur de déconnexion Java, mais si cela avait été le cas, elles auraient été signalées.
Enfin, nous avons ajouté toutes nos colonnes de recherche de texte. Vous remarquerez qu'elles sont marquées en rouge. Toutes ces analyses ont été concluantes, mais j'ai inclus quelques erreurs détectées afin de vous montrer à quoi elles ressemblent dans notre colonne de réponses multiples. Vous pouvez constater que celle-ci a présenté deux échecs et que les réponses sont délimitées par des points-virgules. Celle-ci n'en a présenté qu'un seul.
La dernière étape consiste à ajouter toutes ces nouvelles informations à notre table de données principale. Il s'agit d'une simple concaténation. Nous allions ajouter nos trois nouvelles lignes à notre table. L'étape finale est l'enregistrement de cette table. Nous la compressons lors de l'enregistrement, car ces journaux peuvent parfois contenir des centaines, voire des milliers de lignes. Avec 1 333 lignes, cela représente une quantité importante de données, et ces tables peuvent devenir très volumineuses. C'est le cœur du processus et ce qui nous a pris le plus de temps à développer. Déterminer précisément les informations dont nous avions besoin a été un processus itératif.
La dernière étape consiste à explorer et à représenter graphiquement vos données. Nous avons enregistré de nombreux graphiques que nous avons conçus pour nous aider à diagnostiquer les problèmes. Je vais vous en montrer quelques-uns. Celui-ci illustre la durée d'exécution d'un flux en fonction de la date et du système d'exploitation.
Les flux de courte durée s'interrompent généralement rapidement. Nous obtenons très rarement des résultats avec ces flux. Un flux qui a duré très longtemps a probablement rencontré un problème et finira sans doute par s'interrompre. Ce sont autant de problèmes que nous devons examiner de plus près. Ce flux est très stable, ce qui est toujours encourageant.
Un autre graphique utile est celui-ci, qui montre les corrélations entre les erreurs JavaScript et la dernière opération lancée avec succès. Il peut s'avérer très utile pour diagnostiquer les problèmes. Enfin, mon préféré est sans doute cette carte thermique qui indique l'état des compilations manquantes.
Vous pouvez constater immédiatement que nous exécutons ces tests cinq jours par semaine. Ils ne sont pas effectués le week-end. Vous remarquez ici de nombreuses exécutions manquantes, correspondant à des tests que nous n'avons tout simplement pas lancés. Ces tests ont été exécutés, mais avec des erreurs. Tous les tests validés (en vert) se sont déroulés sans problème. Voici les trois lignes que nous venons d'ajouter à ce tableau.
La cinquième étape consiste à partager vos graphiques. Comme ils sont déjà publiés dans JMP Live, il suffit de mettre à jour le tableau et les graphiques dans JMP Live. Nous créons une connexion à notre instance JMP Live. Celle-ci se trouve dans Fichier > Publier > Gérer les connexions. Nous ouvrons le tableau de données, puis nous exécutons le script de sous-ensemble.
Vous vous demandez peut-être pourquoi nous nous donnons cette peine. Vous remarquerez que notre table principale d'origine comporte 39 colonnes. Notre table de sous-ensembles n'en compte que neuf, et ces neuf colonnes n'incluent pas les volumineux journaux de la console. Cela rend ces tables de sous-ensembles beaucoup plus petites, ce qui améliore les performances de JMP Live. De plus, nous pouvons très facilement ne pas publier de données privées ou confidentielles. Nous ne publions que les données strictement nécessaires aux graphiques que nous utilisons.
Nous envoyons ce sous-ensemble de tableaux et d'autres informations, comme la connexion à JMP Live, à une fonction que nous avons écrite. Cette fonction parcourt chaque graphique du tableau, puis met à jour le sous-ensemble de chaque graphique dans JMP Live avant de passer au tableau suivant, ici, « Windows ». Le processus est ainsi terminé. Chaque jour, nous obtenons de nouveaux résultats.
Voici quelques exemples de graphiques publiés sur JMP Live. Depuis notre tableau de bord, ces graphiques, ainsi que d'autres, nous offrent une vue d'ensemble rapide, nous permettant d'identifier facilement les tendances générales et les points problématiques. Grâce à JMP Live, nous pouvons examiner chaque graphique individuellement et explorer les données en détail. Tous nos graphiques sont publiés avec des filtres de données locaux. Cela nous permet de n'analyser que certains flux de test sur une période donnée. Par exemple, uniquement les flux de test JMP 20 des dernières semaines.
Au final, quel est notre résultat ? Nous avons automatisé l’analyse de nos données. Il nous suffit de consulter les graphiques pour suivre l’évolution de la situation. Ils se mettent à jour automatiquement. Plus besoin de gérer les erreurs individuellement. La publication est automatique. Grâce à la préconfiguration, le processus fonctionne sans problème au quotidien. En analysant nos données, nous avons déterminé les éléments à suivre. Nous avons modifié les informations affichées dans nos journaux de console, notamment en ajoutant les heures de début des étapes clés. Nous avons choisi les graphiques les plus pertinents pour illustrer les problèmes à résoudre.
Une fois ce script finalisé et opérationnel, ce fut une victoire éclatante. Tous nos problèmes étaient résolus et nos graphiques, désormais bien plus stables, sont beaucoup moins impressionnants, puisque les flux de test s'exécutent généralement avec succès. Merci.