Skywalking-go自动监控增强使用探究

 更新时间:2024年01月15日 11:18:54   作者:vearne的01世界  
这篇文章主要介绍了Skywalking-go自动监控增强使用深入探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

1.使用Skywalking-go

使用Skywalking-go,我们可以基于Golang build提供的-toolexec参数,实现了编译期劫持,达到在对代码几乎无侵入的情况下,实现埋点。

Skywalking对大量的框架(比如: gin)提供了支持, 然后这种支持仅限于增加了tracing信息。我们知道完整的监控往往离不开3个重要部分Metrics、Tracing、Logging。那些需要埋点的位置,往往这3种信息都是需要的,是否可以修改Skywalking-go,来达到代码增强的过程同时添加Metrics、Tracing、Logging呢?答案是肯定的。

代码参考

1)改动后的Skywalking-go

vearne/skywalking-go

注意: 如果读者有自己改动的计划,建议好好阅读官方文档,并参考萌叔的改动代码

git diff f9929c6c9275b12f70ec2368544244f27a92f768

2) 测试项目

vearne/sw-test

2.解决问题

2.1 Tracing

tracing保持不变

2.2 Logging

Skywalking默认提供了对zaplogrus的劫持,因此可以直接在插件对应的拦截器中增加对应的日志即可

intercepter.go

package gin

import (
    "fmt"

    "github.com/gin-gonic/gin"

    // 需要增加的import 
    "github.com/apache/skywalking-go/plugins/core/log"
    "github.com/apache/skywalking-go/plugins/core/operator"
    "github.com/apache/skywalking-go/plugins/core/prom"
    "github.com/apache/skywalking-go/plugins/core/tracing"
)

type HTTPInterceptor struct {
}
...
func (h *HTTPInterceptor) AfterInvoke(invocation operator.Invocation, result ...interface{}) error {
    ...

    // add logging
    log.Infof("url:%v", context.Request.URL.Path)
    ...
    return nil
}

经过上诉改动以后,插件拦截器新增的日志,也会输出到和业务日志相同的位置

2024-01-08 13:51:24 | info | url:/ping | {"SW_CTX": "[sw-test,e6966b62ade911eeb5565626e1cdcfe1@10.2.130.14,N/A,N/A,-1]"}
2024-01-08 13:51:24 | info | sw-test/main.go:76 | ping | {"setRes": 0, "SW_CTX": "[sw-test,e6966b62ade911eeb5565626e1cdcfe1@10.2.130.14,e6964894ade911eeb5565626e1cdcfe1.98.39164466848770001,e6964894ade911eeb5565626e1cdcfe1.98.39164466848770002,0]"}

可以看出每条日志都被添加了tracing信息,这有助于我们把tracing和对应的日志关联起来

zap 日志增强的示例

func New(core zapcore.Core, options ...Option) (skywalking_result_0 *Logger) {
    defer skywalking_enhance_automaticLoggerBindgo_uber_org_zap_New(&core,&options,&skywalking_result_0);   
    /*
     这个defer函数把返回的新创建的logger对象skywalking_result_0,保存在一个全局变量中
     "New", "NewNop", "NewProduction", "NewDevelopment", "NewExample"也做了类似动作
    */
    if core == nil {
        return NewNop()
    }
    log := &Logger{
        core:       core,
        errorOutput:    zapcore.Lock(os.Stderr),
        addStack:   zapcore.FatalLevel + 1,
        clock:      zapcore.DefaultClock,
    }
    return log.WithOptions(options...)
}

2.2 Metrics

Skywalking-go也有提供的Metrics,但它的实现比较弱,另外萌叔的项目几乎都使用的是Prometheus + Grafana,因此我们需要在插件中加入Prometheus的Metrics.

注意: 以下只叙述概要,完整代码见vearne/skywalking-go

1)  PromOperator

首先需要修改Operator的全局定义

common.go

type Operator interface {
    Tracing() interface{}     // to TracingOperator
    Logger() interface{}      // to LogOperator
    Tools() interface{}       // to ToolsOperator
    DebugStack() []byte       // Getting the stack of the current goroutine, for getting details when plugin broken.
    Entity() interface{}      // Get the entity of the service
    Metrics() interface{}     // to MetricsOperator
    LogReporter() interface{} // to LogReporter
    // 增加PromMetrics
    PromMetrics() interface{} // to PromOperator
}

PromOperator的接口定义位于 prom.go

PromOperator的接口实现为PromWrapper, 位于prometheus.go

2)在plugin中(此处为gin) 使用Metrics的示例

intercepter.go

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/apache/skywalking-go/plugins/core/log"
    "github.com/apache/skywalking-go/plugins/core/operator"
    // 需要增加的import 
    "github.com/apache/skywalking-go/plugins/core/prom"
    "github.com/apache/skywalking-go/plugins/core/tracing"
)

type HTTPInterceptor struct {
}
...

func (h *HTTPInterceptor) AfterInvoke(invocation operator.Invocation, result ...interface{}) error {

    // add metrics
    httpReqTotal := prom.GetOrNewCounterVec(
        "gin_requests_total",
        "Total number of gin HTTP requests made",
        []string{"method", "path", "status"},
    )

    httpReqTotal.With(map[string]string{
        "method": context.Request.Method,
        "path":   context.Request.URL.Path,
        "status": fmt.Sprintf("%d", context.Writer.Status()),
    }).(prom.Counter).Inc()

    return nil
}

3)劫持 promhttp.Handler()

一般我们对prometheus的使用方式如下:

import (
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "log"
    "net/http"
)

var cpuTemp prometheus.Gauge

