TripPin, partie 8 - Ajout de diagnostics
Remarque
Ce contenu fait actuellement référence à celui d’une implémentation héritée pour les diagnostics dans Visual Studio. Le contenu sera mis à jour dans un futur proche pour couvrir le nouveau Kit de développement logiciel (SDK) Power Query dans Visual Studio Code.
Ce tutoriel en plusieurs parties traite de la création d’une extension de source de données pour Power Query. Le tutoriel est destiné à être utilisé de manière séquentielle : chaque leçon s’appuie sur le connecteur créé dans les leçons précédentes, ajoutant de nouvelles fonctionnalités de manière incrémentielle.
Dans cette leçon, vous allez :
- Découvrir la fonction Diagnostics.Trace
- Utiliser les fonctions d’assistance Diagnostics pour ajouter des informations de trace afin de faciliter le débogage de votre connecteur
Activation des diagnostics
Les utilisateurs de Power Query peuvent activer la journalisation des traces en cochant la case sous Options | Diagnostic.
Une fois l’option activée, le moteur M émet des informations de trace dans les fichiers journaux situés dans un répertoire utilisateur fixe après chaque requête.
Lors de l’exécution de requêtes M à partir du SDK Power Query, le traçage est activé au niveau du projet. La page des propriétés du projet compte trois paramètres liés au traçage :
- Effacer le journal : si cette option est définie sur
true
, le journal est réinitialisé/effacé quand vous exécutez vos requêtes. Nous vous recommandons de conserver la valeurtrue
. - Afficher les traces du moteur : ce paramètre contrôle la sortie des traces intégrées du moteur M. Ces traces n’étant utiles qu’aux membres de l’équipe Power Query, vous pouvez généralement conserver la valeur
false
. - Afficher les traces utilisateur : ce paramètre contrôle la sortie des informations de trace par votre connecteur. Définissez ce paramètre sur
true
.
Une fois l’option activée, des entrées de journal s’affichent dans la fenêtre Sortie de la requête M, sous l’onglet Journal.
Diagnostics.Trace
La fonction Diagnostics.Trace permet d’écrire des messages dans le journal des traces du moteur M.
Diagnostics.Trace = (traceLevel as number, message as text, value as any, optional delayed as nullable logical as any) => ...
Important
M est un langage fonctionnel à évaluation différée. Quand vous utilisez Diagnostics.Trace
, gardez à l’esprit que la fonction n’est appelée que si l’expression dont elle fait partie est réellement évaluée. Vous trouverez des exemples illustrant ceci plus loin dans ce tutoriel.
Le paramètre traceLevel
peut prendre l’une des valeurs suivantes (dans l’ordre décroissant) :
TraceLevel.Critical
TraceLevel.Error
TraceLevel.Warning
TraceLevel.Information
TraceLevel.Verbose
Lorsque le traçage est activé, l’utilisateur peut sélectionner le niveau maximum de messages qu’il souhaite voir. Tous les messages de trace de ce niveau et des niveaux inférieurs sont consignés dans le journal. Par exemple, si l’utilisateur sélectionne le niveau « Avertissement », les messages de trace de TraceLevel.Warning
, TraceLevel.Error
et TraceLevel.Critical
apparaissent dans les journaux.
Le paramètre message
est le texte réel qui est généré dans le fichier de trace. Notez que le texte ne contient pas le paramètre value
, à moins que vous ne l’incluiez explicitement dans le texte.
Le paramètre value
est ce que la fonction retourne. Quand le paramètre delayed
est défini sur true
, value
est une fonction sans aucun paramètre qui retourne la valeur réelle que vous évaluez. Quand delayed
est défini sur false
, value
est la valeur réelle. Un exemple illustrant le fonctionnement de ceci est présenté ci-dessous.
Utilisation de Diagnostics. Trace dans le connecteur TripPin
Pour obtenir un exemple pratique d’utilisation de Diagnostics.Trace et comprendre l’impact du delayed
paramètre, mettez à jour la fonction GetSchemaForEntity
du connecteur error
TripPin pour envelopper l’exception :
GetSchemaForEntity = (entity as text) as type =>
try
SchemaTable{[Entity=entity]}[Type]
otherwise
let
message = Text.Format("Couldn't find entity: '#{0}'", {entity})
in
Diagnostics.Trace(TraceLevel.Error, message, () => error message, true);
Vous pouvez forcer une erreur durant l’évaluation (à des fins de test) en passant un nom d’entité non valide à la fonction GetEntity
. Ici, vous modifiez la ligne withData
dans la fonction TripPinNavTable
, en remplaçant [Name]
par "DoesNotExist"
.
TripPinNavTable = (url as text) as table =>
let
// Use our schema table as the source of top level items in the navigation tree
entities = Table.SelectColumns(SchemaTable, {"Entity"}),
rename = Table.RenameColumns(entities, {{"Entity", "Name"}}),
// Add Data as a calculated column
withData = Table.AddColumn(rename, "Data", each GetEntity(url, "DoesNotExist"), type table),
// Add ItemKind and ItemName as fixed text values
withItemKind = Table.AddColumn(withData, "ItemKind", each "Table", type text),
withItemName = Table.AddColumn(withItemKind, "ItemName", each "Table", type text),
// Indicate that the node should not be expandable
withIsLeaf = Table.AddColumn(withItemName, "IsLeaf", each true, type logical),
// Generate the nav table
navTable = Table.ToNavigationTable(withIsLeaf, {"Name"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
in
navTable;
Activez le traçage pour votre projet et exécutez vos requêtes de test. Sous l’onglet Errors
, vous devriez voir le texte de l’erreur que vous avez déclenchée :
Sous l’onglet Log
, vous devriez voir le même message. Si vous utilisez des valeurs différentes pour les paramètres message
et value
, ces derniers seront différents.
Notez également que le champ Action
du message de journal contient le nom (Genre de source de données) de votre extension (dans ce cas, Engine/Extension/TripPin
). Cela facilite la recherche des messages liés à votre extension quand plusieurs requêtes sont impliquées et/ou le traçage du système (moteur de mashup) est activé.
Évaluation différée
Pour illustrer le fonctionnement du paramètre delayed
, vous allez apporter quelques modifications et réexécuter les requêtes.
Commencez par définir la valeur de delayed
sur false
, mais gardez le paramètre value
tel quel :
Diagnostics.Trace(TraceLevel.Error, message, () => error message, false);
Lorsque vous exécutez la requête, vous recevez l’erreur « Désolé... Nous n’avons pas pu convertir une valeur de type Fonction en type Type », et non l’erreur réelle que vous avez levée. Cela est dû au fait que l’appel retourne maintenant une valeur function
, et non la valeur elle-même.
Ensuite, supprimez la fonction value
du paramètre :
Diagnostics.Trace(TraceLevel.Error, message, error message, false);
Quand vous exécutez la requête, vous recevez la bonne erreur, mais aucun message ne figure sous l’onglet Journal. Cela est dû au fait que error
finit par être déclenché/évalué pendant l’appel à Diagnostics.Trace
. Le message n’est donc jamais réellement généré.
Maintenant que vous comprenez l’impact du paramètre
delayed
, pensez à remettre votre connecteur dans un état opérationnel avant de continuer.
Fonctions d’assistance de diagnostic dans Diagnostics.pqm
Le fichier Diagnostics.pqm inclus dans ce projet contient un certain nombre de fonctions d’assistance qui facilitent le suivi. Comme indiqué dans le tutoriel précédent, vous pouvez inclure ce fichier dans votre projet (en n’oubliant pas de définir Action de génération de build sur Compiler), puis le charger dans votre fichier de connecteur. La partie inférieure de votre fichier de connecteur doit maintenant ressembler à l’extrait de code ci-dessous. N’hésitez pas à explorer les différentes fonctions fournies par ce module. Toutefois, dans cet exemple, vous n’utiliserez que les fonctions Diagnostics.LogValue
et Diagnostics.LogFailure
.
// Diagnostics module contains multiple functions. We can take the ones we need.
Diagnostics = Extension.LoadFunction("Diagnostics.pqm");
Diagnostics.LogValue = Diagnostics[LogValue];
Diagnostics.LogFailure = Diagnostics[LogFailure];
Diagnostics.LogValue
La fonction Diagnostics.LogValue
ressemble beaucoup à Diagnostics.Trace
et peut être utilisée pour afficher la valeur de ce que vous évaluez.
Diagnostics.LogValue = (prefix as text, value as any) as any => ...
Le paramètre prefix
est ajouté au début du message de journal. Vous pouvez l’utiliser pour déterminer l’appel ayant généré le message. Le paramètre value
est ce que la fonction retourne et est également écrit dans la trace en tant que représentation textuelle de la valeur M. Par exemple, si value
est égal à une table
avec des colonnes A et B, le journal contient la représentation #table
équivalente : #table({"A", "B"}, {{"row1 A", "row1 B"}, {"row2 A", row2 B"}})
Remarque
La sérialisation des valeurs M en texte peut être une opération coûteuse. Tenez compte de la taille potentielle des valeurs que vous générez dans la trace.
Remarque
La plupart des environnements Power Query tronquent les messages de trace selon une longueur maximale.
En guise d’exemple, vous allez mettre à jour la fonction TripPin.Feed
pour effectuer le traçage des arguments url
et schema
passés à la fonction.
TripPin.Feed = (url as text, optional schema as type) as table =>
let
_url = Diagnostics.LogValue("Accessing url", url),
_schema = Diagnostics.LogValue("Schema type", schema),
//result = GetAllPagesByNextLink(url, schema)
result = GetAllPagesByNextLink(_url, _schema)
in
result;
Vous devez utiliser les nouvelles valeurs _url
et _schema
dans l’appel à GetAllPagesByNextLink
. Si vous utilisez les paramètres de fonction d’origine, les appels Diagnostics.LogValue
ne sont jamais réellement évalués et aucun message n’est écrit dans la trace. La programmation fonctionnelle, c’est amusant !
Quand vous exécutez vos requêtes, vous devriez maintenant voir de nouveaux messages dans le journal.
Accès à l’url :
Type de schéma :
La version sérialisée du paramètre schema
type
est affichée. Le résultat obtenu est différent si vous faites un simple Text.FromValue
sur une valeur de type (ce qui donne « type »).
Diagnostics.LogFailure
La fonction Diagnostics.LogFailure
peut être utilisée pour wrapper des appels de fonction et n’écrit dans la trace que si l’appel de fonction échoue (autrement dit, s’il retourne error
).
Diagnostics.LogFailure = (text as text, function as function) as any => ...
En interne, Diagnostics.LogFailure
ajoute un opérateur try
à l’appel function
. Si l’appel échoue, la valeur text
est écrite dans la trace avant de retourner l’origine error
. Si l'appel function
réussit, le résultat est retourné sans rien écrire dans la trace. Étant donné que les erreurs M ne contiennent pas une trace de pile complète (autrement dit, vous ne voyez généralement que le message de l’erreur), cela peut être utile si vous souhaitez identifier où l’erreur a réellement été levée.
À titre d’exemple (médiocre), modifiez la ligne withData
de la fonction TripPinNavTable
pour forcer à nouveau une erreur :
withData = Table.AddColumn(rename, "Data", each Diagnostics.LogFailure("Error in GetEntity", () => GetEntity(url, "DoesNotExist")), type table),
Dans la trace, vous pouvez trouver le message d’erreur résultant contenant votre text
et les informations d’erreur d’origine.
Pensez à remettre votre fonction dans un état opérationnel avant de passer au tutoriel suivant.
Conclusion
Cette brève leçon (mais importante) vous a montré comment utiliser les fonctions d’assistance de diagnostic pour consigner des informations dans les fichiers de trace Power Query. Utilisées correctement, ces fonctions peuvent être utiles pour déboguer des problèmes au sein de votre connecteur.
Remarque
En tant que développeur de connecteurs, il vous appartient de vérifier que vous ne consignez pas d’informations sensibles ou d’identification personnelle (PII) dans le cadre de votre journalisation de diagnostics. Vous devez également veiller à ne pas générer trop d’informations de trace, car cela peut avoir un impact négatif sur les performances.