全部產品
Search
文件中心

Application Real-Time Monitoring Service:使用Golang探針的自訂擴充能力

更新時間:Nov 29, 2025

Golang探針提供自訂擴充能力,您可以在不修改原有代碼的基礎上注入自訂功能,從而實現通過請求參數、Body來定位問題。本文以Net/HTTP為例介紹如何使用Golang探針的自訂擴充能力擷取要求標頭和回應標頭。

前提條件

  • 確認當前應用的Golang版本在1.18及以上。

  • 將Golang應用接入到ARMS

    重要

    請確認編譯語句已參考接入文檔修改為./instgo go build xxx

限制說明

  • 自訂擴充能力暫無法對Package main中的使用者函數埋點。

  • 自訂擴充能力暫無法對ReceiverType為any的函數埋點。

編寫規範

  • Hook代碼中不能使用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,第二個參數為ReceiverType(如果有),後續參數為插入函數的入參。

    說明

    ReceiverType存在*時,需在JSON檔案內加上\\首碼用於轉義。

  • OnExit函數第一個參數固定為call api.CallContext,後續參數依次填寫插入函數的傳回值。

例如,net/http::(*Transport).RoundTrip函數如下所示:

func (t *Transport) RoundTrip(req *Request) (*Response, error) {
	return t.roundTrip(req)
}

RoundTrip的ReceiverType為*Transport,所以OnEnter函數的第二參數為*Transport,第三個參數為req *Request;OnExit函數的第二個、第三個參數為RoundTrip的傳回值*Response, error

如果ReceiverType是一個小寫類,沒有對外暴露,可以使用_ interface{}代替,如果有參數不想填,也可以使用_ interface{}代替。

操作步驟

  1. 在非當前專案的目錄下建立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))
    }
  2. 修改config.json設定檔,添加以下內容將hook代碼注入到net/http::(*Transport).RoundTrip

    [
      {
        "ImportPath":"net/http",
        "Function":"RoundTrip",
        "OnEnter":"httpClientEnterHook1",
        "ReceiverType": "\\*Transport",
        "OnExit": "httpClientExitHook1",
        "Path": "/extension/rules" //替換為rules檔案夾的絕對路徑
      }
    ]
  3. 編寫測試Demo。

    在不同於rules檔案夾的目錄下建立一個demo應用的檔案夾,並使用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()
    
    }
    
  4. 切換到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

    如果輸出以下內容, 表示注入成功,外掛程式已生效。

    image.png

    完整的範例程式碼請參見nethttp

    說明

    除了上述介紹的通過擴充方式列印請求和返回的Header外,自訂擴充能力還可以用於SQL注入檢測、日誌列印、出參和入參列印等。