如何为Diameter Device-Watchdog Request(DWR)添加日志、记录参数并生成Prometheus指标
实现方案:记录Device-Watchdog参数并生成Prometheus指标
一、捕获并记录Device-Watchdog参数
基于go-diameter包,你需要为**Device-Watchdog Request(命令码280)**注册专属处理函数,在函数内提取请求中的核心参数并记录。
- 注册请求处理器
在初始化Diameter服务器时,绑定命令码对应的处理逻辑:
import ( "log" "time" "github.com/fiorix/go-diameter/v4/diam" "github.com/fiorix/go-diameter/v4/diam/datatype" ) func main() { // 初始化服务器配置(省略原有配置代码) srv, err := diam.NewServer(cfg, nil) if err != nil { log.Fatal(err) } // 为Device-Watchdog Request绑定处理函数 srv.HandleFunc(diam.CommandDeviceWatchdogRequest, handleDeviceWatchdogRequest) // 启动服务器(省略原有启动代码) }
- 提取并记录参数
在处理函数中,提取Origin-Host、Origin-Realm、Vendor-ID等关键参数,写入日志:
func handleDeviceWatchdogRequest(w diam.ResponseWriter, r *diam.Request) { // 提取基础参数 originHost, err := r.Diameter.OriginHost() if err != nil { log.Printf("DWR解析失败:无法获取Origin-Host - %v", err) } originRealm, err := r.Diameter.OriginRealm() if err != nil { log.Printf("DWR解析失败:无法获取Origin-Realm - %v", err) } // 提取Vendor-Specific-Application-ID中的Vendor-ID var vendorID uint32 if vsaiAVP, ok := r.FindAVP(diam.VendorSpecificApplicationID); ok { if vendorIDAVP, ok := vsaiAVP.FindAVP(diam.VendorID); ok { vendorID = vendorIDAVP.Data.(datatype.Unsigned32) } } // 记录完整参数 log.Printf("收到Device-Watchdog请求 | Origin-Host: %s | Origin-Realm: %s | Vendor-ID: %d", originHost, originRealm, vendorID) // 后续处理响应与Prometheus指标更新(见下文) }
二、创建Prometheus指标
使用Prometheus的Go客户端库client_golang,定义计数器、直方图两类指标,分别统计请求总量与响应耗时。
- 导入依赖并定义指标
import ( "net/http" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) // 定义Prometheus指标 var ( // 统计Device-Watchdog请求总量,按Origin-Host、Origin-Realm打标签 dwRequestCounter = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "diameter_device_watchdog_requests_total", Help: "Total number of Device-Watchdog Requests received by the server", }, []string{"origin_host", "origin_realm"}, ) // 统计Device-Watchdog响应耗时,按Origin-Host、Origin-Realm打标签 dwResponseDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "diameter_device_watchdog_response_duration_seconds", Help: "Response time distribution of Device-Watchdog Responses", Buckets: prometheus.DefBuckets, // 使用默认分桶区间 }, []string{"origin_host", "origin_realm"}, ) ) // 初始化时注册指标到Prometheus func init() { prometheus.MustRegister(dwRequestCounter) prometheus.MustRegister(dwResponseDuration) }
- 在处理函数中更新指标
回到handleDeviceWatchdogRequest函数,补充指标更新逻辑,并完成响应发送:
func handleDeviceWatchdogRequest(w diam.ResponseWriter, r *diam.Request) { // (省略之前的参数提取、日志记录代码) // 更新请求计数器 dwRequestCounter.WithLabelValues(originHost, originRealm).Inc() // 记录响应开始时间 startTime := time.Now() // 构造并发送成功响应 resp := r.NewResponse(diam.ResultCodeSuccess) // 填充响应的必要AVP(与服务器配置一致) resp.Header.SetOriginHost(srv.Config().Host) resp.Header.SetOriginRealm(srv.Config().Realm) if err := resp.WriteTo(w); err != nil { log.Printf("发送DWR响应失败:%v", err) return } // 计算响应耗时并更新直方图 duration := time.Since(startTime).Seconds() dwResponseDuration.WithLabelValues(originHost, originRealm).Observe(duration) }
- 暴露Prometheus指标端点
在main函数中启动HTTP服务,暴露/metrics端点供Prometheus采集:
func main() { // (省略原有服务器初始化、处理器绑定代码) // 启动Prometheus指标服务 go func() { http.Handle("/metrics", promhttp.Handler()) log.Fatal(http.ListenAndServe(":9090", nil)) }() // 启动Diameter服务器 log.Fatal(srv.ListenAndServe()) }
三、验证与扩展
- 启动服务后,访问
http://localhost:9090/metrics即可看到自定义的Diameter指标 - 可根据需求扩展指标:比如添加
result_code标签区分成功/失败响应,或统计特定Vendor的请求量
内容的提问来源于stack exchange,提问作者ansuf
相关产品推荐
相关产品推荐