func main() {
    cpuTemp = prometheus.NewGauge(prometheus.GaugeOpts{
        Name: "cpu_temperature_celsius",
        Help: "Current temperature of the CPU.",
    })

    prometheus.MustRegister(cpuTemp)

    http.Handle("/metrics", promhttp.Handler())
    log.Fatal(http.ListenAndServe(":9090", nil))
}

prometheus.MustRegister()会把监控指标cpuTemp注册到prometheus.DefaultRegister上,为了使得插件中DefaultRegister和业务应用中使用Register是同一个,需要为Prometheus开发一个代码增强插件,劫持promhttp.Handler()

plugins/prometheus

import (
    "github.com/apache/skywalking-go/plugins/core/log"
    "github.com/apache/skywalking-go/plugins/core/operator"
    "github.com/apache/skywalking-go/plugins/core/prom"
    "github.com/prometheus/client_golang/prometheus"
)

type RegistryInterceptor struct {
}

func (h *RegistryInterceptor) BeforeInvoke(invocation operator.Invocation) error {

    return nil
}

func (h *RegistryInterceptor) AfterInvoke(invocation operator.Invocation, result ...interface{}) error {
    log.Infof("-----register prometheus------, %p\n", prometheus.DefaultRegisterer)
    prom.SetRegistry(prometheus.DefaultRegisterer)
    return nil
}

3.  业务应用

main.go

package main
import (
    "context"
    // 必须引入依赖包
    _ "github.com/apache/skywalking-go"
    "github.com/gin-gonic/gin"
    "github.com/go-resty/resty/v2"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "github.com/redis/go-redis/v9"
    zlog "github.com/vearne/zaplog"
    "go.uber.org/zap"
    "golang.org/x/sync/errgroup"
    "net/http"
)
var rdb *redis.Client
func main() {
    zlog.InitLogger("/tmp/aa.log", "debug")
    // 添加Prometheus的相关监控
    // /metrics
    go func() {
        r := gin.Default()
        /*
        promhttp.Handler()调用后
        prometheus.DefaultRegister会被注入到全局变量中
        */
        r.GET("/metrics", gin.WrapH(promhttp.Handler()))
        r.Run(":9090")
    }()
    //prometheus.NewRegistry()
    rdb = redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })
    r := gin.Default()
    r.GET("/hello", func(c *gin.Context) {
        ...
    })
    r.GET("/hello2", func(c *gin.Context) {
        ...
    })
    r.GET("/ping", func(c *gin.Context) {
        ...
    })
    r.Run(":8000")
}

注意: go.mod中 需要用replace引入萌叔改动后的Skywalking-go

replace github.com/apache/skywalking-go => github.com/vearne/skywalking-go v0.3.0-1
require (
    github.com/apache/skywalking-go v0.3.0-1
    ...
)

结果:监控指标使用正常

总结

Skywalking不仅仅可以用来增加tracing信息,它应该被视为一个非常强大的代码增强工具,具有很大的潜力。

以上就是Skywalking-go自动监控增强使用探究的详细内容,更多关于go Skywalking自动监控的资料请关注脚本之家其它相关文章!

相关文章

  • Golang程序漏洞检测器govulncheck的安装和使用

    Golang程序漏洞检测器govulncheck的安装和使用

    govulncheck 是一个命令行工具,可以帮助 Golang 开发者快速找到项目代码和依赖的模块中的安全漏洞,该工具可以分析源代码和二进制文件,识别代码中对这些漏洞的任何直接或间接调用,本文就给大家介绍一下govulncheck安装和使用,需要的朋友可以参考下
    2023-09-09
  • 使用VSCODE配置GO语言开发环境的完整步骤

    使用VSCODE配置GO语言开发环境的完整步骤

    Go语言是采用UTF8编码的,理论上使用任何文本编辑器都能做Go语言开发,大家可以根据自己的喜好自行选择,下面这篇文章主要给大家介绍了关于使用VSCODE配置GO语言开发环境的完整步骤,需要的朋友可以参考下
    2022-11-11
  • 在Linux系统中安装Go语言的详细教程

    在Linux系统中安装Go语言的详细教程

    这篇文章主要介绍了在Linux系统中安装Go语言的详细教程,由于国内很多人对谷歌的盲目追捧,导致Go语言在国内的人气远超国外...需要的朋友可以参考下
    2015-06-06
  • Golang中的泛型你真的了解吗

    Golang中的泛型你真的了解吗

    Golang 在 1.18 版本更新后引入了泛型,这是一个重要的更新,Gopher 万众瞩目,为 Golang 带来了更多的灵活性和可重用性,今天,我们将深入探讨泛型的概念、为什么需要泛型、泛型的语法,并探讨如何在实践中使用它
    2023-05-05
  • Golang高性能持久化解决方案BoltDB数据库介绍

    Golang高性能持久化解决方案BoltDB数据库介绍

    这篇文章主要为大家介绍了Golang高性能持久化解决方案BoltDB数据库介绍,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • go内置函数copy()的具体使用

    go内置函数copy()的具体使用

    当我们在Go语言中需要将一个切片的内容复制到另一个切片时,可以使用内置的copy()函数,本文就介绍了go内置函数copy()的具体使用,感兴趣的可以了解一下
    2023-08-08
  • golang中随机数rand的使用

    golang中随机数rand的使用

    本文主要介绍了golang中随机数rand的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • go语言数据类型之字符串string

    go语言数据类型之字符串string

    这篇文章介绍了go语言数据类型之字符串string,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • golang 获取字符串长度的案例

    golang 获取字符串长度的案例

    这篇文章主要介绍了golang 获取字符串长度的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 一文带你了解Golang中的泛型

    一文带你了解Golang中的泛型

    泛型是一种可以编写独立于使用的特定类型的代码的方法,可以通过编写函数或类型来使用一组类型中的任何一个,下面就来和大家聊聊Golang中泛型的使用吧
    2023-07-07

最新评论