The Go instrumentor tool (Go SDK)#

The Go instrumentor is a command-line tool which transforms your source code to enable full SDK functionality when running in the Antithesis environment. The instrumentor provides assertion cataloging and coverage instrumentation.

  • Assertion cataloging: The instrumentor modifies your program so that at runtime it emits a catalog entry for every assertion you define (like Always(), Sometimes(), Unreachable(), etc.) Assertion cataloging is necessary for certain assertions to work.

  • Coverage instrumentation: The instrumentor adds coverage callbacks at every basic block in the program’s control flow and writes the transformed source files to a separate directory. These callbacks enable the Antithesis platform to test your program more effectively.

The Go instrumentor manipulates Go language code via a source transformation. This means the tool must be invoked in your own build or CI system before the source is compiled into binaries, packaged into containers, and uploaded to Antithesis. We’re happy to work with you to determine the best way to integrate the Go instrumentor into your build system. Contact us if you need help with this.

The Go instrumentor is distributed as part of the Antithesis Go SDK.

Setup#

Install the instrumentor as follows:

  1. Add the Antithesis SDK for Go to your Go module and install the instrumentor tool.

    go get github.com/antithesishq/antithesis-sdk-go@latest
    go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest
    go mod tidy
    

    Note

    These examples use the (generally recommended) version called latest. You might choose a specific version such as v0.2.7.

  2. Ensure you can run the instrumentor

    `go env GOPATH`/bin/antithesis-go-instrumentor
    

Using the instrumentor#

The instrumentor may be run in two modes: (1) assertion cataloging mode, where a command-line flag restricts the instrumentor to only cataloging assertions; and (2) coverage instrumentation and assertion cataloging mode, which is the default. The syntax and a short description of each mode follows. To see an overview of this tool, run antithesis-go-instrumentor --help.


Assertion cataloging mode#

antithesis-go-instrumentor -assert_only [options] go_project_dir
  • Arguments

    go_project_dir:

    The top-level directory of your Go project. Must contain a valid go.mod file

  • Options

    See common options below.

Assertion cataloging behavior (Cataloging only)#

The instrumentor generates a catalog file that should be compiled into your program, and which will register your assertions with Antithesis at program startup. The name of this catalog will be the Go module’s name with _antithesis_catalog.go appended. For example, 'myorg.com' becomes 'myorg.com_antithesis_catalog.go'.

By default this file is written into the same directory as the Go mod file, but you may use the -catalog_dir option to override this. At build time, the assertions catalog must be in the same directory as the source for the main package.

You must rerun the instrumentor every time you add new assertions so that these assertions may be cataloged.


Coverage instrumentation and assertion cataloging mode#

antithesis-go-instrumentor [options] go_project_dir target_dir
  • Arguments

    go_project_dir:

    The top-level directory of your Go project.

    target_dir:

    The directory to which the instrumentor will write its output. Must be an existing but empty directory. The instrumentor will generate three subdirectories: (1) customer, which contains the instrumented code and the assertion catalog, (2) symbols, which contains symbols information that must be copied to your configuration image, and (3) notifier, which contains an Antithesis runtime helper that will be compiled into your program.

  • Options

    -prefix string:

    A string to prepend to the symbol table

    Also see common options below.

Assertion cataloging behavior (Cataloging and instrumentation)#

The instrumentor generates a catalog file that should be compiled into your program, and which will register your assertions with Antithesis at program startup. The name of this catalog will be the Go module’s name with _antithesis_catalog.go appended. For example, 'myorg.com' becomes 'myorg.com_antithesis_catalog.go'.

By default this file is written into the same directory as the Go mod file, but you may use the -catalog_dir option to override this. At build time, the assertions catalog must be in the same directory as the source for the main package.

You must rerun the instrumentor every time you add new assertions so that these assertions may be cataloged.

Coverage instrumentation behavior#

As stated above, the instrumentor will create 'target_dir', which will include three subdirectories as described above: (1) customer, (2) symbols and (3) notifier. The instrumentor will perform the following steps:

