golang使用模板生成接口装饰器插件GoWrap的使用

GoWrap - Golang 接口装饰器生成工具

GoWrap 是一个命令行工具,它使用简单的模板为 Go 接口类型生成装饰器。通过 GoWrap,您可以轻松地在现有代码中添加指标、跟踪、回退、池等多种功能,只需几秒钟。

安装

CLI 安装

go install github.com/hexdigest/gowrap/cmd/gowrap@latest

作为模块安装

go get -u github.com/hexdigest/gowrap/cmd/gowrap

使用示例

基本使用

gowrap gen -p io -i Reader -t prometheus -o reader_with_metrics.go

这将为 io.Reader 接口生成一个包装了 Prometheus 指标的实现。

为本地包生成装饰器

gowrap gen -p ./connector -i Connector -t fallback -o ./connector/with_metrics.go

这将为 ./connector 子包中的 Connector 接口生成一个回退装饰器。

完整示例

下面是一个完整的示例,展示如何使用 GoWrap 为自定义接口生成装饰器:

  1. 首先定义一个接口:
// storage.go
package storage

type ItemStorage interface {
    GetItem(id string) (*Item, error)
    PutItem(item *Item) error
    DeleteItem(id string) error
}
  1. 使用 GoWrap 生成带有日志记录的装饰器:
gowrap gen -p ./storage -i ItemStorage -t log -o storage_with_logging.go
  1. 生成的代码可以这样使用:
package main

import (
    "log"
    "os"
    "./storage"
)

func main() {
    // 原始实现
    var baseStorage storage.ItemStorage = &storage.MyStorageImplementation{}
    
    // 包装后的实现
    loggedStorage := storage.NewItemStorageLogger(
        baseStorage,
        log.New(os.Stdout, "[storage] ", log.LstdFlags),
    )
    
    // 使用包装后的实现
    item, err := loggedStorage.GetItem("123")
    if err != nil {
        log.Fatal(err)
    }
    
    // ...
}

内置模板

GoWrap 提供了多种内置模板:

  • circuitbreaker: 在指定数量的连续错误后停止执行包装接口的方法,并在指定延迟后恢复执行
  • fallback: 接受源接口的多个实现,如果前一次尝试未在指定时间内返回结果,则并发运行每个实现
  • log: 使用标准日志包为源接口添加日志记录
  • logrus: 使用流行的 sirupsen/logrus 日志记录器为源接口添加日志记录
  • prometheus: 为源接口添加 Prometheus 指标
  • retry: 为源接口添加重试机制
  • timeout: 为每个接受上下文的方法添加可配置的超时

自定义模板

您可以编写自己的模板来为接口提供所需的功能。模板接收的结构信息由 TemplateInputs 结构体记录。

模板中可以使用以下自定义函数:

  • up: 返回所有字母大写的输入
  • down: 返回所有字母小写的输入
  • upFirst: 返回首字母大写的输入
  • downFirst: 返回首字母小写的输入
  • replace: 返回用第二个参数替换第一个参数所有出现的输入
  • snake: 返回输入的下划线表示形式

本地化模板

默认情况下,GoWrap 会在生成的代码中包含 //go:generate 指令。如果您使用了远程模板,可以将模板复制到本地文件:

gowrap template copy fallback templates/fallback

然后使用本地模板生成装饰器:

gowrap gen -p io -i Reader -t templates/fallback reader_with_fallback.go

GoWrap 是一个强大的工具,可以显著减少为接口添加横切关注点所需的样板代码量。通过使用模板系统,它可以灵活地适应各种需求。


更多关于golang使用模板生成接口装饰器插件GoWrap的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang使用模板生成接口装饰器插件GoWrap的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


GoWrap: 使用模板生成接口装饰器的Go工具

GoWrap是一个用于生成接口装饰器代码的Go工具,它通过模板驱动的方式自动为接口生成装饰器实现。下面我将详细介绍GoWrap的使用方法和示例代码。

安装GoWrap

首先安装GoWrap工具:

go install github.com/hexdigest/gowrap@latest

基本使用

1. 定义接口

假设我们有一个简单的接口:

// storage.go
package main

type Storage interface {
    Get(key string) ([]byte, error)
    Set(key string, value []byte) error
    Delete(key string) error
}

