注释
此内容当前引用 Visual Studio 中诊断的旧实现中的内容。 内容将在近期内更新,以涵盖 Visual Studio Code 中的新 Power Query SDK。
此多部分教程介绍如何为 Power Query 创建新的数据源扩展。 本教程旨在按顺序完成 — 每个课程都基于在上一课中创建的连接器上构建,以增量方式向连接器添加新功能。
在本课中,你将:
- 了解 Diagnostics.Trace 函数
- 使用诊断帮助程序函数添加跟踪信息以帮助调试连接器
启用诊断
Power Query 用户可以通过选中“选项”下的复选框来启用跟踪日志记录 |诊断。
启用后,任何后续查询都会导致 M 引擎向位于固定用户目录中的日志文件发出跟踪信息。
从 Power Query SDK 中运行 M 查询时,会在项目级别启用跟踪。 在项目属性页上,有三个与跟踪相关的设置:
清除日志:设置为
true时,运行查询时将重置/清除日志。 建议将此设置保留为true。显示引擎跟踪:此设置控制 M 引擎中内置跟踪的输出。 这些跟踪仅适用于 Power Query 团队的成员,因此通常希望将此设置保留为
false。显示用户跟踪:此设置控制连接器输出的跟踪信息。 你想要将此设置设置为
true.
启用后,日志条目将显示在“日志”选项卡下的“M 查询输出”窗口中。
Diagnostics.Trace
Diagnostics.Trace 函数用于将消息写入 M 引擎的跟踪日志。
Diagnostics.Trace = (traceLevel as number, message as text, value as any, optional delayed as nullable logical as any) => ...
重要
M 是一种具有惰性求值的函数式语言。 使用 Diagnostics.Trace时,请记住,仅当表达式是实际计算结果的一部分时,才会调用函数。 本教程稍后可以找到此行为的示例。
参数 traceLevel 可以是下列值之一(降序):
TraceLevel.CriticalTraceLevel.ErrorTraceLevel.WarningTraceLevel.InformationTraceLevel.Verbose
启用跟踪后,用户可以选择要查看的最大消息级别。 此级别和下面的所有跟踪消息都输出到日志。 例如,如果用户选择“警告”级别,日志中将显示TraceLevel.Warning、TraceLevel.Error 和 TraceLevel.Critical的跟踪消息。
该 message 参数是跟踪文件的实际文本输出。 除非在文本中显式包含该参数,否则文本不包含 value 该参数。
参数 value 是函数返回的内容。 当参数 delayed 设置为 true零参数函数时, value 该函数返回要计算的实际值。 如果 delayed 设置为 false, value 则为实际值。 在 延迟评估中可以找到此工作原理的示例。
在 TripPin 连接器中使用 Diagnostics.Trace
有关使用 Diagnostics.Trace 以及 delayed 参数影响的实际示例,请更新 TripPin 连接器的 GetSchemaForEntity 函数,以捕获 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);
通过将无效的实体名称传递给 GetEntity 函数,可以在评估期间(出于测试目的)强制出错。 在此处更改 withData 函数中的 TripPinNavTable 行,替换为 [Name]"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;
为项目启用跟踪 ,并运行测试查询。 在 Errors 选项卡上,应会看到引发的错误文本:
此外,在 Log 选项卡上,应会看到相同的消息。 如果对 message 参数 value 使用不同的值,则这些值会有所不同。
另请注意,Action日志消息的字段包含有关您的扩展程序的名称(数据源类型),在此情况下为Engine/Extension/TripPin。 当涉及多个查询和/或启用系统(混合引擎)跟踪时,此字段能够更便捷地找到与您的扩展相关的信息。
延迟评估
作为参数工作原理 delayed 的示例,需要进行一些修改,然后再次运行查询。
首先,将 delayed 值设置为 false,但保持 value 参数不变。
Diagnostics.Trace(TraceLevel.Error, message, () => error message, false);
运行查询时,您会收到错误“无法将函数类型的值转换为数据类型”,而不是您实际遇到的错误。 这种差异是因为调用现在返回一个 function 值,而不是值本身。
接下来,从 value 参数中删除函数:
Diagnostics.Trace(TraceLevel.Error, message, error message, false);
运行查询时,会收到正确的错误,但如果选中 “日志 ”选项卡,则没有任何消息。 这种差异是因为error在调用期间被触发/评估,因此消息实际上从未输出。
了解参数的影响 delayed 后,请务必在继续作之前将连接器重置回工作状态。
Diagnostics.pqm 中的诊断帮助程序函数
此项目中包含的 Diagnostics.pqm 文件包含许多帮助程序函数,可简化跟踪。 如 上一教程所示,可以在项目中包括此文件(记得将生成作设置为 编译),然后将其加载到连接器文件中。 连接器文件的底部现在应类似于以下代码片段。 请随意浏览本模块提供的各种函数,但在此示例中,你只使用 Diagnostics.LogValue 和 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
函数 Diagnostics.LogValue 非常类似 Diagnostics.Trace,可用于输出要计算的值。
Diagnostics.LogValue = (prefix as text, value as any) as any => ...
参数 prefix 被添加到日志消息的开头。 使用此参数可以找出哪个调用输出消息。 该 value 参数是函数返回的内容,还作为 M 值的文本表示形式写入跟踪。 例如,如果 value 与列 table A 和 B 相等,则日志包含等效 #table 表示形式: #table({"A", "B"}, {{"row1 A", "row1 B"}, {"row2 A", row2 B"}})
注释
将 M 值序列化为文本可能是一项昂贵的作。 请注意要输出到追踪日志的值的潜在大小。
注释
大多数 Power Query 环境会将跟踪消息截断为最大长度。
例如,更新 TripPin.Feed 函数以跟踪传递到该函数中的 url 和 schema 参数。
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;
必须在调用GetAllPagesByNextLink时使用新_url值和_schema值。 如果使用了原始函数参数,那么 Diagnostics.LogValue 的调用实际上不会被评估,因此不会有消息被写入到跟踪中。
函数编程很有趣!
运行查询时,现在应在日志中看到新消息。
访问 URL:
架构类型:
将显示schema参数的type序列化版本,而不是在类型值上执行简单Text.FromValue时产生的结果(其结果为“type”)。
Diagnostics.LogFailure (诊断日志失败)
该 Diagnostics.LogFailure 函数可用于封装函数调用,并且仅当函数调用失败(即返回一个 error)时才写入跟踪。
Diagnostics.LogFailure = (text as text, function as function) as any => ...
在内部,Diagnostics.LogFailure 向 function 调用中添加一个 try 运算符。 如果调用失败,则 text 该值将写入跟踪,然后再返回原始 error值。 如果function调用成功,结果会直接返回,不会向跟踪中写入任何内容。 由于 M 错误不包含完整堆栈跟踪(也就是说,通常只看到错误的消息),因此当想要确定错误引发的位置时,此函数非常有用。
作为一个不完善的示例,修改withData函数的TripPinNavTable行以再次故意引发错误:
withData = Table.AddColumn(rename, "Data", each Diagnostics.LogFailure("Error in GetEntity", () => GetEntity(url, "DoesNotExist")), type table),
在跟踪中,你可以找到包含text的结果性错误消息以及原始错误信息。
在继续下一教程之前,请务必将函数重置为工作状态。
结论
本简短(但重要的)课程介绍了如何使用诊断帮助程序函数登录到 Power Query 跟踪文件。 正确使用时,这些函数在调试连接器中的问题非常有用。
注释
作为连接器开发人员,你需要负责确保不会将敏感信息或个人身份信息(PII)记录为诊断日志记录的一部分。 还必须小心,不要输出过多的跟踪信息,因为它可能会对性能产生负面影响。