Go instrumentor tool
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:
- 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
These examples use the (generally recommended) version called latest
. You might choose a specific version such as v0.2.7
.
- 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)
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)
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:
customer
symbols
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.
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
. This file should be copied into a directory named /symbols
in the root of the appropriate container image. This file must be copied with the exact filename that is output by the instrumentor. For example, suppose that running the instrumentor on software called client
produces the file client-go-df2451fe9b4e.sym.tsv
. In this case, the resulting file should be copied to /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.