2. 生成装饰器

使用GoWrap为这个接口生成装饰器:

gowrap gen -p . -i Storage -t log -o storage_decorator.go

参数说明:

  • -p 指定包路径
  • -i 指定接口名
  • -t 指定模板(这里是log)
  • -o 输出文件名

3. 生成的装饰器代码

生成的storage_decorator.go文件会包含一个实现了Storage接口的结构体,并添加了日志功能:

// storage_decorator.go
package main

import (
    "log"
)

type StorageWithLog struct {
    base Storage
}

func NewStorageWithLog(base Storage) StorageWithLog {
    return StorageWithLog{
        base: base,
    }
}

func (d StorageWithLog) Get(key string) ([]byte, error) {
    log.Printf("Storage.Get called with key: %v", key)
    defer log.Printf("Storage.Get returned with key: %v", key)
    return d.base.Get(key)
}

func (d StorageWithLog) Set(key string, value []byte) error {
    log.Printf("Storage.Set called with key: %v", key)
    defer log.Printf("Storage.Set returned with key: %v", key)
    return d.base.Set(key, value)
}

func (d StorageWithLog) Delete(key string) error {
    log.Printf("Storage.Delete called with key: %v", key)
    defer log.Printf("Storage.Delete returned with key: %v", key)
    return d.base.Delete(key)
}

自定义模板

GoWrap的强大之处在于可以使用自定义模板。创建一个模板文件metrics.tmpl

// 自定义指标监控装饰器模板
package {{.Package}}

import (
    "time"
    "github.com/prometheus/client_golang/prometheus"
)

type {{.Interface}}WithMetrics struct {
    base {{.Interface}}
    requestCount *prometheus.CounterVec
    requestDuration *prometheus.HistogramVec
}

func New{{.Interface}}WithMetrics(
    base {{.Interface}},
    requestCount *prometheus.CounterVec,
    requestDuration *prometheus.HistogramVec,
) *{{.Interface}}WithMetrics {
    return &{{.Interface}}WithMetrics{
        base: base,
        requestCount: requestCount,
        requestDuration: requestDuration,
    }
}

{{range .Methods}}
func (d *{{$.Interface}}WithMetrics) {{.Name}}({{.Params}}) {{.Results}} {
    start := time.Now()
    d.requestCount.WithLabelValues("{{.Name}}").Inc()
    
    defer func() {
        d.requestDuration.WithLabelValues("{{.Name}}").Observe(time.Since(start).Seconds())
    }()
    
    {{if .ReturnsError}}return {{end}}d.base.{{.Name}}({{.ArgNames}})
}
{{end}}

然后使用自定义模板生成装饰器:

gowrap gen -p . -i Storage -t metrics.tmpl -o storage_metrics_decorator.go

常用模板

GoWrap提供了一些内置模板:

  1. log - 添加日志记录
  2. sync - 添加互斥锁
  3. retry - 添加重试逻辑
  4. fallback - 添加回退逻辑
  5. circuit - 添加熔断器模式

实际应用示例

package main

import (
    "log"
)

func main() {
    // 原始实现
    realStorage := &RealStorage{}
    
    // 添加日志装饰器
    loggedStorage := NewStorageWithLog(realStorage)
    
    // 使用装饰后的接口
    err := loggedStorage.Set("key", []byte("value"))
    if err != nil {
        log.Fatal(err)
    }
    
    data, err := loggedStorage.Get("key")
    if err != nil {
        log.Fatal(err)
    }
    
    log.Printf("Got data: %s", data)
}

// 实际存储实现
type RealStorage struct{}

func (s *RealStorage) Get(key string) ([]byte, error) {
    return []byte("data for " + key), nil
}

func (s *RealStorage) Set(key string, value []byte) error {
    return nil
}

func (s *RealStorage) Delete(key string) error {
    return nil
}

总结

GoWrap是一个强大的工具,可以:

  1. 通过模板自动生成装饰器代码
  2. 减少重复的样板代码
  3. 保持代码整洁和可维护性
  4. 方便地添加横切关注点(日志、监控、重试等)

通过合理使用GoWrap,你可以更专注于业务逻辑的实现,而将通用的装饰逻辑交给工具自动生成。

回到顶部