Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add instrgen implementation #3108

Merged
merged 15 commits into from Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/dependabot.yml
Expand Up @@ -199,6 +199,24 @@ updates:
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /instrgen/driver
labels:
- dependencies
- go
- Skip Changelog
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /instrgen/driver/testdata/interface
labels:
- dependencies
- go
- Skip Changelog
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /instrumentation/github.com/Shopify/sarama/otelsarama
labels:
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -10,7 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added

- Add the new `go.opentelemetry.io/contrib/instrgen` package to provide auto-generated source code instrumentation. (#3068)
- Add the new `go.opentelemetry.io/contrib/instrgen` package to provide auto-generated source code instrumentation. (#3068, #3108)

## [1.16.0-rc.2/0.41.0-rc.2/0.10.0-rc.2] - 2023-03-23

Expand Down
26 changes: 26 additions & 0 deletions instrgen/README.md
Expand Up @@ -6,6 +6,32 @@ This package provides a code generation utility that instruments existing source

:construction: This package is currently work in progress.

## How to use it

In order to instrument your project you have to add following call in your entry point function, usually main
(you can look at testdata directory for reference) and invoke instrgen tool.

```
func main() {
rtlib.AutotelEntryPoint()
```

Instrgen requires three parameters: command, path to project and package(s) pattern we
would like to instrument.

```
./instrgen --inject [path to your go project] [package(s) pattern]
```

Below concrete example with one of test instrumentation that is part of the project.

```
./instrgen --inject ./testdata/basic ./...
```

```./...``` works like wildcard in this case and it will instrument all packages in this path, but it can be invoked with
specific package as well.

### Compatibility

The `instrgen` utility is based on the Go standard library and is platform agnostic.
Expand Down
19 changes: 19 additions & 0 deletions instrgen/driver/go.mod
@@ -0,0 +1,19 @@
module go.opentelemetry.io/contrib/instrgen/instrgen

go 1.19

replace go.opentelemetry.io/contrib/instrgen => ../

require (
github.com/stretchr/testify v1.8.1
go.opentelemetry.io/contrib/instrgen v0.0.0-00010101000000-000000000000
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/tools v0.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
24 changes: 24 additions & 0 deletions instrgen/driver/go.sum
@@ -0,0 +1,24 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
118 changes: 118 additions & 0 deletions instrgen/driver/instrgen_test.go
@@ -0,0 +1,118 @@
// Copyright The OpenTelemetry Authors
//
// 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
//
// http://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.

//go:build !windows

package main

import (
"bytes"
"fmt"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

alib "go.opentelemetry.io/contrib/instrgen/lib"
)

var testcases = map[string]string{
"./testdata/basic": "./testdata/expected/basic",
"./testdata/selector": "./testdata/expected/selector",
"./testdata/interface": "./testdata/expected/interface",
}

var failures []string

func inject(t *testing.T, root string, packagePattern string) {
err := executeCommand("--inject-dump-ir", root, packagePattern)
require.NoError(t, err)
}

func Test(t *testing.T) {
for k, v := range testcases {
inject(t, k, "./...")
files := alib.SearchFiles(k, ".go_pass_tracing")
expectedFiles := alib.SearchFiles(v, ".go")
numOfFiles := len(expectedFiles)
fmt.Println("Go Files:", len(files))
fmt.Println("Expected Go Files:", len(expectedFiles))
numOfComparisons := 0
for _, file := range files {
fmt.Println(filepath.Base(file))
for _, expectedFile := range expectedFiles {
fmt.Println(filepath.Base(expectedFile))
if filepath.Base(file) == filepath.Base(expectedFile+"_pass_tracing") {
f1, err1 := os.ReadFile(file)
require.NoError(t, err1)
f2, err2 := os.ReadFile(expectedFile)
require.NoError(t, err2)
if !assert.True(t, bytes.Equal(f1, f2)) {
fmt.Println(k)
failures = append(failures, k)
}
numOfComparisons = numOfComparisons + 1
}
}
}
if numOfFiles != numOfComparisons {
fmt.Println("numberOfComparisons:", numOfComparisons)
panic("not all files were compared")
}
_, err := Prune(k, "./...", false)
if err != nil {
fmt.Println("Prune failed")
}
}
for _, f := range failures {
fmt.Println("FAILURE : ", f)
}
}

func TestCommands(t *testing.T) {
err := executeCommand("--dumpcfg", "./testdata/dummy", "./...")
require.NoError(t, err)
err = executeCommand("--rootfunctions", "./testdata/dummy", "./...")
require.NoError(t, err)
err = executeCommand("--prune", "./testdata/dummy", "./...")
require.NoError(t, err)
err = executeCommand("--inject", "./testdata/dummy", "./...")
require.NoError(t, err)
err = usage()
require.NoError(t, err)
}

func TestCallGraph(t *testing.T) {
cg := makeCallGraph("./testdata/dummy", "./...")
dumpCallGraph(cg)
assert.Equal(t, len(cg), 0, "callgraph should contain 0 elems")
rf := makeRootFunctions("./testdata/dummy", "./...")
dumpRootFunctions(rf)
assert.Equal(t, len(rf), 0, "rootfunctions set should be empty")
}

func TestArgs(t *testing.T) {
err := checkArgs(nil)
require.Error(t, err)
args := []string{"driver", "--inject", "", "./..."}
err = checkArgs(args)
require.NoError(t, err)
}

func TestUnknown(t *testing.T) {
err := executeCommand("unknown", "a", "b")
require.Error(t, err)
}