Golang エージェントは、元のコードを変更することなくカスタム関数を注入できるカスタム拡張機能を提供します。これにより、リクエストパラメーターとリクエストボディを検査して問題を特定できます。このトピックでは、Net/HTTP を例として、Golang エージェントのカスタム拡張機能を使用してリクエストヘッダーとレスポンスヘッダーを取得する方法を説明します。
前提条件
アプリケーションが Golang 1.18 以降を使用していることを確認してください。
Golang アプリケーションを Application Real-Time Monitoring Service (ARMS) に接続済みであること。
重要統合ドキュメントの説明に従って、コンパイル文が
./instgo go build xxxに変更されていることを確認してください。
制限事項
カスタム拡張機能は、`package main` 内のユーザー関数のインストルメンテーションをサポートしていません。
カスタム拡張機能は、ReceiverType が `any` である関数のイベントトラッキングをサポートしていません。
仕様
フックコードでは `package main` を使用しないでください。
コードバージョン 2.0.0 以降を使用する場合は、次のように import 文に
"_ unsafe"を追加します。import ( "encoding/json" "fmt" "github.com/alibaba/loongsuite-go-agent/pkg/api" "net/http" _ "unsafe" )`OnEnter` 関数の最初のパラメーターは
call api.CallContextである必要があります。2 番目のパラメーターは、存在する場合、ReceiverType です。後続のパラメーターは、インストルメント対象の関数の入力パラメーターです。説明ReceiverType に
*が含まれている場合は、JSON ファイルで\\プレフィックスを追加して文字をエスケープする必要があります。`OnExit` 関数の最初のパラメーターは
call api.CallContextである必要があります。後続のパラメーターは、インストルメント対象の関数の戻り値です。
たとえば、net/http::(*Transport).RoundTrip 関数は次のとおりです。
func (t *Transport) RoundTrip(req *Request) (*Response, error) {
return t.roundTrip(req)
}RoundTrip のレシーバータイプは *Transport です。したがって、OnEnter 関数の 2 番目のパラメーターは *Transport で、3 番目のパラメーターは req *Request です。OnExit 関数の 2 番目と 3 番目のパラメーターは RoundTrip の戻り値であり、*Response, error です。
ReceiverType が小文字で始まる非公開クラスである場合は、その型として _ interface{} を使用します。また、省略したいパラメーターのプレースホルダーとして _ interface{} を使用することもできます。
手順
現在のプロジェクトディレクトリの外に `rules` フォルダを作成します。
go mod init rulesコマンドを実行してフォルダを初期化します。次に、`rules` フォルダに `rules.go` ファイルを作成し、次のコードを含めます。このコードは、注入するカスタム拡張機能を定義します。
package rules import ( "encoding/json" "fmt" "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api" "net/http" _ "unsafe" ) //go:linkname httpClientEnterHook1 net/http.httpClientEnterHook1 func httpClientEnterHook1(call api.CallContext, t *http.Transport, req *http.Request) { header, _ := json.Marshal(req.Header) fmt.Println("request header is ", string(header)) } //go:linkname httpClientExitHook1 net/http.httpClientExitHook1 func httpClientExitHook1(call api.CallContext, res *http.Response, err error) { header, _ := json.Marshal(res.Header) fmt.Println("response header is ", string(header)) }`config.json` 構成ファイルを変更します。次の内容を追加して、フックコードを
net/http::(*Transport).RoundTripに注入します。[ { "ImportPath":"net/http", "Function":"RoundTrip", "OnEnter":"httpClientEnterHook1", "ReceiverType": "\\*Transport", "OnExit": "httpClientExitHook1", "Path": "/extension/rules" // rules フォルダの絶対パスに置き換えます } ]サンプルアプリケーションを作成します。
`rules` フォルダとは別のディレクトリに、サンプルアプリケーション用の新しいフォルダを作成します。このフォルダを
go mod init demoコマンドを実行して初期化します。次に、`demo` フォルダに `net_http.go` ファイルを作成し、次のコードを含めます。package main import ( "context" "net/http" ) func main() { req, err := http.NewRequestWithContext(context.Background(), "GET", "http://www.baidu.com", nil) if err != nil { panic(err) } req.Header.Set("otelbuild", "true") client := &http.Client{} resp, err := client.Do(req) defer resp.Body.Close() }`demo` ディレクトリに切り替えます。instgo ツールを使用してプログラムをコンパイルし、実行します。
$ ./instgo set --rule=../config.json $ INSTGO_CACHE_DIR=./ ./instgo go build net_http.go # Linux で実行する場合 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 INSTGO_CACHE_DIR=./ ./instgo go build net_http.go $ ./net_http次の出力が表示された場合、注入が成功し、拡張機能がアクティブであることを示します。

完全なコード例については、nethttp をご参照ください。
説明リクエストヘッダーとレスポンスヘッダーの取得に加えて、SQL インジェクションの検出、カスタムロギング、リクエストパラメーターとレスポンスパラメーターの取得など、他の目的でカスタム拡張機能を使用できます。