将 watchagent 从全局注入改为随 main 包注入

This commit is contained in:
lyyyuna 2021-08-10 22:50:30 +08:00 committed by Li Yiyang
parent c406e68e7d
commit d55c54d3a1
2 changed files with 73 additions and 104 deletions

View File

@ -1,4 +1,4 @@
package coverdef
package cover
import (
"fmt"
@ -6,19 +6,11 @@ import (
"os"
"log"
"strconv"
"strings"
"net/url"
"{{.GlobalCoverVarImportPath}}/websocket"
)
var (
watchChannel = make(chan *blockInfo, 1024)
watchEnabled = false
waitDelay time.Duration = 10 * time.Second
host string = "{{.Host}}"
_cover "{{.GlobalCoverVarImportPath}}"
)
func init() {
@ -55,7 +47,7 @@ func init() {
}
// 连接成功
watchEnabled = true
_cover.WatchEnabled_{{.Random}} = true
log.Printf("[goc][Info] watch connected to goc server")
ticker := time.NewTicker(time.Second)
@ -74,18 +66,18 @@ func init() {
Loop:
for {
select {
case block := <-watchChannel:
i := block.i
case block := <-_cover.WatchChannel_{{.Random}}:
i := block.I
cov := fmt.Sprintf("%s:%d.%d,%d.%d %d %d", block.name,
block.pos[3*i+0], uint16(block.pos[3*i+2]),
block.pos[3*i+1], uint16(block.pos[3*i+2] >> 16),
block.stmts,
cov := fmt.Sprintf("%s:%d.%d,%d.%d %d %d", block.Name,
block.Pos[3*i+0], uint16(block.Pos[3*i+2]),
block.Pos[3*i+1], uint16(block.Pos[3*i+2] >> 16),
block.Stmts,
1)
err = ws.WriteMessage(websocket.TextMessage, []byte(cov))
if err != nil {
watchEnabled = false
_cover.WatchEnabled_{{.Random}} = false
log.Println("[goc][Error] push coverage failed: %v", err)
time.Sleep(waitDelay)
break Loop
@ -99,56 +91,3 @@ func init() {
}
}()
}
// get process meta info for register
type processInfo struct {
hostname string
pid int
cmdline string
}
func getRegisterInfo() (*processInfo, error) {
hostname, err := os.Hostname()
if err != nil {
log.Printf("[goc][Error] fail to get hostname: %v", hostname)
return nil, err
}
pid := os.Getpid()
cmdline := strings.Join(os.Args, " ")
return &processInfo{
hostname: hostname,
pid: pid,
cmdline: cmdline,
}, nil
}
//
type blockInfo struct {
name string
pos []uint32
i int
stmts int
}
// UploadCoverChangeEvent_{{.Random}} is non-blocking
func UploadCoverChangeEvent_{{.Random}}(name string, pos []uint32, i int, stmts uint16) {
if watchEnabled == false {
return
}
// make sure send is non-blocking
select {
case watchChannel <- &blockInfo{
name: name,
pos: pos,
i: i,
stmts: int(stmts),
}:
default:
}
}

View File

@ -1,6 +1,7 @@
package cover
import (
"fmt"
"os"
"path"
"path/filepath"
@ -56,12 +57,7 @@ func Inject() {
}
// 在工程根目录注入所有插桩变量的声明+定义
injectGlobalCoverVarFile(allDecl)
// 在工程根目录注入 watch agent 的定义
if config.GocConfig.Mode == "watch" {
log.Infof("watch mode is enabled")
injectWatchAgentFile()
log.Donef("watch handler injected")
}
// 添加自定义 websocket 依赖
// 用户代码可能有 gorrila/websocket 的依赖,为避免依赖冲突,以及可能的 replace/vendor
// 这里直接注入一份完整的 gorrila/websocket 实现
@ -120,7 +116,8 @@ func getPkgTmpDir(pkgDir string) string {
// - goc-cover-agent-apis-auto-generated-11111-22222-bridge.go
// - goc-cover-agent-apis-auto-generated-11111-22222-package
// |
// -- init.go
// -- rpcagent.go
// -- watchagent.go
//
// 11111_22222_bridge.go 仅仅用于引用 11111_22222_package, where package contains ws agent main logic.
// 使用 bridge.go 文件是为了避免插桩逻辑中的变量名污染 main 包
@ -153,7 +150,7 @@ func injectGocAgent(where string, covers []*config.PackageCover) {
}
// create ws agent files
dest := filepath.Join(wherePkg, "init.go")
dest := filepath.Join(wherePkg, "rpcagent.go")
f2, err := os.Create(dest)
if err != nil {
@ -184,6 +181,29 @@ func injectGocAgent(where string, covers []*config.PackageCover) {
if err := coverMainTmpl.Execute(f2, tmplData); err != nil {
log.Fatalf("fail to generate cover agent handlers in temporary project: %v", err)
}
// 写入 watch
if config.GocConfig.Mode != "watch" {
return
}
f, err := os.Create(filepath.Join(wherePkg, "watchagent.go"))
if err != nil {
log.Fatalf("fail to create watchagent file: %v", err)
}
tmplwatchData := struct {
Random string
Host string
GlobalCoverVarImportPath string
}{
Random: filepath.Base(config.GocConfig.TmpModProjectDir),
Host: config.GocConfig.Host,
GlobalCoverVarImportPath: config.GocConfig.GlobalCoverVarImportPath,
}
if err := coverWatchTmpl.Execute(f, tmplwatchData); err != nil {
log.Fatalf("fail to generate watchagent in temporary project: %v", err)
}
}
// injectGlobalCoverVarFile 写入所有插桩变量的全局定义至一个单独的文件
@ -205,32 +225,42 @@ func injectGlobalCoverVarFile(decl string) {
packageName := "package coverdef\n\n"
_, err = coverFile.WriteString(packageName + decl)
random := filepath.Base(config.GocConfig.TmpModProjectDir)
varWatchDef := fmt.Sprintf(`
var WatchChannel_%v = make(chan *blockInfo, 1024)
var WatchEnabled_%v = false
type blockInfo struct {
Name string
Pos []uint32
I int
Stmts int
}
// UploadCoverChangeEvent_%v is non-blocking
func UploadCoverChangeEvent_%v(name string, pos []uint32, i int, stmts uint16) {
if WatchEnabled_%v == false {
return
}
// make sure send is non-blocking
select {
case WatchChannel_%v <- &blockInfo{
Name: name,
Pos: pos,
I: i,
Stmts: int(stmts),
}:
default:
}
}
`, random, random, random, random, random, random)
_, err = coverFile.WriteString(packageName + varWatchDef + decl)
if err != nil {
log.Fatalf("fail to write to global cover definition file: %v", err)
}
}
func injectWatchAgentFile() {
globalCoverVarPackage := path.Base(config.GocConfig.GlobalCoverVarImportPath)
globalCoverDef := filepath.Join(config.GocConfig.TmpModProjectDir, globalCoverVarPackage)
f, err := os.Create(filepath.Join(globalCoverDef, "watchagent.go"))
if err != nil {
log.Fatalf("fail to create watchagent file: %v", err)
}
tmplData := struct {
Random string
Host string
GlobalCoverVarImportPath string
}{
Random: filepath.Base(config.GocConfig.TmpModProjectDir),
Host: config.GocConfig.Host,
GlobalCoverVarImportPath: config.GocConfig.GlobalCoverVarImportPath,
}
if err := coverWatchTmpl.Execute(f, tmplData); err != nil {
log.Fatalf("fail to generate watchagent in temporary project: %v", err)
}
}