Todos os produtos
Search
Central de documentação

Application Real-Time Monitoring Service:Use extensões personalizadas para o agente Go

Última atualização: Jun 27, 2026

O agente do Application Real-Time Monitoring (ARMS) para Go oferece extensões personalizadas que permitem injetar funcionalidades específicas sem alterar seu source code. Esse recurso facilita a solução de problemas ao capturar dados dos parâmetros e do corpo da requisição. Este tópico utiliza Net/HTTP como exemplo para demonstrar como capturar cabeçalhos de requisição e resposta com essas extensões.

Pré-requisitos

  • Verifique se sua aplicação executa no Go 1.18 ou superior.

  • Sua aplicação Go já está integrada ao Application Real-Time Monitoring (ARMS).

    Importante

    Confirme se o comando de build foi modificado para ./instgo go build xxx, conforme especificado na documentação de integração.

Limitações

  • Não é possível usar extensões personalizadas para instrumentar funções definidas pelo usuário em package main.

  • Extensões personalizadas não suportam a instrumentação de funções cujo ReceiverType seja any.

Especificações de código

  • Evite utilizar package main no seu código de hook.

  • Para códigos da versão 2.0.0 ou posterior, adicione "_ unsafe" à declaração de import, conforme abaixo:

    import (
    	"encoding/json"
    	"fmt"
    	"github.com/alibaba/loongsuite-go-agent/pkg/api"
    	"net/http"
            _ "unsafe"
    )
  • O primeiro parâmetro da função OnEnter é sempre call api.CallContext, o segundo é o ReceiverType (se houver) e os seguintes correspondem aos parâmetros de requisição da função inserida.

    Nota

    Caso o ReceiverType contenha *, adicione o prefixo \\ no arquivo JSON para escapar os caracteres.

  • A função OnExit tem como primeiro parâmetro fixo call api.CallContext, enquanto os subsequentes representam os valores de retorno da função inserida, respeitando a ordem definida.

Por exemplo, a função net/http::(*Transport).RoundTrip apresenta a seguinte estrutura:

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

Como o ReceiverType de RoundTrip é *Transport, o segundo parâmetro da função OnEnter será *Transport e o terceiro será req *Request. Já o segundo e o terceiro parâmetros da função OnExit correspondem aos valores de retorno de RoundTrip: *Response, error.

Se o ReceiverType for um tipo não exportado, utilize _ interface{} como substituto. Essa mesma abordagem vale para ignorar quaisquer parâmetros indesejados, podendo também usar _ interface{} como substituto.

Procedimento

  1. Em um diretório fora do projeto atual, crie uma pasta chamada rules, inicialize-a executando o comando go mod init rules e, em seguida, crie um arquivo chamado rules.go nessa pasta com o código abaixo.

    Este código define a extensão personalizada.

    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. Modifique o arquivo config.json e adicione o conteúdo a seguir para injetar o código de hook em net/http::(*Transport).RoundTrip.

    [
      {
        "ImportPath":"net/http",
        "Function":"RoundTrip",
        "OnEnter":"httpClientEnterHook1",
        "ReceiverType": "\\*Transport",
        "OnExit": "httpClientExitHook1",
        "Path": "/extension/rules" // Replace with the absolute path to the rules folder.
      }
    ]
  3. Crie uma demonstração de teste.

    Fora da pasta rules, crie um diretório para a aplicação de demonstração e use o comando go mod init demo para inicializá-lo. Depois, crie um arquivo net_http.go contendo o código abaixo dentro da pasta demo.

    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. Navegue até o diretório demo. Utilize a ferramenta instgo para compilar e executar o programa.

    $ ./instgo set --rule=../config.json
    $ INSTGO_CACHE_DIR=./ ./instgo go build net_http.go
    # If you need to run on a Linux system
    CGO_ENABLED=0 GOOS=linux GOARCH=amd64 INSTGO_CACHE_DIR=./ ./instgo go build net_http.go
    $ ./net_http

    A saída abaixo confirma que a extensão foi injetada com sucesso.

    request header is  {"Otelbuild":["true"]}
    response header is  {"Content-Type":["application/x-gzip"],"Date":["Mon, 04 Nov 2024 09:10:48 GMT"],"Server":["bfe"]}

    Para consultar o exemplo de código completo, acesse nethttp.

    Nota

    Além de capturar cabeçalhos de requisição e resposta, as extensões personalizadas servem para outras finalidades, como detecção de injeção de SQL, criação de logs personalizados e acesso a parâmetros de requisição e resposta.