【Azure】Bicepを使ってデータ収集ルール（カスタムテキストログ）を構成する

### 初めに
皆さんこんにちは、データ収集ルール（カスタムテキストログ）はAzurePortalからはあまり知識が無くてもなんとなく上手く構築できてしましまいますが、Bicepで書いていく場合は少しだけ深い知見が必要になります。とはいってもそれほど難しくはないので、一緒に学んでいきましょう。

## 目次

+ [コードの構成](#tablestorageから仮想マシンのリストを取得する)
    + [streamDeclarations](#streamdeclarations)
    + [dataSources](#datasources)
    + [destinations](#destinations)
    + [dataFlows](#dataflows)
+ [コードサンプル](#コードサンプル) 

## コードの構成
まずはコードの全体像を見てみましょう。
``` Bicep:コードの全体像
resource dataCollectionRules 'Microsoft.Insights/dataCollectionRules@2022-06-01' = {
  name: <リソース名>
  location: <リソースの場所（リソースグループのリージョン）>
  tags: {
    <タグを記載>
  }
  kind: <Linux or Windows>
  properties: {
    dataCollectionEndpointId: <このルールを使用できるデータ収集エンドポイントのリソースID>
    streamDeclarations: {
      <"Custom-" + ストリーム名>: {
        columns: [
          {
            name: <列名>
            type: ＜列の形式＞
          }
          ・・・
        ]
      }
    }
    dataSources: {
      logFiles: [
        {
          name: <データソースのフレンドリ名>
          streams: [
            <"Custom-" + ストリーム名>
          ]
          filePatterns: [
            <取得したいログファイルのパス>
          ]
          format: 'text'
          settings: {
            text: {
              recordStartTimestampFormat: <タイムスタンプのフォーマット>
            }
          }
        }
      ]
    }
    destinations: {
      logAnalytics: [
        {
          name: <宛先のフレンドリ名>
          workspaceResourceId: <格納先のワークスペースのリソースID>
       }
      ]
    }
    dataFlows: [
      {
        streams: [
          <このデータフローのストリームの一覧>
        ]
        destinations: [
          <このデータフローの宛先の一覧>
        ]
        transformKql:<ログの変換用KQL>
        outputStream:<"Custom-" + 保存先のテーブル名>
      }
    ]
  }
}
```

上のコードを見てわかる通り、コードは以下の４つから構成されます。
+ [streamDeclarations](#streamdeclarations)：取得するログの構造の宣言
+ [dataSources](#datasources)：取得するログの情報
+ [destinations](#destinations)：取得したログの送信先の情報
+ [dataFlows](#dataflows)：ログの変換

それぞれの関係はこんな感じ見たいです。参考：[公式ドキュメント](https://learn.microsoft.com/ja-jp/azure/azure-monitor/essentials/data-collection-rule-structure)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/22dbb5c8-14ff-c4ab-6afe-a6e91430f9f7.png)

ここで表記されている２種類のデータ「Known data」と「Custom data」があります。
[公式ドキュメントの説明](https://learn.microsoft.com/ja-jp/azure/azure-monitor/essentials/data-collection-rule-structure)に解説が載っていますが、やや理解が難しいですね。私の解釈は以下表に記載されているデータソースのログは「Known data」と思っています。それ以外が「Cutom data」と思っていますが、扱ったことが無いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/a4861ab2-e495-aff0-8685-b3aa23d82a1e.png)

### streamDeclarations
```Bicep:streamDeclarations
    streamDeclarations: {
      <"Custom-" + ストリーム名>: {
        columns: [
          {
            name: <列名>
            type: ＜列の形式＞
          }
          ・・・
        ]
      }
    }
```
+ 実はカスタムテキストログ収集においては省略可能
+ 先頭名が"Custom-"となる必要がある
+ 形式は送信先のテーブルと一致する必要はない
+ 後の「[dataFlows](#dataflows)」で「[destinations](#destinations)」と突き合わせする

### dataSources
```Bicep:dataSources
    dataSources: {
      logFiles: [
        {
          name: <データソースのフレンドリ名>
          streams: [
            <"Custom-" + ストリーム名>
          ]
          filePatterns: [
            <取得したいログファイルのパス>
          ]
          format: 'text'
          settings: {
            text: {
              recordStartTimestampFormat: <タイムスタンプのフォーマット>
            }
          }
        }
      ]
    }
```
+ ここでデータソースの種類を指定
+ カスタムテキストログを使用する時は「LogFiles（[MS公式ドキュメント|LogFilesDataSource](https://learn.microsoft.com/ja-jp/azure/templates/microsoft.insights/2022-06-01/datacollectionrules?pivots=deployment-language-bicep#logfilesdatasource)）」を選択
+ 「Streams:」には'"Custom-" + ストリーム名'を記載
+ 「filePatterns:」には、取得先のファイルパスを記載。AzurePortalでは以下の部分。「*」等の正規表現が使用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/736a48d1-f14d-2c9c-fc26-11be91c31c5b.png)
+ LogFilesでは「format:」には'text'を記載
+ 「recordStartTimestampFormat:」はAzurePortalでは以下の部分。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/ef43cf30-6b59-3309-f694-a6f4d33e8234.png)
+ 「End of Line」を指定したい場合は「recordStartTimestampFormat:」に'ISO 8061'を指定してください。
```Bicep:End of Lineの指定
          settings: {
            text: {
              recordStartTimestampFormat: ISO 8061
            }
```
:::note warn
警告：2025/1/30 11:00
現在、上記の通りISO 8061に設定をしてもAzurePortal上では「End of Line」と表示されない不具合が発生しています。表示だけの問題であり、機能には影響ないとMSから回答をもらって
:::

### destinations
```Bicep:destinations
    destinations: {
      logAnalytics: [
        {
          name: <宛先のフレンドリ名>
          workspaceResourceId: <格納先のワークスペースのリソースID>
       }
      ]
    }
```
+  ここでログの出力先を指定
+  LogAnalyticsワークスペースへ出力の場合は「logAnalytics:」を記載
+  他の宛先は以下の感じ（[参考：MSドキュメント|destinations 有効な宛先](https://learn.microsoft.com/ja-jp/azure/azure-monitor/essentials/data-collection-rule-structure#valid-destinations)）
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/f5cbad9a-fe29-aecf-264e-3c30f7de68f2.png)
+ 複数の宛先も指定可能
### dataFlows
```Bicep:dataFlows
    dataFlows: [
      {
        streams: [
          <このデータフローのストリームの一覧>
        ]
        destinations: [
          <このデータフローの宛先の一覧>
        ]
        transformKql:<ログの変換用KQL>
        outputStream:<"Custom-" + 保存先のテーブル名>
      }
    ]
```
+ 「streamDeclarations」で宣言していた場合は、ここで「Destination」と紐づけや変換処理を行う
+ 「streams:」には、streamDeclarationsで宣言した名前を記載。
+ 「streamDeclarations」を省略した場合は、「dataSources」の「Streams」に記載の名前を記載。
+ 「destinations:」には、destinationsで宣言した名前を記載
+ 「transformKQL:」には変換式を記載。AzurePortal画面では以下
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678759/7463deb0-56f7-f905-8d0f-22487c70790e.png)

+ 「outputStream:」には'"Custom-" + 保存先のテーブル名'を記載

## コードサンプル
以下にコードサンプルを載せてしておきます。
```Bicep:サンプル（Destinationを省略）
  param name string = 'dcr-customtextlogs'
  param location string = 'japaneast'
  param kind string = 'Linux'
  param dataCollectionEndpointId string = '/subscriptions/<サブスクリプション名>/resourceGroups/<リソースグループ名>/providers/Microsoft.Insights/dataCollectionEndpoints/<データ収集エンドポイント名>'
  param dataSources_name string = 'CustomtextDataSource'
  param streams string = 'Custom-demoStream'//ここにストリーム名
  param filePatterns string = '/var/log/demo.log'//ログ取得先のパスを記載
  param transformKql string = 'source| extend TimeGenerated = now()'//TransformKQLを記載
  param format string = 'text'
  param destinations_name string = 'demo-workspace'
  param workspace string = '/subscriptions/<サブスクリプション名>/resourcegroups/<リソースグループ名>/providers/microsoft.operationalinsights/workspaces/<ワークスペース名>'
  param dataFlows_destinations string = 'demo-workspace'//ワークスペース名
  param timeformats string = 'ISO 8601'
  param outputstreams string = 'Custom-demo_CL'//ここにワークスペース名

  resource dataCollectionRules 'Microsoft.Insights/dataCollectionRules@2022-06-01' = {
    name: name
    location: location
    kind: kind
    properties: {
      dataCollectionEndpointId: dataCollectionEndpointId
      dataSources: {
        logFiles: [
          {
            name: dataSources_name 
            streams: [
              streams
            ]
            filePatterns: [
              filePatterns
            ]
            format: format
            settings: {
              text: {
                recordStartTimestampFormat: timeformats
              }
            }
          }
        ]
      }
      destinations: {
        logAnalytics: [
          {
            name: destinations_name
            workspaceResourceId: workspace
        }
        ]
      }
      dataFlows: [
        {
          streams: [
            streams 
          ]
          destinations: [
            dataFlows_destinations 
          ]
          transformKql:transformKql
          outputStream:outputstreams
        }
      ]
    }
  }
```

```Bicep:サンプル（Destinationを定義）
param name string = 'dcr-customtextlogs'
param location string = 'japaneast'
param kind string = 'Linux'
param dataCollectionEndpointId string = '/subscriptions/<サブスクリプション名>/resourceGroups/<リソースグループ名>/providers/Microsoft.Insights/dataCollectionEndpoints/<データ収集エンドポイント名>'
param dataSources_name string = 'CustomtextDataSource'
param streams string = 'Custom-demoStream'//ここにストリーム名
param filePatterns string = '/var/log/demo.log'//ログ取得先のパスを記載
param transformKql string = 'source| extend TimeGenerated = now()'//TransformKQLを記載
param format string = 'text'
param destinations_name string = 'demo-workspace'
param workspace string = '/subscriptions/<サブスクリプション名>/resourcegroups/<リソースグループ名>/providers/microsoft.operationalinsights/workspaces/<ワークスペース名>'
param dataFlows_streams string = 'Custom-demoStream'//ここにストリーム名
param dataFlows_destinations string = 'demo-workspace'//ワークスペース名
param timeformats string = 'ISO 8601'
param outputstreams string = 'Custom-demo_CL'//ここにワークスペース名


resource dataCollectionRules 'Microsoft.Insights/dataCollectionRules@2022-06-01' = {
  name: name
  location: location
  kind: kind 
  properties: {
    dataCollectionEndpointId: dataCollectionEndpointId
    streamDeclarations: {
      'Custom-demoStream': {
        columns: [
          {
            name: 'Time'
            type: 'datetime'
          }
          {
            name: 'Row1'
            type: 'string'
          }
          {
            name: 'Row2'
            type: 'string'
          }
          {
            name: 'Row3'
            type: 'string'
          }
        ]
      }
    }
    dataSources: {
      logFiles: [
        {
          name: dataSources_name 
          streams: [
            streams
          ]
          filePatterns: [
            filePatterns
          ]
          format: format
          settings: {
            text: {
              recordStartTimestampFormat: timeformats
            }
          }
        }
      ]
    }
    destinations: {
      logAnalytics: [
        {
          name: destinations_name
          workspaceResourceId: workspace 
       }
      ]
    }
    dataFlows: [
      {
        streams: [
          dataFlows_streams
        ]
        destinations: [
          dataFlows_destinations
        ]
        transformKql:transformKql
        outputStream:outputstreams
      }
    ]
  }
}

```