文档首页/ 函数工作流 FunctionGraph/ API参考/ 扩展及遥测API/ 扩展API/ 如何通过扩展完成DataDog的对接
更新时间:2025-03-01 GMT+08:00

如何通过扩展完成DataDog的对接

本章节指导如何通过扩展API,实现上报监控数据至DataDog平台。

前期准备

  • 在DataDog官方网站注册一个账户。完成注册后,您将能够从DataDog的用户界面获取必要的配置信息,包括需上报数据的目标域名、API密钥以及APP密钥。
  • 对于需要扩展的函数,需要为其启用公网访问。具体操作步骤请参考配置函数访问公网

配置函数对接DataDog

  1. 编写扩展包代码。

    以下代码示例展示了如何通过扩展API,实现向DataDog平台上报functiongraph.invoke.count指标,以记录函数调用次数。可参考此示例开发扩展包。
    package main
     
    import (
        "context"
        "encoding/json"
        "errors"
        "fmt"
        "io"
        "net/http"
        "os"
        "time"
     
        "github.com/DataDog/datadog-api-client-go/v2/api/datadog"
        "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
    )
     
    const (
        registerURL    = "/extension/register"
        invokeURL      = "/extension/invoke"
        requestTimeout = 5 * time.Second
        extensionName  = "FunctionGraph-Extension-Name"
        extensionAddr  = "FunctionGraph-Extension-Address"
     
        currentExtensionAddr = "127.0.0.1:8081"
        currentExtensionName = "extension_1.sh"
    )
     
    var (
        extensionApiAddr = os.Getenv("EXTENSION_API_ADDR")
    )
     
    type ExtensionRequest struct {
        TraceID string `json:"traceId" valid:"optional"`
        URN     string `json:"invokedFunctionUrn" valid:"optional"`
    }
     
    func init() {
        // Set your DataDog site address
        os.Setenv("DD_SITE", "your_datadog_site")
        // Set your DataDog api key
        os.Setenv("DD_API_KEY", "your_datadog_api_key")
        // Set your DataDog app key
        os.Setenv("DD_APP_KEY", "your datadog_app_key")
    }
     
    func main() {
        err := registerExtension(currentExtensionName, currentExtensionAddr)
        if err != nil {
            fmt.Printf("failed to register extension, error: %s \n", err.Error())
            return
        }
     
        http.HandleFunc(invokeURL, ServeHTTP)
        err = http.ListenAndServe(currentExtensionAddr, nil)
        if err != nil {
            fmt.Printf("http server error, error: %s \n", err.Error())
            return
        }
     
        return
     
    }
     
    func getHTTPClient() *http.Client {
        httpClient := &http.Client{
            Timeout: requestTimeout,
        }
        return httpClient
    }
     
    func registerExtension(name, address string) error {
        if len(extensionApiAddr) == 0 {
            return errors.New("failed to get extension api addr")
        }
        baseURLPath := "http://" + extensionApiAddr + registerURL
        req, err := http.NewRequest("POST", baseURLPath, nil)
        if err != nil {
            fmt.Printf("failed to build register request, error: %s\n", err.Error())
            return err
        }
        req.Header.Set("Content-Type", "application/json")
        req.Header.Set(extensionName, currentExtensionName)
        req.Header.Set(extensionAddr, currentExtensionAddr)
        _, err = getHTTPClient().Do(req)
        if err != nil {
            fmt.Printf("failed to send register request, error: %s\n", err.Error())
            return err
        }
        return nil
    }
     
    func ServeHTTP(writer http.ResponseWriter, request *http.Request) {
        req := ExtensionRequest{}
        defer request.Body.Close()
        b, err := io.ReadAll(request.Body)
        if err != nil {
            fmt.Printf("failed to parse invoke request body with error: %s \n", err.Error())
            writeHeaders(writer, 500, "failed to parse invoke request body")
            return
        }
        if err := json.Unmarshal(b, &req); err != nil {
            fmt.Printf("failed to unmarshal the json, error: %s", err.Error())
            writeHeaders(writer, 500, "failed to unmarshal the json")
            return
        }
     
        fmt.Println(" invoke request traceID -- ", req.TraceID)
        fmt.Println(" invoke request URN -- ", req.URN)
        sendMetricToMyDataDog(req.URN, req.TraceID)
        writeHeaders(writer, 200, "succeed to get invoke request")
        return
    }
     
    func writeHeaders(w http.ResponseWriter, status int, msg string) error {
        w.WriteHeader(status)
        _, err := w.Write([]byte(msg))
        return err
    }
     
    func sendMetricToMyDataDog(urn string, traceId string) {
        // Assemble your metric data
        body := datadogV2.MetricPayload{
            Series: []datadogV2.MetricSeries{
                {
                    Metric: "functiongraph.invoke.count",
                    Type:   datadogV2.METRICINTAKETYPE_UNSPECIFIED.Ptr(),
                    Points: []datadogV2.MetricPoint{
                        {
                            Timestamp: datadog.PtrInt64(time.Now().Unix()),
                            Value:     datadog.PtrFloat64(1),
                        },
                    },
                    Resources: []datadogV2.MetricResource{
                        {
                            Name: datadog.PtrString(urn),
                            Type: datadog.PtrString("function_urn"),
                        },
                        {
                            Name: datadog.PtrString(traceId),
                            Type: datadog.PtrString("trace_id"),
                        },
                    },
                },
            },
        }
        ctx := datadog.NewDefaultContext(context.Background())
        configuration := datadog.NewConfiguration()
        apiClient := datadog.NewAPIClient(configuration)
        api := datadogV2.NewMetricsApi(apiClient)
        resp, r, err := api.SubmitMetrics(ctx, body, *datadogV2.NewSubmitMetricsOptionalParameters())
     
        if err != nil {
            fmt.Fprintf(os.Stderr, "Error when calling `MetricsApi.SubmitMetrics`: %v\n", err)
            fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
        }
     
        responseContent, _ := json.MarshalIndent(resp, "", "  ")
        fmt.Fprintf(os.Stdout, "Response from `MetricsApi.SubmitMetrics`:\n%s\n", responseContent)
    }

  2. 制作函数扩展依赖包。

    请参见如何制作函数依赖包制作函数扩展依赖包。制作完成后的依赖包示例:datadog-extension,可下载使用。

  3. 配置函数扩展依赖包。

    请参见配置依赖包为需要扩展的函数配置依赖包。

  4. 触发函数执行,登录DataDog查看上报指标。

    图1 登录DataDog查看上报指标