6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Power Query のトレースログ を Power Query でパースしてみた

Last updated at Posted at 2019-04-07

Power Query のトレースログをパースしてみたなど。そのまま眺めても何となく見えてくるのだけど整理された状態で見えたらよいよね。コミュニティイベントでチラ見せしたものを後生大事に塩漬けしててもしょうがないので公開しておこう。修行のお供にでも。

Power BI Desktop に "クエリ診断" 機能が追加されました
Power Query エディターで診断開始から終了、パースされたファイル(JSON)からログなど参照できるようになりました :smile:
image.png

パーサー本体

トレースログ出力先は [Power Query エディター] ⇒ [オプションと設定] ⇒ [診断]
トレース開始は [トレースを有効にする] を ON

解析、リファクタリングなどお好きにどうぞ
let
    Source = Folder.Contents(" <<  >> "),
    FilteredRows = Table.SelectRows(Source, each Text.Lower([Extension]) = ".log"),
    Content = List.Combine(List.Transform(FilteredRows[Content], Lines.FromBinary)),
    TableFromContent = Table.FromColumns({Content}, {"Value"}),
    SplitColumnByDelimiter1 = Table.SplitColumn(
        TableFromContent,
        "Value",
        Splitter.SplitTextByEachDelimiter(
            {":"},
            QuoteStyle.None,
            false
        ),
        {"Value.1", "Value.2"}
    ),
    SplitColumnByDelimiter2 = Table.SplitColumn(
        SplitColumnByDelimiter1,
        "Value.2",
        Splitter.SplitTextByEachDelimiter(
            {":"},
            QuoteStyle.None,
            false
        ),
        {"Value.2", "Value.3"}
    ),
    TryParseJSON = Table.TransformColumns(
        SplitColumnByDelimiter2,
        {
            "Value.3",
            each List.Last(
                List.Generate(
                    ()=>[SourceText = _, Condition = true, Limit = 0],
                    each [Condition] and [Limit] <= 5,
                    each [
                        Limit = [Limit] + 1,
                        _try = try Json.Document([SourceText]),
                        Condition = _try[HasError],
                        _field = Text.BetweenDelimiters(_try[Error][Message], "'", "'"),
                        _SourceText = Text.Split([SourceText], """" & _field & """"),
                        SourceText = Text.Combine(
                            List.Combine(
                                List.Zip(
                                    {
                                        _SourceText,
                                        List.Transform(
                                            {1 .. List.Count(_SourceText) - 1},
                                            each """" & _field & Text.From(_) & """"
                                        )
                                    }
                                )
                            )
                        )
                    ],
                    each [SourceText]
                )
            )
        }
    ),
    ParsedJSON = Table.TransformColumns(
        TryParseJSON,
        {"Value.3", Json.Document}
    ),
    RemovedErrors = Table.RemoveRowsWithErrors(ParsedJSON),
    // ここで展開するフィールドを調整
    ExpandedValue3 = Table.ExpandRecordColumn(
        RemovedErrors,
        "Value.3",
        {"Start", "Action", "Duration", "Message", "RequestUri"},
        {"Start", "Action", "Duration", "Message", "RequestUri"}
    ),
    ChangedType = Table.TransformColumnTypes(
        ExpandedValue3,
        {
            {"Start", type text},
            {"Action", type text},
            {"Duration", type text},
            {"Message", type text}
        }
    ),
    SortedRows = Table.Sort(ChangedType,{{"Start", Order.Ascending}}),
    AddedIndex = Table.AddIndexColumn(SortedRows, "Index", 1, 1)
in
    AddedIndex

ざっくり注釈

  • Folder.Contents の引数には、トレースログが出力されるパス。Folder.Files ではないので サブフォルダーのファイルは見えません。
  • ファイル拡張子 ".log" でフィルタしパースしないファイルを除外。
  • ログファイル (binary)ごとに Lines.FromBinary でテキスト (text)へ変換しつつリスト (list)にして、それらを List.Combine でひとつのリスト (list) におまとめ
  • このあと列 (column)の分解などするので テーブル (table) に変換
  • おまとめ済みリストのアイテムごとに見たとき、デリミタ ":" で 3つに展開できそうなのがわかるので、さきにふたつ抽出。このとき、QuoteStyle.None にしておかないと困ることが発生する。
  • 残る最後の列 (column)をみたとき、もしかして JSON ? で、Json.Document でパースすると Expression.Error が頻発。調査したら フィールド名が重複することがわかったので、フィールド名をリネームしながら Expression.Error が発生しなくなるまで List.Generate で繰り返し
  • おおむね JSONとしてパースしても問題ない状態なったのでテーブル(table)になるよう展開
  • 時系列でソートしインデックスをつけておいた

思ったこと🙄

Power BI Desktop のログは Excel で、Excel のログは Power BI Desktop で 眺めた方が楽かも。
どこまで細かに把握できるかはわからない。ログのフォーマットはいつか変わるかもしれないし。でも、どのように処理がされるのかヒントを得ることは可能じゃないかな。Diagnostics.Trace については別にポストしようか。

その他

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?