TripPin Teil 8 - Hinzufügen von Diagnosen
Hinweis
Dieser Inhalt verweist derzeit auf Inhalte aus einer Vorversion-Implementierung für Diagnose in Visual Studio. Der Inhalt wird in Naher Zukunft aktualisiert, um das neue Power Query SDK in Visual Studio Code abzudecken.
Dieser mehrteilige Lehrgang behandelt die Erstellung einer neuen Datenquellenerweiterung für Power Query. Der Lehrgang sollte nacheinander durchgeführt werden - jede Lektion baut auf dem in den vorangegangenen Lektionen erstellten Connector auf und fügt dem Connector schrittweise neue Funktionen hinzu.
In dieser Lektion lernen Sie Folgendes:
- Erfahren Sie mehr über die Funktion Diagnostics.Trace
- Verwenden Sie die Diagnose-Hilfsfunktionen, um Trace-Informationen zur Fehlersuche in Ihrem Connector hinzuzufügen
Diagnose aktivieren
Power Query-Benutzer können die Trace-Protokollierung aktivieren, indem sie das Kontrollkästchen unter Options | Diagnosticsaktivieren.
Sobald diese Option aktiviert ist, gibt die M-Engine bei allen nachfolgenden Abfragen Trace-Informationen in Protokolldateien aus, die sich in einem festen Benutzerverzeichnis befinden.
Bei der Ausführung von M-Abfragen aus dem Power Query SDK ist die Ablaufverfolgung auf Projektebene aktiviert. Auf der Seite mit den Projekteigenschaften gibt es drei Einstellungen für die Ablaufverfolgung:
- Protokoll löschen- wenn dies auf
true
eingestellt ist, wird das Protokoll zurückgesetzt/gelöscht, wenn Sie Ihre Abfragen ausführen. Wir empfehlen, diese Einstellung auftrue
zu belassen. - Show Engine Traces- diese Einstellung steuert die Ausgabe der integrierten Traces der M-Engine. Diese Abhängigkeiten sind nur für Mitglieder des Power Query-Teams nützlich, daher sollten Sie diese Einstellung auf
false
belassen. - Show User Traces- diese Einstellung steuert die Ausgabe von Trace-Informationen durch Ihren Connector. Sie sollten dies auf
true
einstellen.
Sobald diese Funktion aktiviert ist, werden im Fenster M Query Output auf der Registerkarte Log Protokolleinträge angezeigt.
Diagnostics.Trace
Die Funktion Diagnostics.Trace wird verwendet, um Meldungen in das Trace-Protokoll der M-Engine zu schreiben.
Diagnostics.Trace = (traceLevel as number, message as text, value as any, optional delayed as nullable logical as any) => ...
Wichtig
M ist eine funktionale Sprache mit verzögerter Auswertung. Bei der Verwendung von Diagnostics.Trace
ist zu beachten, dass die Funktion nur aufgerufen wird, wenn der Ausdruck, zu dem sie gehört, tatsächlich ausgewertet wird. Beispiele dafür finden Sie später in diesem Lernprogramm.
Der Parameter traceLevel
kann einen der folgenden Werte annehmen (in absteigender Reihenfolge):
TraceLevel.Critical
TraceLevel.Error
TraceLevel.Warning
TraceLevel.Information
TraceLevel.Verbose
Wenn die Verfolgung aktiviert ist, kann der Benutzer die maximale Anzahl der Meldungen auswählen, die er sehen möchte. Alle Trace-Meldungen dieser Stufe und darunter werden in das Protokoll ausgegeben. Wenn der Benutzer z. B. die Ebene „Warning“ wählt, würden Spuren der Meldungen von TraceLevel.Warning
, TraceLevel.Error
und TraceLevel.Critical
in den Protokollen erscheinen.
Der Parameter message
ist der eigentliche Text, der in der Trace-Datei ausgegeben wird. Der Text enthält den Parameter value
nur dann, wenn Sie ihn ausdrücklich in den Text aufnehmen.
Der Parameter value
gibt an, was die Funktion zurückgeben wird. Wenn der Parameter delayed
auf true
gesetzt ist, ist value
eine Funktion mit null Parametern, die den aktuellen Wert zurückgibt, den Sie auswerten. Wenn delayed
auf false
eingestellt ist, ist value
der aktuelle Wert. Ein Beispiel dafür, wie dies funktioniert, finden Sie nachstehend.
Verwenden von Diagnosen. Ablaufverfolgung im TripPin-Konnektor
Um ein praktisches Beispiel für die Verwendung von Diagnostics.Trace und die Auswirkungen des Parameters delayed
zu erhalten, aktualisieren Sie die Funktion GetSchemaForEntity
des TripPin-Connectors, um die Ausnahme error
einzuschließen:
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);
Sie können während der Auswertung einen Fehler erzwingen (zu Testzwecken!), indem Sie der Funktion GetEntity
einen ungültigen Entitätsnamen übergeben. Hier ändern Sie die Zeile withData
in der Funktion TripPinNavTable
und ersetzen [Name]
durch "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;
Aktivieren Sie die Ablaufverfolgung für Ihr Projekt, und führen Sie Ihre Testabfragen aus. Auf der Registerkarte Errors
sollten Sie den Text des Fehlers sehen, den Sie ausgelöst haben:
Auch auf der Registerkarte Log
sollten Sie die gleiche Meldung sehen. Wenn Sie unterschiedliche Werte für die Parameter message
und value
verwenden, würden diese unterschiedlich ausfallen.
Beachten Sie auch, dass das Feld Action
der Protokollmeldung den Namen (Data Source Kind) Ihrer Erweiterung enthält (in diesem Fall Engine/Extension/TripPin
). Dies erleichtert das Auffinden von Meldungen, die sich auf Ihre Erweiterung beziehen, wenn mehrere Abfragen beteiligt sind und/oder die Systemverfolgung (Mashup-Engine) aktiviert ist.
Verspätete Bewertung
Um zu zeigen, wie der Parameter delayed
funktioniert, nehmen Sie einige Änderungen vor und führen die Abfragen erneut aus.
Setzen Sie zunächst den Wert delayed
auf false
, lassen Sie aber den Parameter value
unverändert:
Diagnostics.Trace(TraceLevel.Error, message, () => error message, false);
Wenn Sie die Abfrage ausführen, erhalten Sie die Fehlermeldung "Wir können einen Wert des Typs Funktion nicht in den Typ Typ konvertieren", und nicht den eigentlichen Fehler, den Sie ausgelöst haben. Dies liegt daran, dass der Aufruf nun einen function
Wert zurückgibt und nicht mehr den Wert selbst.
Als nächstes entfernen Sie die Funktion aus dem Parameter value
:
Diagnostics.Trace(TraceLevel.Error, message, error message, false);
Wenn Sie die Abfrage ausführen, erhalten Sie die korrekte Fehlermeldung, aber wenn Sie die Registerkarte Log überprüfen, werden keine Meldungen angezeigt. Der Grund dafür ist, dass error
ends up being ausgelöst/ausgewertet wird während des Aufrufs an Diagnostics.Trace
, sodass die Nachricht nie tatsächlich ausgegeben wird.
Da Sie nun wissen, wie sich der Parameter
delayed
auswirkt, stellen Sie sicher, dass Sie Ihren Connector in einen funktionierenden Zustand zurücksetzen, bevor Sie fortfahren.
Diagnose-Hilfsfunktionen in Diagnostics.pqm
Die in diesem Projekt enthaltene Datei Diagnostics.pqm enthält viele Hilfsfunktionen, die das Tracing erleichtern. Wie in der vorangegangenen Anleitung gezeigt, können Sie diese Datei in Ihr Projekt einbinden (denken Sie daran, die Build-Aktion auf Kompilierenzu setzen) und sie dann in Ihre Connector-Datei laden. Der untere Teil Ihrer Connector-Datei sollte nun in etwa so aussehen wie der folgende Codeausschnitt. Sie können die verschiedenen Funktionen, die dieses Modul bietet, gerne ausprobieren, aber in diesem Beispiel werden Sie nur die Funktionen Diagnostics.LogValue
und Diagnostics.LogFailure
verwenden.
// 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
Die Funktion Diagnostics.LogValue
ist der Funktion Diagnostics.Trace
sehr ähnlich und kann verwendet werden, um den Wert dessen auszugeben, was Sie gerade auswerten.
Diagnostics.LogValue = (prefix as text, value as any) as any => ...
Der Parameter prefix
wird der Protokollmeldung vorangestellt. Auf diese Weise können Sie herausfinden, welcher Aufruf die Nachricht ausgibt. Der Parameter value
ist das, was die Funktion zurückgibt, und wird auch als Textdarstellung des M-Werts in die Ablaufverfolgung geschrieben. Wenn zum Beispiel value
einer table
mit den Spalten A und B entspricht, enthält das Protokoll die entsprechende Darstellung #table
: #table({"A", "B"}, {{"row1 A", "row1 B"}, {"row2 A", row2 B"}})
Hinweis
Die Serialisierung von M-Werten in Text kann ein kostspieliger Vorgang sein. Achten Sie auf die mögliche Größe der Werte, die Sie in die Kurve ausgeben.
Hinweis
In den meisten Power Query-Umgebungen werden Trace-Meldungen auf eine maximale Länge gekürzt.
Als Beispiel werden Sie die Funktion TripPin.Feed
aktualisieren, um die an die Funktion übergebenen Argumente url
und schema
zu verfolgen.
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;
Beachten Sie, dass Sie die neuen Werte _url
und _schema
im Aufruf von GetAllPagesByNextLink
verwenden müssen. Wenn Sie die ursprünglichen Funktionsparameter verwenden würden, würden die Diagnostics.LogValue
-Aufrufe nie ausgewertet werden, was dazu führt, dass keine Meldungen in die Ablaufverfolgung geschrieben werden. Funktionale Programmierung macht Spaß!
Wenn Sie Ihre Abfragen ausführen, sollten Sie nun neue Meldungen im Protokoll sehen.
Zugriff auf die Url:
Schema-Typ:
Beachten Sie, dass Sie die serialisierte Version des schema
-Parameters type
sehen und nicht das, was Sie erhalten würden, wenn Sie eine einfache Text.FromValue
auf einen Typwert anwenden (was zu "type" führt).
Diagnostics.LogFailure
Die Funktion Diagnostics.LogFailure
kann verwendet werden, um Funktionsaufrufe zu verpacken, und wird nur dann in die Ablaufverfolgung geschrieben, wenn der Funktionsaufruf fehlschlägt (d.h. ein error
zurückgibt).
Diagnostics.LogFailure = (text as text, function as function) as any => ...
Intern fügt Diagnostics.LogFailure
einen try
-Operator zum function
-Aufruf hinzu. Wenn der Aufruf fehlschlägt, wird der Wert text
in den Trace geschrieben, bevor der ursprüngliche error
zurückgegeben wird. Wenn der Aufruf von function
erfolgreich ist, wird das Ergebnis zurückgegeben, ohne dass etwas in den Trace geschrieben wird. Da M-Fehler keinen vollständigen Stack-Trace enthalten (d. h. Sie sehen in der Regel nur die Fehlermeldung), kann dies nützlich sein, wenn Sie herausfinden wollen, wo der Fehler aufgetreten ist.
Als (schlechtes) Beispiel ändern Sie die Zeile withData
der TripPinNavTable
-Funktion, um erneut einen Fehler zu erzwingen:
withData = Table.AddColumn(rename, "Data", each Diagnostics.LogFailure("Error in GetEntity", () => GetEntity(url, "DoesNotExist")), type table),
Im Trace finden Sie die resultierende Fehlermeldung, die Ihre text
enthält, sowie die ursprünglichen Fehlerinformationen.
Stellen Sie sicher, dass Sie Ihre Funktion auf einen funktionierenden Zustand zurücksetzen, bevor Sie mit dem nächsten Lernprogramm fortfahren.
Zusammenfassung
Diese kurze (aber wichtige!) Lektion hat Ihnen gezeigt, wie Sie die Diagnose-Hilfsfunktionen nutzen können, um in den Power Query-Trace-Dateien zu protokollieren. Bei richtiger Anwendung sind diese Funktionen nützlich bei der Fehlersuche in Ihrem Connector.
Hinweis
Als Connectorstwickler sind Sie dafür verantwortlich, dass Sie keine sensiblen oder persönlich identifizierbaren Informationen (PII) als Teil Ihrer Diagnoseprotokollierung aufzeichnen. Sie müssen auch darauf achten, nicht zu viele Trace-Informationen auszugeben, da dies negative Auswirkungen auf die Leistung haben kann.