go-instrumentation

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2024 License: MIT

README

Brief

This tool provides a simple mechanism for auto code instrumentation. User can provide at least one source code file, each file contains at least one global function(patch function), each function represents one instrumentation logic, and every function satifies patch function signature, then this tool will copy every function body to every source code function. Well, instrumentation is not simply copying code snippets, variables in function bodys will be rewritten, and source file imports will be resolved. It is very useful for tracing libaries.

Usage

For example, we write one file which contains only one patch function, package name or function name can be any name, but function signature must satisfiy patch function sigature.

package sample

// Patch Function Signature
import (
 gonativectx "context"
)

// general instrumentation function signature
ProcessFunc(spanName string, hasCtx bool, ctx gonativectx.Context, args ...interface{})

spanName was generated by parser, if hasCtx was true, user can use provided function param ctx, gonativectx is alias for go native context package, mainly for avoiding pkg name confliction. args represents args of the instrumented function, using interface{} other than any only for compatiblity.

NOTE: There should be only instrumentation functions in patch file, any global variables are not allowed.

User can ignore any fields other than spanName, for example, define one instrumentation function which is not nterested in ctx and function args.

package sample

import (
    gonativectx "context"
)

ProcessFunc(spanName string, _ bool, _ gonativectx.Context, _ ...interface{})

Build and instrument patch codes to source files.

go build -o go-instrument-tool ./cmd/

Example

We can instrument functions with go execution tracing logic easily using this tool, see demo/instrument_go_trace.go for more details.

First, we define one patch function:

func InstrumentGoTrace(spanName string, hasCtx bool, ctx gonativectx.Context, args ...interface{}) {
	fctx := gonativectx.TODO()
	var t *trace.Task
	if hasCtx {
		fctx = ctx
		ctx, t = trace.NewTask(fctx, spanName)
	} else {
		_, t = trace.NewTask(fctx, spanName)
	}
	logbin, _ := json.Marshal(args)
	trace.Logf(ctx, spanName, "function args: %s", string(logbin))
	defer t.End()
}

For every source code function, we use trace task to correlate each function, and logging function params, if source function contains context param, task context will be propagated for each callee function.

Then in main function, enable and start go tracing logic.

    f, err := os.Create("servertrace.out")
    if err != nil {
        log.Fatalf("failed to create trace output file: %v", err)
    }   
    defer func() {
        if err := f.Close(); err != nil {
            log.Fatalf("failed to close trace file: %v", err)
        }   
    }()

Now we can select source files to instrument.

// usage: find . -name "*.go"|grep -vE "test|example"|xargs -I {} go-instrument-tool -source={} -replace -patches=xxx/demo/instrument_go_trace.go

after executing, source files will be rewritten, and every function would be instrumented with go trace logic.

package main

import (
    gonativectx "context"
    "log"
    "os"

    "encoding/json"
    "runtime/trace"
)

func main() {
    spanNameinstrumentgotrace17251870431 := "test.go-main.main"
    hasCtxinstrumentgotrace17251870431 := false
    ctxinstrumentgotrace17251870431 := gonativectx.Background()
    argsinstrumentgotrace17251870431 := []interface {
    }{} 
    fctxinstrumentgotrace17251870431 := gonativectx.TODO()
    var tinstrumentgotrace17251870431 *trace.Task
    if hasCtxinstrumentgotrace17251870431 {
        fctxinstrumentgotrace17251870431 = ctxinstrumentgotrace17251870431
        ctxinstrumentgotrace17251870431, tinstrumentgotrace17251870431 = trace.NewTask(fctxinstrumentgotrace17251870431, spanNameinstrumentgotrace17251870431)
    } else {
        _, tinstrumentgotrace17251870431 = trace.NewTask(fctxinstrumentgotrace17251870431, spanNameinstrumentgotrace17251870431)
    }   
    logbininstrumentgotrace17251870431, _ := json.Marshal(argsinstrumentgotrace17251870431)
    trace.Logf(ctxinstrumentgotrace17251870431, spanNameinstrumentgotrace17251870431, "function args: %s", string(logbininstrumentgotrace17251870431))
    defer tinstrumentgotrace17251870431.End()

    f, err := os.Create("servertrace.out")
    if err != nil {
        log.Fatalf("failed to create trace output file: %v", err)
    }   
    defer func() {
        if err := f.Close(); err != nil {
            log.Fatalf("failed to close trace file: %v", err)
        }
    }() 
}

Directories

Path Synopsis
cmd
Package instrument rewrite source file via applying patch functions to source functions, and merge file import paths.
Package instrument rewrite source file via applying patch functions to source functions, and merge file import paths.
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL