This is not an officially supported Google product.
The project aims to collect Go function-level coverage with low overhead for any binary.
For context, the existing coverage in Go works only for tests, and only have the line-coverage, which can be too inefficient to run in a production environment.
Every file containing source code must include copyright and license information. This includes any JS/CSS files that you might be serving out to browsers. (This is to help well-intentioned people avoid accidental copying that doesn't comply with the license.)
Apache header:
Copyright 2020 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The goal is to collect production Go code coverage with low overhead. Coverage scope is function granularity. Function level run-time coverage data can be collected to:
- Detect dynamically dead code as functions never run in certain production jobs.
- Detect run-time dependencies of a test or of a production binary.
Compared to the current coverage implementations in Bazel for Go, our tools work for any binary and not for just unit tests.
Our aim is to integrate our coverage tools to Blaze as well. We are proposing a new instrumentation mode for Go with a new coverage mode build configuration for Go rules. Also a new option --embed_library
for Bazel, which will be useful for our purposes and will be useful for other use cases as well.
Go Function Coverage consists of two parts.
- Instrumenting sources to keep function execution data.
- Linking a collection library to the final binary that will write/upload the coverage data.
This repository implements an example program and two different handler libraries demonstrate the power of our coverage tools.
Install our version of Bazel.
You can install it from source. Follow this instructions.
Only thing you need to do is build the example program with "func" coverage mode. You need to embed example handler for "func" mode to the binary target as well.
$ bazel build --collect_code_coverage --embed_library=//packages/func-handler:example-handler //packages/program:example-program --@io_bazel_rules_go//go/config:covermode=func
This will generate an executable bazel-bin/packages/program/example-program_/example-program
.
When you run the binary, it will ask you to enter numbers in range [0-9]. For each number you enter program will execute F$number
function.
You can also use already existing coverage modes with covermode option. This repository implements a handler for already existing modes as well which you can find here.
$ bazel build --collect_code_coverage --embed_library=//packages/handler:example-handler //packages/program:example-program --@io_bazel_rules_go//go/config:covermode=[count | set | atomic]
Coverage data will be saved to coverage.out
for both examples.
-
Implement your handler library
- Handler library must implement a main package without the main() function.
--embed_library
option will embed this library to thego_binary
target.- It's
init()
function will start executing. - Instrumentation mode
"func"
defines an exit hook,FuncCoverExitHook
which points to an empty function with no paramteres. You can set it to your custom function and it will be called automatically just before program exits. - Please take a look at the example handlers for func and for set, count and atomic.
-
To be able to use new coverage mode and new options, you must load modified rules_go repository instead of official one in your WORKSPACE file. Please take look at the WORKSPACE in this repository.
-
Build your program with
"func"
coverage and your handler.
$ bazel build --collect_code_coverage --embed_library=//:your_handler //:your-program --@io_bazel_rules_go//go/config:covermode=func
Go Function Coverage tools consists of 2 parts, instrumentation and a handler. To collect production coverage data you need to have both.
Our instrumentation is built inside the rules_go. To be able to use it you need to use modified rules_go. You can set the coverage mode using new --@io_bazel_rules_go//go/config:covermode=mode
build configuration.
Other existing modes are
- set: did each statement run?
- count: how many times did each statement run?
- atomic: like count, but for parellel programs.
Handler is a package that implements reporting functionality. It will be embedded to the main package using new --embed_library
option in build time. To be able to use our new --embed_library
option, you need to install our modified version of bazel.
Its init()
function will be invoked when program starts executing. You can call your go routines that will report the coverage data inside it. Coverage data will be saved inside the coverdata
package during runtime. Please look at the examples for more clarification.