TripPin, parte 8: adición de diagnósticos
Nota:
Actualmente, este contenido hace referencia al contenido de una implementación heredada para diagnósticos en Visual Studio. El contenido se actualizará en un futuro próximo para cubrir el nuevo SDK de Power Query en Visual Studio Code.
En este tutorial de varias partes se describe la creación de una nueva extensión de origen de datos para Power Query. El tutorial está diseñado para seguirse secuencialmente: cada lección se basa en el conector creado en las lecciones anteriores, agregando incrementalmente nuevas funcionalidades al conector.
En esta lección, aprenderá lo siguiente:
- Más información sobre la función Diagnostics.Trace
- Uso de las funciones auxiliares de diagnóstico para agregar información de seguimiento para ayudar a depurar el conector
Habilitación de diagnósticos
Los usuarios de Power Query pueden habilitar el registro de seguimiento seleccionando la casilla en Opciones | Diagnósticos.
Una vez habilitado, las consultas posteriores harán que el motor de M emita información de seguimiento a los archivos de registro ubicados en un directorio de usuario fijo.
Al ejecutar consultas M desde el SDK de Power Query, el seguimiento se habilita en el nivel de proyecto. En la página de propiedades del proyecto, hay tres valores relacionados con el seguimiento:
- Clear Log (Borrar registro): cuando esta opción se establezca en
true
, el registro se restablecerá o borrará cuando se ejecuten las consultas. Le recomendamos que la mantenga establecida entrue
. - Show Engine Traces (Mostrar seguimientos del motor): esta opción controla la salida de seguimientos integrados del motor de M. Estos seguimientos solo son útiles para los miembros del equipo de Power Query, por lo que normalmente es recomendable mantener esta opción establecida en
false
. - Show User Traces (Mostrar seguimientos de usuario): esta opción controla la información de seguimiento generada por el conector. Es recomendable establecer esta opción en
true
.
Una vez habilitada, empezará a ver las entradas de registro en la ventana M Query Output (Salida de consulta M), en la pestaña Log (Registro).
Diagnostics.Trace
La función Diagnostics.Trace se usa para escribir mensajes en el registro de seguimiento del motor de M.
Diagnostics.Trace = (traceLevel as number, message as text, value as any, optional delayed as nullable logical as any) => ...
Importante
M es un lenguaje funcional con evaluación diferida. Al usar Diagnostics.Trace
, tenga en cuenta que solo se llamará a la función si la expresión de la que forma parte realmente se evalúa. Encontrará ejemplos de esto más adelante en este tutorial.
El parámetro traceLevel
puede ser en uno de los valores siguientes (en orden descendente):
TraceLevel.Critical
TraceLevel.Error
TraceLevel.Warning
TraceLevel.Information
TraceLevel.Verbose
Cuando el seguimiento está habilitado, el usuario puede seleccionar el nivel máximo de mensajes que desea ver. Todos los mensajes de seguimiento de este nivel y de niveles inferiores en se mostrarán en el registro. Por ejemplo, si el usuario selecciona el nivel "Advertencia", los mensajes de seguimiento de TraceLevel.Warning
, TraceLevel.Error
y TraceLevel.Critical
aparecerán en los registros.
El parámetro message
es el texto real que se generará en el archivo de seguimiento. El texto no contendrá el parámetro value
a menos que usted lo incluya explícitamente en el texto.
El parámetro value
es lo que devolverá la función. Cuando el parámetro delayed
se establezca en true
, value
será una función de parámetro cero que devuelve el valor real que se está evaluando. Cuando delayed
se establezca en false
, value
será el valor real. A continuación se muestra un ejemplo de cómo funciona esto.
Uso de diagnósticos. Seguimiento en el conector de TripPin
Para obtener un ejemplo práctico del uso de Diagnostics.Trace y el impacto del parámetro delayed
, actualice la función GetSchemaForEntity
del conector TripPin para ajustar la excepción error
:
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);
Puede forzar un error durante la evaluación (con fines de prueba). Para ello, pase un nombre de entidad no válido a la función GetEntity
. Aquí se cambia la línea withData
de la función TripPinNavTable
, reemplazando [Name]
por "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;
Habilite el seguimiento para el proyecto y ejecute las consultas de prueba. En la pestaña Errors
debería ver el texto del error que ha generado:
Además, en la pestaña Log
, debería ver el mismo mensaje. Si usa valores diferentes para los parámetros message
y value
, estos serían diferentes.
Tenga en cuenta también que el campo Action
del mensaje de registro contiene el nombre (Tipo de origen de datos) de la extensión (en este caso, Engine/Extension/TripPin
). Esto facilita la búsqueda de los mensajes relacionados con la extensión cuando hay varias consultas implicadas o el seguimiento del sistema (motor de mashup) está habilitado.
Evaluación retrasada
Como ejemplo de cómo funciona el parámetro delayed
, deberá llevar a cabo algunas modificaciones y ejecutar las consultas de nuevo.
En primer lugar, establezca el valor delayed
en false
, pero deje el parámetro value
tal como está:
Diagnostics.Trace(TraceLevel.Error, message, () => error message, false);
Al ejecutar la consulta, recibirá un error que indica "We cannot convert a value of type Function to type Type" (No se puede convertir un valor de tipo Función a tipo Tipo) y no el error real que usted ha generado. Esto se debe a que la llamada ahora devuelve un valor function
, en lugar del propio valor.
A continuación, quite la función del parámetro value
:
Diagnostics.Trace(TraceLevel.Error, message, error message, false);
Al ejecutar la consulta, recibirá el error correcto, pero si comprueba la pestaña Log (Registro), no habrá ningún mensaje. Esto se debe a que error
termina generándose o evaluándose durante la llamada a Diagnostics.Trace
, por lo que el mensaje nunca se emite realmente.
Ahora que ya sabe cuál es el impacto del parámetro
delayed
, asegúrese de restablecer el conector a un estado de funcionamiento antes de continuar.
Funciones auxiliares de diagnóstico en Diagnostics.pqm
El archivo Diagnostics.pqm incluido en este proyecto contiene muchas funciones auxiliares que facilitan el seguimiento. Como se muestra en el tutorial anterior, puede incluir este archivo en el proyecto (recuerde establecer la Acción de compilación en Compilar) y, a continuación, cargarlo en el archivo del conector. La parte inferior del archivo del conector ahora debería ser similar al fragmento de código siguiente. No dude en explorar las distintas funciones que proporciona este módulo, pero en este ejemplo, solo usará las funciones Diagnostics.LogValue
y 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 función Diagnostics.LogValue
es muy similar a Diagnostics.Trace
y se puede usar para generar el valor de lo que se está evaluando.
Diagnostics.LogValue = (prefix as text, value as any) as any => ...
El parámetro prefix
se antepone al mensaje de registro. Se usaría para averiguar qué llamada genera el mensaje. El parámetro value
es lo que devolverá la función y también se escribirá en el seguimiento como una representación de texto del valor M. Por ejemplo, si value
es igual a table
con las columnas A y B, el registro contendrá la representación #table
equivalente: #table({"A", "B"}, {{"row1 A", "row1 B"}, {"row2 A", row2 B"}})
Nota:
La serialización de valores M en texto puede ser una operación costosa. Tenga en cuenta el tamaño potencial de los valores que va a generar en el seguimiento.
Nota:
La mayoría de los entornos de Power Query truncarán los mensajes de seguimiento a una longitud máxima.
Por ejemplo, usted actualizará la función TripPin.Feed
para realizar un seguimiento de los argumentos url
y schema
pasados a la función.
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;
Tiene que usar los nuevos valores _url
y _schema
en la llamada a GetAllPagesByNextLink
. Si usó los parámetros de función originales, las llamadas Diagnostics.LogValue
nunca se evaluarían realmente, lo que provocaría que no se escribiese ningún mensaje en el seguimiento. ¡La programación funcional es divertida!
Al ejecutar las consultas, ahora debería ver nuevos mensajes en el registro.
Acceso a la dirección URL:
Tipo de esquema:
Verá la versión serializada del parámetro schema
type
, en lugar de lo que obtendría al llevar a cabo un simple Text.FromValue
en un valor de tipo (lo que da como resultado "type").
Diagnostics.LogFailure
La función Diagnostics.LogFailure
se puede usar para encapsular llamadas de función y solo escribirá en el seguimiento si se produce un error en la llamada de función (es decir, devuelve un error
).
Diagnostics.LogFailure = (text as text, function as function) as any => ...
Internamente, Diagnostics.LogFailure
agrega un operador try
a la llamada function
. Si se produce un error en la llamada, el valor text
se escribe en el seguimiento antes de devolver el original error
. Si la llamada function
se realiza correctamente, el resultado se devuelve sin escribir nada en el seguimiento. Dado que los errores de M no contienen un seguimiento de pila completo (es decir, normalmente solo se ve el mensaje del error), esto puede resultar útil cuando se desea identificar dónde se generó el error.
Como ejemplo (poco adecuado), modifique la línea withData
de la función TripPinNavTable
para forzar un error una vez más:
withData = Table.AddColumn(rename, "Data", each Diagnostics.LogFailure("Error in GetEntity", () => GetEntity(url, "DoesNotExist")), type table),
En el seguimiento, puede encontrar el mensaje de error resultante que contiene el text
y la información del error original.
Asegúrese de restablecer la función a un estado de funcionamiento antes de continuar con el siguiente tutorial.
Conclusión
En esta breve (pero importante) lección se le ha mostrado cómo usar las funciones auxiliares de diagnóstico para iniciar sesión en los archivos de seguimiento de Power Query. Si se usan correctamente, estas funciones son útiles para depurar problemas dentro del conector.
Nota:
Como desarrollador de conectores, debe asegurarse de que registrar información confidencial o de identificación personal (PII) como parte del registro de diagnóstico. También debe tener cuidado de no generar demasiada información de seguimiento, ya que puede tener un impacto negativo en el rendimiento.