从Golang的开源项目中学习不同的功能实现

缘起 最近看到有些go开源项目中的代码,看到其中的功能,故整理备用。 日志 Zap 带日志等级输出 代码源 https://github.com/illacloud/builder-backend/tree/main/internal/util var logger *zap.SugaredLogger type LogConfig struct { ILLA_LOG_LEVEL int `env:"ILLA_LOG_LEVEL" envDefault:"0"` } func init() { cfg := &LogConfig{} err := env.Parse(cfg) if err != nil { return } logConfig := zap.NewProductionConfig() logConfig.Level = zap.NewAtomicLevelAt(zapcore.Level(cfg.ILLA_LOG_LEVEL)) baseLogger, err := logConfig.Build() if err != nil { panic("failed to create the default logger: " + err.Error()) } logger = baseLogger.Sugar() } func NewSugardLogger() *zap.SugaredLogger { return logger } 账户验证 邮箱验证码 代码来自于illacloud,代码位置链接...

November 25, 2022 · 2 min · czyt

使用protoc-gen-star编写protoc插件

预备知识 需要安装的软件 protoc golang go 软件包 github.com/lyft/protoc-gen-star 插件调用步骤 protoc,PB编译器,使用一组标志(记录在protoc -h下)进行配置,并将一组文件作为参数交给它。在这种情况下,I标志可以被多次指定,是它在proto文件中用于导入依赖关系的查找路径。默认情况下,官方描述符protos已经被包含在内。 myplugin_out 告诉 protoc 使用 protoc-gen-myplugin protoc-plugin。这些插件会从系统的 PATH 环境变量中自动解析,或者可以用另一个标志明确指定。官方的protoc-plugins (例如,protoc-gen-python) 已经在protoc注册了。该标志的值是特定于特定插件的,但 :…/generated 后缀除外。这个后缀表示protoc将把该包生成的文件放在哪个根目录下(相对于当前工作目录)。然而,这个生成的输出目录不会传播给 protoc-gen-myplugin,所以它需要在标志的左边重复。PG* 通过一个 output_path 参数支持这一点。 protoc 解析传入的 proto 文件,确保它们在语法上是正确的,并加载任何导入的依赖项。它将这些文件和依赖关系转换成描述符 (它们本身就是 PB 消息),并创建一个 CodeGeneratorRequest (又是一个 PB)。protoc 将这个请求序列化,然后执行每个配置的 protoc-plugin,通过 stdin 发送有效载荷。 protoc-gen-myplugin 启动,接收请求的有效载荷,并将其解密。一个基于 PG* 的 protoc-plugin 有两个阶段。首先,PG* 对从 protoc 收到的 CodeGeneratorRequest 进行解密,并为每个文件和其包含的所有实体创建一个完全连接的抽象语法树 (AST)。为这个插件指定的任何参数也会被解析,以便以后使用。 当这一步完成后,PG*就会执行任何注册的模块,把构建的AST交给它。模块可以被写成生成人工制品(例如,文件),或者只是对所提供的图进行某种形式的验证而没有任何其他副作用。模块在针对PB的操作方面提供了极大的灵活性。 一旦所有的模块都被运行,PG*会将任何自定义的工件写入文件系统,或者将生成器特定的工件序列化为CodeGeneratorResponse并将数据发送到其stdout。这整个流程看起来像这样。 foo.proto → protoc → CodeGeneratorRequest → protoc-gen-myplugin → CodeGeneratorResponse → protoc → foo.pb.go 假设插件名称为diy,则需要编译程序为protoc-gen-diy,并将程序加入系统Path变量,通过下面的命令调用插件。 protoc -I ....

October 29, 2022 · 3 min · czyt

tailscale的泛型SingleFlight

源地址 tailscale仓库 完整代码如下 // Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package singleflight provides a duplicate function call suppression // mechanism....

September 23, 2022 · 5 min · czyt

Golang 默认的CGO参数编译导致的GLIBC错误

问题描述 使用go正常编译了Linux下的程序,放到服务器上报错 ./app: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by ./app) 解决 Google了下,发现相同的Issue,于是通过go env检查本机golang运行环境,发现CGO默认启用而且程序也不涉及CGO相关的东西,于是设置CGO参数为关闭。然后编译程序 CGO_ENABLED="0" go build -v 重新上传,运行OK.

August 30, 2022 · 1 min · czyt

golang http客户端使用自定义dns