Step 1. Code is instrumented

The instrumentor will first add coverage instrumentation to the code. It will instrument every .go file that is not excluded via exclude (see below). The original code is left in place and the instrumented code is written to customer.

Coverage instrumentation adds a function call to every basic block that is executed, for example:

func main() {
    __antithesis_instrumentation__.Notify(1)
    greet()
}

func greet() {
    __antithesis_instrumentation__.Notify(2)
    fmt.Println("Hello, world!")
}

You must rerun the instrumentor every time you add new basic blocks so that they may be instrumented.

Step 2. The symbol table is created

The symbol table information is generated in the symbols directory. The name of this file is derived from a hash of its contents.

Step 3. Notifier module is generated

The notifier module is generated in the notifier directory. The notifier package name is determined using the hash from the symbols table filename, and prefixed with ‘z’ to conform to go package name requirements. The notifier.go file is generated with this package name.

The generated notifier module named antithesis.notifier/zXXXXXXXXXXXX is added as a dependency to the instumented go program in customer.

Step 4. Copy all non-instrumented files

Copies all non-instrumented files from the go_project_dir to the 'target_dir' customer directory. The hierarchy of the copied files is preserved.

The complete modified program, including both instrumented and intentionally uninstrumented files, has now been written to the customer directory.

Warning

The Antithesis Go instrumentor uses the same parser as the Go compiler, which was not designed with source transformations in mind. Our goal is that the output folder be an exact copy of the input folder, with as many Go files instrumented as possible while erring on the side of being buildable over that of being fully instrumented.

Unfortunately, the abstract syntax tree that the Go parser creates does not handle comments well. Comments may shift into the wrong place when a modified AST is serialized again as a .go file. This may result in invalid Go source. The instrumentor tries to prevent this by stripping most comments. Unfortunately, some comments in Go affect the compiler’s behavior, especially in relation to native libraries. The Antithesis instrumentor implements special handling for such comments. If it determines that it cannot correctly instrument a particular file, it simply copies that file to the output directory. In the worst case, the user can explicitly exclude a problematic file or directory from being instrumented. In every case, the instrumentor will print a warning about every file that was passed through uninstrumented.

Contact us if you need help with this.

The Antithesis instrumentor will output a file ending in .sym.tsv, which must be copied to a top-level /symbols directory in the configuration image with the exact filename that is output by the instrumentor. For example if running the instrumentor on a piece of software called client produces a file called client-go-df2451fe9b4e.sym.tsv, then this should be copied to the configuration image at the location: /symbols/client-go-df2451fe9b4e.sym.tsv.


Common instrumentation options#

-V int:

Verbosity level 0-3, where 3 is highest. The default is 0.

-catalog_dir string:

The path to the directory where the assertion catalog will be generated. For example: /home/mydir. The default is the same directory that the go.mod file is located in.

-exclude string:

The full path to a text file that lists the files and directories to exclude from being scanned by the Go instrumentor. Excluded files and directories will not be instrumented and their assertions will not be cataloged. By default all the .go files in a Go module will be cataloged, excluding Go test files. (In particular, by default the instrumentor ignores all directories beginning with a . and it excludes any files ending in .pb.go and _test.go.)

The exclusion file must contain paths to the files or directories to exclude—these paths are relative to the Go project directory. The entries must be newline separated. Lines beginning with a “#” are ignored, and so are all-whitespace lines. One exclusion file might be:

new_feature.go
# This line does nothing
mypack/newstuff

Every file or directory that you attempt to exclude must exist. If you attempt to exclude nonexistent files or directories, the instrumentor will fail.

-instrumentor_version string:

The version of the SDK instrumentation package to require. The default is “latest” but you may also use e.g. “v0.2.10”.

-logfile string:

The full path to a file where the instrumentor will log messages. The default is stderr.

-version:

Outputs the current version of this application

-local_sdk_path:

Path to a local copy of the Antithesis SDK. Used for running the instrumentor without an internet connection. Most users will not need to do this.