Datadog Integrationを魔改造する

:::note info
この記事は[ZOZO AdventCalender 2023](https://qiita.com/advent-calendar/2023/zozo)シリーズ5の11日目の記事です。
:::

# Datadog Integration
Datadogには[インテグレーション](https://docs.datadoghq.com/ja/integrations/)と呼ばれる、様々なシステム/アプリケーション/サービスの監視を実現するための機能があります。  
[公式ドキュメント](https://docs.datadoghq.com/ja/getting_started/integrations/)のインテグレーションとは を確認すると以下のように書かれています。  
>最上位レベルにおいては、通常個別に検討される要素から統合されたシステムを構築することをいいます。Datadog では、インテグレーションを利用することで、インフラストラクチャーからすべてのメトリクスとログを収集して、統合システムを全体として把握することができます。1 つひとつの要素はもちろん、個々の要素が全体にどのように影響を与えているかも確認できます。  

正直よくわかりませんが、インテグレーションを使えば色んなシステムからメトリクスとログが取得できるよ！ってことです。  
実際、現時点でDatadogが提供する組み込みインテグレーションは650以上あるようでメジャーなシステムはほぼ網羅してるといって良いと思います。  

### インテグレーションの種類
こちらも公式ドキュメントからの引用になりますが、Datadogでは主に3種類のインテグレーションが提供されています。  
>エージェントベースのインテグレーションは、Datadog Agent と共にインストールされ、check という Python クラスメソッドを使用して、収集するメトリクスを定義します。
認証 (クローラー) ベースのインテグレーションは、Datadog で設定されます。その際、API を使用してメトリクスを取得するための資格情報を指定します。これには、Slack、AWS、Azure、PagerDuty などのよく使用されるインテグレーションがあります。
ライブラリインテグレーションでは、Datadog API を使用して、記述言語 (Node.js、Python など) に基づいてアプリケーションを監視できます。

今回はこれらの3種類のインテグレーションのうち、エージェントベースで提供されるものを独自にカスタマイズする方法を説明したいと思います。  
なおこれから説明するカスタマイズ方法は、使用していたインテグレーションの実装にバグがありそれを解消するために行ったもので公式で推奨されたやり方ではありませんのでご了承ください。  
※しばらく魔改造したもので稼働させていましたが、現在は同じチームのメンバーが公式にPRを送ってマージされているので公式のものに戻しています。

## インテグレーションを魔改造するぞ
[公式ドキュメントのインテグレーションの設定](https://docs.datadoghq.com/ja/getting_started/integrations/#%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E8%A8%AD%E5%AE%9A)で、
>Datadog Agent パッケージには、Datadog が公式にサポートしているインテグレーションコアが含まれています  

と説明されています。  
インテグレーションコアはDatadogAgent本体とは別のリポジトリで管理されていて、このリポジトリには公式でサポートされている様々なシステムのメトリクスやログを収集するための実装が含まれています。  
今回はこのインテグレーションコアのリポジトリで管理されているpythonのコードを修正して差し替えることで魔改造を実現していきます。  
早速、手順を説明していきたいと思います。

#### 手順
1. まずはこの[インテグレーションコアのリポジトリ](https://github.com/DataDog/integrations-core)をforkしてリポジトリを準備します。  
2. forkしたリポジトリで元のリポジトリの最新を取り込めるように設定します。
    ```git
    git remote add upstream git@github.com:DataDog/integrations-core.git
    git fetch -p upstream
    ```
3. forkしたリポジトリでベースにしたいdatadog agentのバージョンのtagからブランチを作ります(ex: 7.44.0 → 7.44.0-selfpatch)
4. 手順3で作成したブランチで修正を行います。
5. 修正ができたらブランチをpushしてtagを打ちます。
    ```git
    git tag 7.44.0.selfpatch-1
    git push origin 7.44.0.selfpatch-1
    ```
6. インストールしたい(している)DatadogAgentをベースにしたDockerfileを用意して、pipコマンドでインテグレーションコアを差し替えます。  
    以下の例ではsqlserverの実装を差し替えています。
    ```Dockerfile
    FROM datadog/agent:7.44.0
    pip uninstall -y datadog-sqlserver
    pip install git+https://github.com/kane8n/integrations-core.git@7.44.0.selfpatch-1#subdirectory=sqlserver
    ```
7. このDockerfileをビルドしたイメージでDatadogAgentを稼働させれば魔改造の完了です。

### 詳解
手順の中でポイントとなる箇所を説明していきます。  

#### インテグレーションコアのリポジトリ構造
[インテグレーションコアのリポジトリ](https://github.com/DataDog/integrations-core)を見ると、リポジトリルートの直下に様々な製品やシステム名のディレクトリがあります。  
このそれぞれのディレクトリ配下には、`pyproject.toml`や`setup.py`といったpythonプロジェクトを管理するためのファイルと、  
`datadog_checks`という各種製品/システムのメトリクスやログを収集するための実装が含まれたディレクトリが存在します。  
例えばnginxだとこんな感じのディレクトリ構成になっています。
![スクリーンショット 2023-11-09 12.37.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108538/4e66f32b-7859-f565-da55-d490bc475519.png)
独自の修正やカスタマイズを行う場合、`datadog_checks`配下のファイルを修正します。

#### pipコマンドでの差し替えについて
- uninstall
  ```zsh
  pip unstall -y datadog-sqlserver
  ```
  これはインテグレーションコア本家の実装を一旦uninstallしています。  
  `datadog-[インテグレーション名]`という命名規則になっているので、差し替えたいインテグレーションの名前に適時変えます。
- install
  ```zsh
  pip install git+https://github.com/kane8n/integrations-core.git@7.44.0.selfpatch-1#subdirectory=sqlserver
  ```
  uninstallしたインテグレーションの代わりにforkした自前実装のインテグレーションをinstallしています。
  リポジトリ名の後ろの`@`に続けて手順5で作成したtagを指定します。
  `#subdirectory=sqlserver`と指定している箇所は、インテグレーションコアのリポジトリ直下にある対象としたい製品/システムのディレクトリ名を指定します。

公式ドキュメントでの説明と実際にインテグレーションコアのリポジトリを見ることでインテグレーションコアはpythonで実装されていることがわかりました。  
ではなぜpipコマンドで差し替えられるのかを説明していきたいと思います。  

##### DatadogAgent本体を見てみよう
`setup.py`があることからなんとなく`pip`で管理されてるだろうなというあたりは付けれるので、まずはさくっとgithubの検索機能を使ってDatadogAgent本体のリポジトリを調べてみます。  
[検索結果](https://github.com/search?q=repo%3ADataDog%2Fdatadog-agent%20pip%20install&type=code)を見てみると予想通り`pip install`をしてるファイルが見つかります。  
その中でも`omnibus/config/software/datadog-agent-integrations-py3.rb`や`omnibus/config/software/datadog-agent-integrations-py2.rb`といった、いかにもインテグレーションのインストールをやってそうなファイルが見つかります。  
さらにファイルの中を追っていくと、[pip install datadog-#{check}](https://github.com/DataDog/datadog-agent/blob/c50f63ad3570ec56b1e2870bae787be545f39211/omnibus/config/software/datadog-agent-integrations-py3.rb#L457)を実行している箇所が見つかりました。  
ファイルの先頭のほうには`integrations-core`のgitリポジトリの定義もあり、これでpipでインテグレーションを管理していることは確実そうです。  
しかしながらお気づきの方も多いと思いますが、このファイルはrubyのファイルです。そしてルートディレクトリは`omnibus`という名前です。  
`omnibus`とはなんでしょう。rubyの経験がある方なら知ってるかもしれませんが、筆者はあまりrubyの経験はありません。  
わからないので調べてみます。

##### omnibus
検索してみるとさっそく[リポジトリ](https://github.com/chef/omnibus)が見つかります。  
そして[datadogがforkしてるリポジトリ](https://github.com/DataDog/omnibus-ruby)も見つかりました。  
READMEを読んでみると、
>Easily create full-stack installers for your project across a variety of platforms.

とあります。なにやらインストーラを簡単につくれるもののようです。  
どうやらDatadogAgentはこの`omnibus`を使ってコードやimageのビルドを行っているようです。  
インテグレーションのinstallをやっているファイルは、`omnibus/config/software`以下にあります。  
[ドキュメント](https://github.com/DataDog/omnibus-ruby#software)によると、
>オムニバス "ソフトウェア "ファイルは、パッケージ全体を構成する個々のソフトウェアコンポーネントを定義します。これらはアプリケーションの構成要素です。
ソフトウェアDSLは、ソフトウェアソースの取得場所、ビルド方法、依存関係を定義 する方法を提供します。
これらの依存関係も独自のソフトウェア DSL ファイルで定義され、依存関係を考慮したビルド順序の基礎を形成します。
すべてのソフトウェア定義は、Omnibus プロジェクトリポジトリの config/software ディレクトリに置く必要があります。

※DeepL先生に訳してももらいました

とあるのでsoftware配下に定義されたものでパッケージに含まれるソフトウェアが全て管理されるようです。  
DatadogAgent本体のビルドなどを行うdatadog-agent.rbもありますね。  


以上のことからインテグレーションの実装はpipでインストールされていることがわかりました。  
pip installした状態でimageがビルドされているなら、そのimageをbaseにしたDockerfileでpipの操作をしてやれば良いだけであることがわかったと思います。


# 最後に
この記事ではDatadog Integraionを独自に修正する方法について説明しました。  
ただこの手法は公式で提示された方法ではなく、筆者がバグを回避するために試行錯誤した結果です。  
この手法のユースケースとしては、何かバグを発見して修正方法までわかったからちょっと試しに動かしたい！なんて時になると思います。  
バグを発見して修正から動作確認まで出来たら是非公式にPRを送ってください。