摘自互联网 原文 package main import ( "context" "io/ioutil" "log" "net" "net/http" "time" ) func main() { var ( dnsResolverIP = "8.8.8.8:53" // Google DNS resolver. dnsResolverProto = "udp" // Protocol to use for the DNS resolver dnsResolverTimeoutMs = 5000 // Timeout (ms) for the DNS resolver (optional) ) dialer := &net.Dialer{ Resolver: &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ Timeout: time.Duration(dnsResolverTimeoutMs) * time....

August 22, 2022 · 1 min · czyt

go-kratos使用备忘

自定义接口返回内容 正常的响应序列化逻辑通过Response Encoder实现。 错误的序列化逻辑通过ErrorEncoder实现。 注意:自定义Encoder后,可能会遇到零值字段被忽略的情况,可以参考这个issue。具体的解决办法是 proto定义返回内容,然后将生成的类型在encoder中使用。 简单代码大致如下: proto定义 import "google/protobuf/any.proto"; // BaseResponse is the base response message BaseResponse{ int32 code = 1 [json_name = "code"]; google.protobuf.Any data = 2 [json_name = "data"]; } go代码 func CustomResponseEncoder() http.ServerOption { return http.ResponseEncoder(func(w http.ResponseWriter, r *http.Request, i interface{}) error { reply := &v1.BaseResponse{ Code: 0, } if m, ok := i.(proto.Message); ok { payload, err := anypb.New(m) if err != nil { return err } reply....

August 12, 2022 · 22 min · czyt

Protobuf golang小札

Oneof 如果您有许多字段的消息,并且最多可以同时设置一个字段,则可以使用Oneof功能来执行此行为并保存内存。一个字段就像常规字段一样,除了单一共享内存中的所有字段,最多可以同时设置一个字段。设置Oneof的任何成员都会自动清除所有其他成员。 ​ Google protobuf 文档#Oneof 示例proto 创建protoOneof.proto 的proto文件 syntax = "proto3"; package oneof_test; option go_package ='.;oneof'; message WeiboUser{ string user_id = 1; string user_nick = 2; } message DouyinUser{ string auth_token = 1; string nick_name = 2; } message User{ oneof user_source{ string weibo_url = 1; string douyin_url = 2; } oneof user_info{ WeiboUser weibo_user_info = 3; DouyinUser douyin_user_info = 4; } } 使用命令生成go代码 protoc --proto_path=. --go_out=paths=source_relative:./oneof ./protoOneof.proto 生成的protoOneof.pb.go代码如下:...

July 25, 2022 · 12 min · czyt

使用gotests生成表驱动测试

使用gotests可以很方便的生成表驱动测试代码,表驱动测试的具体内容,请参考go官方的wiki。下面是具体的使用方法。 安装 使用下面命令进行安装 go install github.com/cweill/gotests/[email protected] 如果是go1.16之前的版本,可以使用命令 go get -u github.com/cweill/gotests/...来进行安装。 使用 gotests支持的参数如下: Usage of C:\Users\czyt\go\bin\gotests.exe: -all generate tests for all functions and methods -excl string regexp. generate tests for functions and methods that don't match. Takes precedence over -only, -exported, and -all -exported generate tests for exported functions and methods. Takes precedence over -only and -all -i print test inputs in error messages -nosubtests disable generating tests using the Go 1....

July 22, 2022 · 2 min · czyt

Golang Expr不完全指南

安装 库的说明 Expr package provides an engine that can compile and evaluate expressions. An expression is a one-liner that returns a value (mostly, but not limited to, booleans). It is designed for simplicity, speed and safety. The purpose of the package is to allow users to use expressions inside configuration for more complex logic. It is a perfect candidate for the foundation of a business rule engine. 安装 go get -u /github....

July 13, 2022 · 9 min · czyt

Golang DSL参考

ANTLR 4 图书 The definitive ANTLR 4 reference (2014) 英文版下载 中文版下载 文章 使用ANTLR和Go实现DSL入门 手把手教你使用ANTLR和Go实现一门DSL语言part1 part2part3part4part5 Parsing with ANTLR 4 and Go 实例代码 bilibili gengine link go-zero link grule-rule-engine Others 图书 Writing A Compiler In Go Writing an Interpreter in Go µGo语言实现——从头开发一个迷你Go语言编译器 文章 Build your own DSL with Go & HCL How to Write Syntax Tree-Based Domain-Specific Languages in Go Handwritten Parsers & Lexers in Go goyacc实战 TiDB SQL Parser 的实现...

July 11, 2022 · 1 min · czyt