From ea147d98dd90c9b8b348f623c63fd5dd46887151 Mon Sep 17 00:00:00 2001 From: Przemek Delewski Date: Mon, 19 Dec 2022 13:29:18 +0100 Subject: [PATCH] Add instrgen implementation --- .github/dependabot.yml | 18 + instrgen/driver/driver_test.go | 99 ++++ instrgen/driver/go.mod | 25 + instrgen/driver/go.sum | 38 ++ instrgen/driver/main.go | 183 ++++++ instrgen/driver/passes.go | 52 ++ instrgen/driver/test/expected/fib/fib.go | 65 +++ instrgen/driver/test/expected/fib/main.go | 38 ++ instrgen/driver/test/expected/fib/traces.txt | 148 +++++ .../driver/test/expected/goroutines/main.go | 57 ++ .../test/expected/goroutines/traces.txt | 111 ++++ instrgen/driver/test/expected/methods/main.go | 82 +++ .../driver/test/expected/methods/traces.txt | 148 +++++ instrgen/driver/test/expected/package/main.go | 46 ++ .../driver/test/expected/package/traces.txt | 37 ++ .../test/expected/recursion/recursion.go | 46 ++ .../driver/test/expected/recursion/traces.txt | 259 +++++++++ .../driver/test/expected/selector/main.go | 56 ++ instrgen/driver/test/fib/fib.go | 54 ++ instrgen/driver/test/fib/main.go | 30 + .../test/funwithoutpathtoroot/driver.go | 35 ++ instrgen/driver/test/goroutines/main.go | 45 ++ instrgen/driver/test/methods/main.go | 64 +++ instrgen/driver/test/package/main.go | 38 ++ instrgen/driver/test/recursion/recursion.go | 35 ++ instrgen/driver/test/selector/main.go | 45 ++ instrgen/go.mod | 15 + instrgen/go.sum | 25 + instrgen/lib/analysis_pass.go | 133 +++++ instrgen/lib/callgraph.go | 504 +++++++++++++++++ instrgen/lib/context_propagation.go | 238 ++++++++ instrgen/lib/instrumentation.go | 533 ++++++++++++++++++ instrgen/lib/otel_pruning.go | 157 ++++++ instrgen/lib/tools.go | 70 +++ instrgen/rtlib/rtlib.go | 98 ++++ 35 files changed, 3627 insertions(+) create mode 100644 instrgen/driver/driver_test.go create mode 100644 instrgen/driver/go.mod create mode 100644 instrgen/driver/go.sum create mode 100644 instrgen/driver/main.go create mode 100644 instrgen/driver/passes.go create mode 100644 instrgen/driver/test/expected/fib/fib.go create mode 100644 instrgen/driver/test/expected/fib/main.go create mode 100644 instrgen/driver/test/expected/fib/traces.txt create mode 100644 instrgen/driver/test/expected/goroutines/main.go create mode 100644 instrgen/driver/test/expected/goroutines/traces.txt create mode 100644 instrgen/driver/test/expected/methods/main.go create mode 100644 instrgen/driver/test/expected/methods/traces.txt create mode 100644 instrgen/driver/test/expected/package/main.go create mode 100644 instrgen/driver/test/expected/package/traces.txt create mode 100644 instrgen/driver/test/expected/recursion/recursion.go create mode 100644 instrgen/driver/test/expected/recursion/traces.txt create mode 100644 instrgen/driver/test/expected/selector/main.go create mode 100644 instrgen/driver/test/fib/fib.go create mode 100644 instrgen/driver/test/fib/main.go create mode 100644 instrgen/driver/test/funwithoutpathtoroot/driver.go create mode 100644 instrgen/driver/test/goroutines/main.go create mode 100644 instrgen/driver/test/methods/main.go create mode 100644 instrgen/driver/test/package/main.go create mode 100644 instrgen/driver/test/recursion/recursion.go create mode 100644 instrgen/driver/test/selector/main.go create mode 100644 instrgen/go.sum create mode 100644 instrgen/lib/analysis_pass.go create mode 100644 instrgen/lib/callgraph.go create mode 100644 instrgen/lib/context_propagation.go create mode 100644 instrgen/lib/instrumentation.go create mode 100644 instrgen/lib/otel_pruning.go create mode 100644 instrgen/lib/tools.go create mode 100644 instrgen/rtlib/rtlib.go diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a0fb05c3366..cbd2b1dc1e9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -64,6 +64,24 @@ updates: schedule: interval: weekly day: sunday + - package-ecosystem: gomod + directory: /instrgen + labels: + - dependencies + - go + - Skip Changelog + 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: /instrumentation/github.com/Shopify/sarama/otelsarama labels: diff --git a/instrgen/driver/driver_test.go b/instrgen/driver/driver_test.go new file mode 100644 index 00000000000..100151ab1d0 --- /dev/null +++ b/instrgen/driver/driver_test.go @@ -0,0 +1,99 @@ +// 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. + +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{ + "./test/fib": "./test/expected/fib", + "./test/methods": "./test/expected/methods", + "./test/goroutines": "./test/expected/goroutines", + "./test/recursion": "./test/expected/recursion", + "./test/package": "./test/expected/package", + "./test/selector": "./test/expected/selector", +} + +var failures []string + +func inject(t *testing.T, root string, packagePattern string) { + var rootFunctions []alib.FuncDescriptor + + rootFunctions = append(rootFunctions, alib.FindRootFunctions(root, packagePattern)...) + interfaces := alib.FindInterfaces(root, packagePattern) + funcDecls := alib.FindFuncDecls(root, packagePattern, interfaces) + backwardCallGraph := alib.BuildCallGraph(root, packagePattern, funcDecls, interfaces) + + fmt.Println("\n\tchild parent") + for k, v := range backwardCallGraph { + fmt.Print("\n\t", k) + fmt.Print(" ", v) + } + fmt.Println("") + + analysis := &alib.Analysis{ProjectPath: root, + PackagePattern: packagePattern, + RootFunctions: rootFunctions, + FuncDecls: funcDecls, + Callgraph: backwardCallGraph, + Interfaces: interfaces, + Debug: false} + err := ExecutePasses(analysis) + require.NoError(t, err) +} + +func Test(t *testing.T) { + for k, v := range testcases { + inject(t, k, "./...") + files := alib.SearchFiles(k, ".go.input") + expectedFiles := alib.SearchFiles(v, ".go.expected") + numOfFiles := len(expectedFiles) + numOfComparisons := 0 + for _, file := range files { + for _, expectedFile := range expectedFiles { + fmt.Println(file) + fmt.Println(expectedFile) + if filepath.Base(file) == filepath.Base(expectedFile) { + 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 { + panic("not all files were compared") + } + Prune(k, "./...") + } + for _, f := range failures { + fmt.Println("FAILURE : ", f) + } +} diff --git a/instrgen/driver/go.mod b/instrgen/driver/go.mod new file mode 100644 index 00000000000..389a0d66aa8 --- /dev/null +++ b/instrgen/driver/go.mod @@ -0,0 +1,25 @@ +module go.opentelemetry.io/contrib/instrgen/driver + +go 1.18 + +replace go.opentelemetry.io/contrib/instrgen => ../ + +require ( + github.com/stretchr/testify v1.8.1 + go.opentelemetry.io/contrib/instrgen v0.0.0-00010101000000-000000000000 + go.opentelemetry.io/otel v1.11.2 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2 // indirect + go.opentelemetry.io/otel/sdk v1.11.2 // indirect + go.opentelemetry.io/otel/trace v1.11.2 // 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 +) diff --git a/instrgen/driver/go.sum b/instrgen/driver/go.sum new file mode 100644 index 00000000000..f029404273e --- /dev/null +++ b/instrgen/driver/go.sum @@ -0,0 +1,38 @@ +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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +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= +go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= +go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2 h1:BhEVgvuE1NWLLuMLvC6sif791F45KFHi5GhOs1KunZU= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2/go.mod h1:bx//lU66dPzNT+Y0hHA12ciKoMOH9iixEwCqC1OeQWQ= +go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= +go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= +go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= +go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= +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= diff --git a/instrgen/driver/main.go b/instrgen/driver/main.go new file mode 100644 index 00000000000..59795ad3722 --- /dev/null +++ b/instrgen/driver/main.go @@ -0,0 +1,183 @@ +// 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. + +package main + +import ( + "fmt" + "log" + "os" + + alib "go.opentelemetry.io/contrib/instrgen/lib" +) + +func usage() { + fmt.Println("\nusage autotel --command [path to go project] [package pattern]") + fmt.Println("\tcommand:") + fmt.Println("\t\tinject (injects open telemetry calls into project code)") + fmt.Println("\t\tinject-dump-ir (injects open telemetry calls into project code and intermediate passes)") + fmt.Println("\t\tprune (prune open telemetry calls") + fmt.Println("\t\tdumpcfg (dumps control flow graph)") + fmt.Println("\t\tgencfg (generates json representation of control flow graph)") + fmt.Println("\t\trootfunctions (dumps root functions)") +} + +// Prune. +func Prune(projectPath string, packagePattern string) { + var rootFunctions []alib.FuncDescriptor + + interfaces := alib.FindInterfaces(projectPath, packagePattern) + rootFunctions = append(rootFunctions, alib.FindRootFunctions(projectPath, packagePattern)...) + funcDecls := alib.FindFuncDecls(projectPath, packagePattern, interfaces) + backwardCallGraph := alib.BuildCallGraph(projectPath, packagePattern, funcDecls, interfaces) + fmt.Println("\n\tchild parent") + for k, v := range backwardCallGraph { + fmt.Print("\n\t", k) + fmt.Print(" ", v) + } + fmt.Println("") + analysis := &alib.Analysis{ + ProjectPath: projectPath, + PackagePattern: packagePattern, + RootFunctions: rootFunctions, + FuncDecls: funcDecls, + Callgraph: backwardCallGraph, + Interfaces: interfaces, + Debug: false} + err := analysis.Execute(&alib.OtelPruner{}, otelPrunerPassSuffix) + if err != nil { + log.Println("Pruning failed") + } else { + fmt.Println("\tpruning done") + } +} + +// Parsing algorithm works as follows. It goes through all function +// decls and infer function bodies to find call to AutotelEntryPoint +// A parent function of this call will become root of instrumentation +// Each function call from this place will be instrumented automatically + +func executeCommand(arglist []string) { + if arglist[1] == "--inject" { + projectPath := arglist[2] + packagePattern := arglist[3] + Prune(projectPath, packagePattern) + var rootFunctions []alib.FuncDescriptor + + interfaces := alib.FindInterfaces(projectPath, packagePattern) + rootFunctions = append(rootFunctions, alib.FindRootFunctions(projectPath, packagePattern)...) + funcDecls := alib.FindFuncDecls(projectPath, packagePattern, interfaces) + backwardCallGraph := alib.BuildCallGraph(projectPath, packagePattern, funcDecls, interfaces) + fmt.Println("\n\tchild parent") + for k, v := range backwardCallGraph { + fmt.Print("\n\t", k) + fmt.Print(" ", v) + } + fmt.Println("") + analysis := &alib.Analysis{ + ProjectPath: projectPath, + PackagePattern: packagePattern, + RootFunctions: rootFunctions, + FuncDecls: funcDecls, + Callgraph: backwardCallGraph, + Interfaces: interfaces, + Debug: false} + err := ExecutePasses(analysis) + if err != nil { + log.Println("Analysis failed") + } else { + fmt.Println("\tinstrumentation done") + } + } + if arglist[1] == "--inject-dump-ir" { + projectPath := arglist[2] + packagePattern := arglist[3] + Prune(projectPath, packagePattern) + var rootFunctions []alib.FuncDescriptor + + interfaces := alib.FindInterfaces(projectPath, packagePattern) + rootFunctions = append(rootFunctions, alib.FindRootFunctions(projectPath, packagePattern)...) + funcDecls := alib.FindFuncDecls(projectPath, packagePattern, interfaces) + backwardCallGraph := alib.BuildCallGraph(projectPath, packagePattern, funcDecls, interfaces) + fmt.Println("\n\tchild parent") + for k, v := range backwardCallGraph { + fmt.Print("\n\t", k) + fmt.Print(" ", v) + } + fmt.Println("") + analysis := &alib.Analysis{ + ProjectPath: projectPath, + PackagePattern: packagePattern, + RootFunctions: rootFunctions, + FuncDecls: funcDecls, + Callgraph: backwardCallGraph, + Interfaces: interfaces, + Debug: true} + err := ExecutePassesDumpIr(analysis) + if err != nil { + log.Println("Analysis failed") + } else { + fmt.Println("\tinstrumentation done") + } + } + if arglist[1] == "--dumpcfg" { + projectPath := arglist[2] + packagePattern := arglist[3] + var funcDecls map[alib.FuncDescriptor]bool + var backwardCallGraph map[alib.FuncDescriptor][]alib.FuncDescriptor + + interfaces := alib.FindInterfaces(projectPath, packagePattern) + funcDecls = alib.FindFuncDecls(projectPath, packagePattern, interfaces) + backwardCallGraph = alib.BuildCallGraph(projectPath, packagePattern, funcDecls, interfaces) + fmt.Println("\n\tchild parent") + for k, v := range backwardCallGraph { + fmt.Print("\n\t", k) + fmt.Print(" ", v) + } + } + if arglist[1] == "--gencfg" { + projectPath := arglist[2] + packagePattern := arglist[3] + var funcDecls map[alib.FuncDescriptor]bool + var backwardCallGraph map[alib.FuncDescriptor][]alib.FuncDescriptor + interfaces := alib.FindInterfaces(projectPath, packagePattern) + funcDecls = alib.FindFuncDecls(projectPath, packagePattern, interfaces) + backwardCallGraph = alib.BuildCallGraph(projectPath, packagePattern, funcDecls, interfaces) + alib.Generatecfg(backwardCallGraph, "callgraph.js") + } + if arglist[1] == "--rootfunctions" { + projectPath := arglist[2] + packagePattern := arglist[3] + var rootFunctions []alib.FuncDescriptor + rootFunctions = append(rootFunctions, alib.FindRootFunctions(projectPath, packagePattern)...) + fmt.Println("rootfunctions:") + for _, fun := range rootFunctions { + fmt.Println("\t" + fun.TypeHash()) + } + } + if arglist[1] == "--prune" { + projectPath := arglist[2] + packagePattern := arglist[3] + Prune(projectPath, packagePattern) + } +} + +func main() { + fmt.Println("autotel compiler") + if len(os.Args) != 4 { + usage() + os.Exit(-1) + } + executeCommand(os.Args) +} diff --git a/instrgen/driver/passes.go b/instrgen/driver/passes.go new file mode 100644 index 00000000000..7df0f364d64 --- /dev/null +++ b/instrgen/driver/passes.go @@ -0,0 +1,52 @@ +// 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. + +package main + +import ( + "fmt" + + "go.opentelemetry.io/contrib/instrgen/lib" +) + +const ( + otelPrunerPassSuffix = "_pass_pruner.go" + contextPassFileSuffix = "_pass_ctx.go" + instrumentationPassFileSuffix = "_pass_tracing.go" +) + +// ExecutePassesDumpIr. +func ExecutePassesDumpIr(analysis *lib.Analysis) error { + fmt.Println("Instrumentation") + err := analysis.Execute(&lib.InstrumentationPass{}, instrumentationPassFileSuffix) + if err != nil { + return err + } + + fmt.Println("ContextPropagation") + err = analysis.Execute(&lib.ContextPropagationPass{}, contextPassFileSuffix) + return err +} + +// ExecutePasses. +func ExecutePasses(analysis *lib.Analysis) error { + fmt.Println("Instrumentation") + err := analysis.Execute(&lib.InstrumentationPass{}, instrumentationPassFileSuffix) + if err != nil { + return err + } + fmt.Println("ContextPropagation") + err = analysis.Execute(&lib.ContextPropagationPass{}, contextPassFileSuffix) + return err +} diff --git a/instrgen/driver/test/expected/fib/fib.go b/instrgen/driver/test/expected/fib/fib.go new file mode 100644 index 00000000000..0298cc218ff --- /dev/null +++ b/instrgen/driver/test/expected/fib/fib.go @@ -0,0 +1,65 @@ +// 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 exclude + +//nolint:all +package main + +import ( + __atel_context "context" + "fmt" + + __atel_otel "go.opentelemetry.io/otel" +) + +func foo(__atel_tracing_ctx __atel_context.Context) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("foo").Start(__atel_tracing_ctx, "foo") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + fmt.Println("foo") +} + +func FibonacciHelper(__atel_tracing_ctx __atel_context.Context, n uint) (uint64, error) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("FibonacciHelper").Start(__atel_tracing_ctx, "FibonacciHelper") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + func() { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("anonymous").Start(__atel_child_tracing_ctx, "anonymous") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + foo(__atel_child_tracing_ctx) + }() + return Fibonacci(__atel_child_tracing_ctx, n) +} + +func Fibonacci(__atel_tracing_ctx __atel_context.Context, n uint) (uint64, error) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("Fibonacci").Start(__atel_tracing_ctx, "Fibonacci") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + if n <= 1 { + return uint64(n), nil + } + + if n > 93 { + return 0, fmt.Errorf("unsupported fibonacci number %d: too large", n) + } + + var n2, n1 uint64 = 0, 1 + for i := uint(2); i < n; i++ { + n2, n1 = n1, n1+n2 + } + + return n2 + n1, nil +} diff --git a/instrgen/driver/test/expected/fib/main.go b/instrgen/driver/test/expected/fib/main.go new file mode 100644 index 00000000000..1a442badcfd --- /dev/null +++ b/instrgen/driver/test/expected/fib/main.go @@ -0,0 +1,38 @@ +// 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 exclude + +//nolint:all +package main + +import ( + __atel_context "context" + "fmt" + + "go.opentelemetry.io/contrib/instrgen/rtlib" + __atel_otel "go.opentelemetry.io/otel" +) + +func main() { + __atel_ts := rtlib.NewTracingState() + defer rtlib.Shutdown(__atel_ts) + __atel_otel.SetTracerProvider(__atel_ts.Tp) + __atel_ctx := __atel_context.Background() + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + rtlib.AutotelEntryPoint() + fmt.Println(FibonacciHelper(__atel_child_tracing_ctx, 10)) +} diff --git a/instrgen/driver/test/expected/fib/traces.txt b/instrgen/driver/test/expected/fib/traces.txt new file mode 100644 index 00000000000..ecf2f9e541f --- /dev/null +++ b/instrgen/driver/test/expected/fib/traces.txt @@ -0,0 +1,148 @@ +{ + "Name": "foo", + "SpanContext": { + "TraceID": "374c11217817c32b01876bb2e2aceae8", + "SpanID": "8c982b3e435c56e0", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "374c11217817c32b01876bb2e2aceae8", + "SpanID": "65c37661e2869798", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "foo", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "Fibonacci", + "SpanContext": { + "TraceID": "374c11217817c32b01876bb2e2aceae8", + "SpanID": "6676950f24fe09e2", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "374c11217817c32b01876bb2e2aceae8", + "SpanID": "65c37661e2869798", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "Fibonacci", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "FibonacciHelper", + "SpanContext": { + "TraceID": "374c11217817c32b01876bb2e2aceae8", + "SpanID": "65c37661e2869798", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "374c11217817c32b01876bb2e2aceae8", + "SpanID": "89a2f3b8fc474d6a", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 2, + "Resource": null, + "InstrumentationLibrary": { + "Name": "FibonacciHelper", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "main", + "SpanContext": { + "TraceID": "374c11217817c32b01876bb2e2aceae8", + "SpanID": "89a2f3b8fc474d6a", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "00000000000000000000000000000000", + "SpanID": "0000000000000000", + "TraceFlags": "00", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 1, + "Resource": null, + "InstrumentationLibrary": { + "Name": "main", + "Version": "", + "SchemaURL": "" + } +} diff --git a/instrgen/driver/test/expected/goroutines/main.go b/instrgen/driver/test/expected/goroutines/main.go new file mode 100644 index 00000000000..7f54757c4dd --- /dev/null +++ b/instrgen/driver/test/expected/goroutines/main.go @@ -0,0 +1,57 @@ +// 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 exclude + +//nolint:all +package main + +import ( + __atel_context "context" + "fmt" + + "go.opentelemetry.io/contrib/instrgen/rtlib" + __atel_otel "go.opentelemetry.io/otel" +) + +func foo(__atel_tracing_ctx __atel_context.Context) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("foo").Start(__atel_tracing_ctx, "foo") + _ = __atel_child_tracing_ctx + defer __atel_span.End() +} + +func main() { + __atel_ts := rtlib.NewTracingState() + defer rtlib.Shutdown(__atel_ts) + __atel_otel.SetTracerProvider(__atel_ts.Tp) + __atel_ctx := __atel_context.Background() + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + rtlib.AutotelEntryPoint() + messages := make(chan string) + + go func() { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("anonymous").Start(__atel_child_tracing_ctx, "anonymous") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + messages <- "ping" + }() + + foo(__atel_child_tracing_ctx) + + msg := <-messages + fmt.Println(msg) + +} diff --git a/instrgen/driver/test/expected/goroutines/traces.txt b/instrgen/driver/test/expected/goroutines/traces.txt new file mode 100644 index 00000000000..9a8a461d078 --- /dev/null +++ b/instrgen/driver/test/expected/goroutines/traces.txt @@ -0,0 +1,111 @@ +{ + "Name": "foo", + "SpanContext": { + "TraceID": "ed39b601dfc653a1af2d201580524e04", + "SpanID": "46beedbba3f44afd", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "ed39b601dfc653a1af2d201580524e04", + "SpanID": "4667d6ee96cebbd3", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "foo", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "anonymous", + "SpanContext": { + "TraceID": "ed39b601dfc653a1af2d201580524e04", + "SpanID": "761d4271fbd42829", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "ed39b601dfc653a1af2d201580524e04", + "SpanID": "4667d6ee96cebbd3", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "anonymous", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "main", + "SpanContext": { + "TraceID": "ed39b601dfc653a1af2d201580524e04", + "SpanID": "4667d6ee96cebbd3", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "00000000000000000000000000000000", + "SpanID": "0000000000000000", + "TraceFlags": "00", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 2, + "Resource": null, + "InstrumentationLibrary": { + "Name": "main", + "Version": "", + "SchemaURL": "" + } +} diff --git a/instrgen/driver/test/expected/methods/main.go b/instrgen/driver/test/expected/methods/main.go new file mode 100644 index 00000000000..99b44312e53 --- /dev/null +++ b/instrgen/driver/test/expected/methods/main.go @@ -0,0 +1,82 @@ +// 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 exclude + +//nolint:all +package main + +import ( + __atel_context "context" + + "go.opentelemetry.io/contrib/instrgen/rtlib" + __atel_otel "go.opentelemetry.io/otel" +) + +type element struct { +} + +type driver struct { + e element +} + +type i interface { + foo(__atel_tracing_ctx __atel_context.Context, p int) int +} + +type impl struct { +} + +func (i impl) foo(__atel_tracing_ctx __atel_context.Context, p int) int { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("foo").Start(__atel_tracing_ctx, "foo") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + return 5 +} + +func foo(p int) int { + return 1 +} + +func (d driver) process(__atel_tracing_ctx __atel_context.Context, a int) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("process").Start(__atel_tracing_ctx, "process") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + +} + +func (e element) get(__atel_tracing_ctx __atel_context.Context, a int) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("get").Start(__atel_tracing_ctx, "get") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + +} + +func main() { + __atel_ts := rtlib.NewTracingState() + defer rtlib.Shutdown(__atel_ts) + __atel_otel.SetTracerProvider(__atel_ts.Tp) + __atel_ctx := __atel_context.Background() + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + + rtlib.AutotelEntryPoint() + d := driver{} + d.process(__atel_child_tracing_ctx, 10) + d.e.get(__atel_child_tracing_ctx, 5) + var in i + in = impl{} + in.foo(__atel_child_tracing_ctx, 10) +} diff --git a/instrgen/driver/test/expected/methods/traces.txt b/instrgen/driver/test/expected/methods/traces.txt new file mode 100644 index 00000000000..3a69222b60f --- /dev/null +++ b/instrgen/driver/test/expected/methods/traces.txt @@ -0,0 +1,148 @@ +{ + "Name": "process", + "SpanContext": { + "TraceID": "89e24b204157ed68a6374f050991d378", + "SpanID": "b89f206f686a8a63", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "89e24b204157ed68a6374f050991d378", + "SpanID": "196142f06e386892", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "process", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "get", + "SpanContext": { + "TraceID": "89e24b204157ed68a6374f050991d378", + "SpanID": "6215269b7e32fe21", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "89e24b204157ed68a6374f050991d378", + "SpanID": "196142f06e386892", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "get", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "foo", + "SpanContext": { + "TraceID": "89e24b204157ed68a6374f050991d378", + "SpanID": "152c58c026034105", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "89e24b204157ed68a6374f050991d378", + "SpanID": "196142f06e386892", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "foo", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "main", + "SpanContext": { + "TraceID": "89e24b204157ed68a6374f050991d378", + "SpanID": "196142f06e386892", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "00000000000000000000000000000000", + "SpanID": "0000000000000000", + "TraceFlags": "00", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 3, + "Resource": null, + "InstrumentationLibrary": { + "Name": "main", + "Version": "", + "SchemaURL": "" + } +} diff --git a/instrgen/driver/test/expected/package/main.go b/instrgen/driver/test/expected/package/main.go new file mode 100644 index 00000000000..73f4a4a5d16 --- /dev/null +++ b/instrgen/driver/test/expected/package/main.go @@ -0,0 +1,46 @@ +// 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 exclude + +//nolint:all +package main + +import ( + __atel_context "context" + "os" + + "go.opentelemetry.io/contrib/instrgen/rtlib" + __atel_otel "go.opentelemetry.io/otel" +) + +func Close() error { + return nil +} + +func main() { + __atel_ts := rtlib.NewTracingState() + defer rtlib.Shutdown(__atel_ts) + __atel_otel.SetTracerProvider(__atel_ts.Tp) + __atel_ctx := __atel_context.Background() + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + rtlib.AutotelEntryPoint() + f, e := os.Create("temp") + defer f.Close() + if e != nil { + + } +} diff --git a/instrgen/driver/test/expected/package/traces.txt b/instrgen/driver/test/expected/package/traces.txt new file mode 100644 index 00000000000..fb9dc2adce5 --- /dev/null +++ b/instrgen/driver/test/expected/package/traces.txt @@ -0,0 +1,37 @@ +{ + "Name": "main", + "SpanContext": { + "TraceID": "5595ce412c3da83c9cebb3917f08cf58", + "SpanID": "bdf9407bbf75a56c", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "00000000000000000000000000000000", + "SpanID": "0000000000000000", + "TraceFlags": "00", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "main", + "Version": "", + "SchemaURL": "" + } +} diff --git a/instrgen/driver/test/expected/recursion/recursion.go b/instrgen/driver/test/expected/recursion/recursion.go new file mode 100644 index 00000000000..8d0f50d60be --- /dev/null +++ b/instrgen/driver/test/expected/recursion/recursion.go @@ -0,0 +1,46 @@ +// 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 exclude + +//nolint:all +package main + +import ( + __atel_context "context" + + "go.opentelemetry.io/contrib/instrgen/rtlib" + __atel_otel "go.opentelemetry.io/otel" +) + +func recur(__atel_tracing_ctx __atel_context.Context, n int) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("recur").Start(__atel_tracing_ctx, "recur") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + if n > 0 { + recur(__atel_child_tracing_ctx, n-1) + } +} + +func main() { + __atel_ts := rtlib.NewTracingState() + defer rtlib.Shutdown(__atel_ts) + __atel_otel.SetTracerProvider(__atel_ts.Tp) + __atel_ctx := __atel_context.Background() + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + rtlib.AutotelEntryPoint() + recur(__atel_child_tracing_ctx, 5) +} diff --git a/instrgen/driver/test/expected/recursion/traces.txt b/instrgen/driver/test/expected/recursion/traces.txt new file mode 100644 index 00000000000..1d7eb7fb9bf --- /dev/null +++ b/instrgen/driver/test/expected/recursion/traces.txt @@ -0,0 +1,259 @@ +{ + "Name": "recur", + "SpanContext": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "f7072f1c443491d3", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "4f868529fdeddcfa", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 0, + "Resource": null, + "InstrumentationLibrary": { + "Name": "recur", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "recur", + "SpanContext": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "4f868529fdeddcfa", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "9ba267d15a2df848", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 1, + "Resource": null, + "InstrumentationLibrary": { + "Name": "recur", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "recur", + "SpanContext": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "9ba267d15a2df848", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "d01b017c4592b65b", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 1, + "Resource": null, + "InstrumentationLibrary": { + "Name": "recur", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "recur", + "SpanContext": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "d01b017c4592b65b", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "1b22106503e01007", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 1, + "Resource": null, + "InstrumentationLibrary": { + "Name": "recur", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "recur", + "SpanContext": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "1b22106503e01007", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "673c5c2f4a18d412", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 1, + "Resource": null, + "InstrumentationLibrary": { + "Name": "recur", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "recur", + "SpanContext": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "673c5c2f4a18d412", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "8cf8d618faf53859", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 1, + "Resource": null, + "InstrumentationLibrary": { + "Name": "recur", + "Version": "", + "SchemaURL": "" + } +} +{ + "Name": "main", + "SpanContext": { + "TraceID": "898ffa664b45f09ba6de96a592079305", + "SpanID": "8cf8d618faf53859", + "TraceFlags": "01", + "TraceState": "", + "Remote": false + }, + "Parent": { + "TraceID": "00000000000000000000000000000000", + "SpanID": "0000000000000000", + "TraceFlags": "00", + "TraceState": "", + "Remote": false + }, + "SpanKind": 1, + "StartTime": "0001-01-01T00:00:00Z", + "EndTime": "0001-01-01T00:00:00Z", + "Attributes": null, + "Events": null, + "Links": null, + "Status": { + "Code": "Unset", + "Description": "" + }, + "DroppedAttributes": 0, + "DroppedEvents": 0, + "DroppedLinks": 0, + "ChildSpanCount": 1, + "Resource": null, + "InstrumentationLibrary": { + "Name": "main", + "Version": "", + "SchemaURL": "" + } +} diff --git a/instrgen/driver/test/expected/selector/main.go b/instrgen/driver/test/expected/selector/main.go new file mode 100644 index 00000000000..df25c810a02 --- /dev/null +++ b/instrgen/driver/test/expected/selector/main.go @@ -0,0 +1,56 @@ +// 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 exclude + +//nolint:all +package main + +import ( + __atel_context "context" + + "go.opentelemetry.io/contrib/instrgen/rtlib" + __atel_otel "go.opentelemetry.io/otel" +) + +type Driver interface { + Foo(__atel_tracing_ctx __atel_context.Context, i int) +} + +type Impl struct { +} + +func (impl Impl) Foo(__atel_tracing_ctx __atel_context.Context, i int) { + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("Foo").Start(__atel_tracing_ctx, "Foo") + _ = __atel_child_tracing_ctx + defer __atel_span.End() +} + +func main() { + __atel_ts := rtlib.NewTracingState() + defer rtlib.Shutdown(__atel_ts) + __atel_otel.SetTracerProvider(__atel_ts.Tp) + __atel_ctx := __atel_context.Background() + __atel_child_tracing_ctx, __atel_span := __atel_otel.Tracer("main").Start(__atel_ctx, "main") + _ = __atel_child_tracing_ctx + defer __atel_span.End() + rtlib.AutotelEntryPoint() + a := []Driver{ + Impl{}, + } + var d Driver + d = Impl{} + d.Foo(__atel_child_tracing_ctx, 3) + a[0].Foo(__atel_child_tracing_ctx, 4) +} diff --git a/instrgen/driver/test/fib/fib.go b/instrgen/driver/test/fib/fib.go new file mode 100644 index 00000000000..eaa187f64bd --- /dev/null +++ b/instrgen/driver/test/fib/fib.go @@ -0,0 +1,54 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "fmt" +) + +func foo() { + + fmt.Println("foo") +} + +func FibonacciHelper(n uint) (uint64, error) { + + func() { + + foo() + }() + return Fibonacci(n) +} + +func Fibonacci(n uint) (uint64, error) { + + if n <= 1 { + return uint64(n), nil + } + + if n > 93 { + return 0, fmt.Errorf("unsupported fibonacci number %d: too large", n) + } + + var n2, n1 uint64 = 0, 1 + for i := uint(2); i < n; i++ { + n2, n1 = n1, n1+n2 + } + + return n2 + n1, nil +} diff --git a/instrgen/driver/test/fib/main.go b/instrgen/driver/test/fib/main.go new file mode 100644 index 00000000000..9f9122712a8 --- /dev/null +++ b/instrgen/driver/test/fib/main.go @@ -0,0 +1,30 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "fmt" + + "go.opentelemetry.io/contrib/instrgen/rtlib" +) + +func main() { + + rtlib.AutotelEntryPoint() + fmt.Println(FibonacciHelper(10)) +} diff --git a/instrgen/driver/test/funwithoutpathtoroot/driver.go b/instrgen/driver/test/funwithoutpathtoroot/driver.go new file mode 100644 index 00000000000..c4614672ddd --- /dev/null +++ b/instrgen/driver/test/funwithoutpathtoroot/driver.go @@ -0,0 +1,35 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "go.opentelemetry.io/contrib/instrgen/rtlib" +) + +func bar() { + +} + +func foo() { + bar() +} + +func main() { + rtlib.AutotelEntryPoint() + bar() +} diff --git a/instrgen/driver/test/goroutines/main.go b/instrgen/driver/test/goroutines/main.go new file mode 100644 index 00000000000..f52f4601238 --- /dev/null +++ b/instrgen/driver/test/goroutines/main.go @@ -0,0 +1,45 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "fmt" + + "go.opentelemetry.io/contrib/instrgen/rtlib" +) + +func foo() { + +} + +func main() { + + rtlib.AutotelEntryPoint() + messages := make(chan string) + + go func() { + + messages <- "ping" + }() + + foo() + + msg := <-messages + fmt.Println(msg) + +} diff --git a/instrgen/driver/test/methods/main.go b/instrgen/driver/test/methods/main.go new file mode 100644 index 00000000000..861ad9b2610 --- /dev/null +++ b/instrgen/driver/test/methods/main.go @@ -0,0 +1,64 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "go.opentelemetry.io/contrib/instrgen/rtlib" +) + +type element struct { +} + +type driver struct { + e element +} + +type i interface { + foo(p int) int +} + +type impl struct { +} + +func (i impl) foo(p int) int { + + return 5 +} + +func foo(p int) int { + return 1 +} + +func (d driver) process(a int) { + +} + +func (e element) get(a int) { + +} + +func main() { + + rtlib.AutotelEntryPoint() + d := driver{} + d.process(10) + d.e.get(5) + var in i + in = impl{} + in.foo(10) +} diff --git a/instrgen/driver/test/package/main.go b/instrgen/driver/test/package/main.go new file mode 100644 index 00000000000..19a95c34fa8 --- /dev/null +++ b/instrgen/driver/test/package/main.go @@ -0,0 +1,38 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "os" + + "go.opentelemetry.io/contrib/instrgen/rtlib" +) + +func Close() error { + return nil +} + +func main() { + + rtlib.AutotelEntryPoint() + f, e := os.Create("temp") + defer f.Close() + if e != nil { + + } +} diff --git a/instrgen/driver/test/recursion/recursion.go b/instrgen/driver/test/recursion/recursion.go new file mode 100644 index 00000000000..ab6aff5a6eb --- /dev/null +++ b/instrgen/driver/test/recursion/recursion.go @@ -0,0 +1,35 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "go.opentelemetry.io/contrib/instrgen/rtlib" +) + +func recur(n int) { + + if n > 0 { + recur(n - 1) + } +} + +func main() { + + rtlib.AutotelEntryPoint() + recur(5) +} diff --git a/instrgen/driver/test/selector/main.go b/instrgen/driver/test/selector/main.go new file mode 100644 index 00000000000..cbb8786d781 --- /dev/null +++ b/instrgen/driver/test/selector/main.go @@ -0,0 +1,45 @@ +// 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 exclude + +//nolint:all +package main + +import ( + "go.opentelemetry.io/contrib/instrgen/rtlib" +) + +type Driver interface { + Foo(i int) +} + +type Impl struct { +} + +func (impl Impl) Foo(i int) { + +} + +func main() { + + rtlib.AutotelEntryPoint() + a := []Driver{ + Impl{}, + } + var d Driver + d = Impl{} + d.Foo(3) + a[0].Foo(4) +} diff --git a/instrgen/go.mod b/instrgen/go.mod index 2b60f5633da..b18ac6eadd9 100644 --- a/instrgen/go.mod +++ b/instrgen/go.mod @@ -1,3 +1,18 @@ module go.opentelemetry.io/contrib/instrgen go 1.18 + +require ( + go.opentelemetry.io/otel v1.11.2 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2 + go.opentelemetry.io/otel/sdk v1.11.2 + golang.org/x/tools v0.4.0 +) + +require ( + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + go.opentelemetry.io/otel/trace v1.11.2 // indirect + golang.org/x/mod v0.7.0 // indirect + golang.org/x/sys v0.3.0 // indirect +) diff --git a/instrgen/go.sum b/instrgen/go.sum new file mode 100644 index 00000000000..34de4a69aaf --- /dev/null +++ b/instrgen/go.sum @@ -0,0 +1,25 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= +go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2 h1:BhEVgvuE1NWLLuMLvC6sif791F45KFHi5GhOs1KunZU= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2/go.mod h1:bx//lU66dPzNT+Y0hHA12ciKoMOH9iixEwCqC1OeQWQ= +go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= +go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= +go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= +go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= +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/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/instrgen/lib/analysis_pass.go b/instrgen/lib/analysis_pass.go new file mode 100644 index 00000000000..34253e05ab4 --- /dev/null +++ b/instrgen/lib/analysis_pass.go @@ -0,0 +1,133 @@ +// 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. + +package lib // import "go.opentelemetry.io/contrib/instrgen/lib" + +import ( + "fmt" + "go/ast" + "go/printer" + "go/token" + "os" + + "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/go/packages" +) + +// Analysis. +type Analysis struct { + ProjectPath string + PackagePattern string + RootFunctions []FuncDescriptor + FuncDecls map[FuncDescriptor]bool + Callgraph map[FuncDescriptor][]FuncDescriptor + Interfaces map[string]bool + Debug bool +} + +type importaction int + +const ( + // import header. + Add importaction = iota + // remove header. + Remove +) + +// Import. +type Import struct { + NamedPackage string + Package string + ImportAction importaction +} + +// Analysis. +type AnalysisPass interface { + Execute(node *ast.File, + analysis *Analysis, + pkg *packages.Package, + pkgs []*packages.Package) []Import +} + +func createFile(name string) (*os.File, error) { + var out *os.File + out, err := os.Create(name) + if err != nil { + defer out.Close() + } + return out, err +} + +// Execute. +func (analysis *Analysis) Execute(pass AnalysisPass, fileSuffix string) error { + fset := token.NewFileSet() + cfg := &packages.Config{Fset: fset, Mode: LoadMode, Dir: analysis.ProjectPath} + pkgs, err := packages.Load(cfg, analysis.PackagePattern) + if err != nil { + return err + } + for _, pkg := range pkgs { + fmt.Println("\t", pkg) + var node *ast.File + for _, node = range pkg.Syntax { + fmt.Println("\t\t", fset.File(node.Pos()).Name()) + var out *os.File + out, err = createFile(fset.File(node.Pos()).Name() + fileSuffix) + if err != nil { + return err + } + if len(analysis.RootFunctions) == 0 { + e := printer.Fprint(out, fset, node) + if e != nil { + return e + } + continue + } + imports := pass.Execute(node, analysis, pkg, pkgs) + for _, imp := range imports { + if imp.ImportAction == Add { + if len(imp.NamedPackage) > 0 { + astutil.AddNamedImport(fset, node, imp.NamedPackage, imp.Package) + } else { + astutil.AddImport(fset, node, imp.Package) + } + } else { + if len(imp.NamedPackage) > 0 { + astutil.DeleteNamedImport(fset, node, imp.NamedPackage, imp.Package) + } else { + astutil.DeleteImport(fset, node, imp.Package) + } + } + } + e := printer.Fprint(out, fset, node) + if e != nil { + return e + } + var oldFileName string + var newFileName string + if analysis.Debug { + oldFileName = fset.File(node.Pos()).Name() + newFileName = fset.File(node.Pos()).Name() + ".original" + } else { + oldFileName = fset.File(node.Pos()).Name() + fileSuffix + newFileName = fset.File(node.Pos()).Name() + } + e = os.Rename(oldFileName, newFileName) + if e != nil { + return e + } + } + } + return nil +} diff --git a/instrgen/lib/callgraph.go b/instrgen/lib/callgraph.go new file mode 100644 index 00000000000..1a1b32cc5ee --- /dev/null +++ b/instrgen/lib/callgraph.go @@ -0,0 +1,504 @@ +// 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. + +package lib // import "go.opentelemetry.io/contrib/instrgen/lib" + +import ( + "fmt" + "go/ast" + "go/token" + "go/types" + "log" + "os" + "strconv" + "strings" + + "golang.org/x/tools/go/packages" +) + +// FuncDescriptor. +type FuncDescriptor struct { + Id string + DeclType string + CustomInjection bool +} + +// TypeHash. +func (fd FuncDescriptor) TypeHash() string { + return fd.Id + fd.DeclType +} + +// LoadMode. +const LoadMode packages.LoadMode = packages.NeedName | + packages.NeedTypes | + packages.NeedSyntax | + packages.NeedTypesInfo | + packages.NeedFiles + +// FindRootFunctions. +func FindRootFunctions(projectPath string, packagePattern string) []FuncDescriptor { + fset := token.NewFileSet() + + var currentFun FuncDescriptor + var rootFunctions []FuncDescriptor + + fmt.Println("FindRootFunctions") + cfg := &packages.Config{Fset: fset, Mode: LoadMode, Dir: projectPath} + pkgs, err := packages.Load(cfg, packagePattern) + if err != nil { + log.Println(err) + } + for _, pkg := range pkgs { + fmt.Println("\t", pkg) + + for _, node := range pkg.Syntax { + fmt.Println("\t\t", fset.File(node.Pos()).Name()) + ast.Inspect(node, func(n ast.Node) bool { + switch x := n.(type) { + case *ast.CallExpr: + selector, ok := x.Fun.(*ast.SelectorExpr) + if ok { + if selector.Sel.Name == "AutotelEntryPoint" { + rootFunctions = append(rootFunctions, currentFun) + } + } + case *ast.FuncDecl: + if pkg.TypesInfo.Defs[x.Name] != nil { + funId := pkg.TypesInfo.Defs[x.Name].Pkg().Path() + "." + pkg.TypesInfo.Defs[x.Name].Name() + currentFun = FuncDescriptor{funId, pkg.TypesInfo.Defs[x.Name].Type().String(), false} + fmt.Println("\t\t\tFuncDecl:", funId, pkg.TypesInfo.Defs[x.Name].Type().String()) + } + } + return true + }) + } + } + return rootFunctions +} + +// GetMostInnerAstIdent. +func GetMostInnerAstIdent(inSel *ast.SelectorExpr) *ast.Ident { + var l []*ast.Ident + var e ast.Expr + e = inSel + for e != nil { + if _, ok := e.(*ast.Ident); ok { + l = append(l, e.(*ast.Ident)) + break + } else if _, ok := e.(*ast.SelectorExpr); ok { + l = append(l, e.(*ast.SelectorExpr).Sel) + e = e.(*ast.SelectorExpr).X + } else if _, ok := e.(*ast.CallExpr); ok { + e = e.(*ast.CallExpr).Fun + } else if _, ok := e.(*ast.IndexExpr); ok { + e = e.(*ast.IndexExpr).X + } else if _, ok := e.(*ast.UnaryExpr); ok { + e = e.(*ast.UnaryExpr).X + } else if _, ok := e.(*ast.ParenExpr); ok { + e = e.(*ast.ParenExpr).X + } else if _, ok := e.(*ast.SliceExpr); ok { + e = e.(*ast.SliceExpr).X + } else if _, ok := e.(*ast.IndexListExpr); ok { + e = e.(*ast.IndexListExpr).X + } else if _, ok := e.(*ast.StarExpr); ok { + e = e.(*ast.StarExpr).X + } else if _, ok := e.(*ast.TypeAssertExpr); ok { + e = e.(*ast.TypeAssertExpr).X + } else if _, ok := e.(*ast.CompositeLit); ok { + // TODO dummy implementation + if len(e.(*ast.CompositeLit).Elts) == 0 { + e = e.(*ast.CompositeLit).Type + } else { + e = e.(*ast.CompositeLit).Elts[0] + } + } else if _, ok := e.(*ast.KeyValueExpr); ok { + e = e.(*ast.KeyValueExpr).Value + } else { + // TODO this is uncaught expression + panic("uncaught expression") + } + } + if len(l) < 2 { + panic("selector list should have at least 2 elems") + } + // caller or receiver is always + // at position 1, function is at 0 + return l[1] +} + +// GetPackagePathHashFromFunc. +func GetPackagePathHashFromFunc(pkg *packages.Package, + pkgs []*packages.Package, x *ast.FuncDecl, interfaces map[string]bool) string { + pkgPath := "" + for _, v := range x.Recv.List { + for _, dependentpkg := range pkgs { + for _, defs := range dependentpkg.TypesInfo.Defs { + if defs != nil { + if _, ok := defs.Type().Underlying().(*types.Interface); ok { + if len(v.Names) == 0 || pkg.TypesInfo.Defs[v.Names[0]] == nil { + continue + } + funType := pkg.TypesInfo.Defs[v.Names[0]].Type() + + if types.Implements(funType, defs.Type().Underlying().(*types.Interface)) { + interfaceExists := interfaces[defs.Type().String()] + if interfaceExists { + pkgPath = defs.Type().String() + } + break + } + } + } + } + } + } + if len(pkgPath) == 0 { + for _, v := range x.Recv.List { + if len(v.Names) == 0 { + continue + } + funType := pkg.TypesInfo.Defs[v.Names[0]].Type() + pkgPath = funType.String() + // We don't care if that's pointer, remove it from + // type id + if _, ok := funType.(*types.Pointer); ok { + pkgPath = strings.TrimPrefix(pkgPath, "*") + } + // We don't care if called via index, remove it from + // type id + if _, ok := funType.(*types.Slice); ok { + pkgPath = strings.TrimPrefix(pkgPath, "[]") + } + } + } + return pkgPath +} + +// GetSelectorPkgPath. +func GetSelectorPkgPath(sel *ast.SelectorExpr, pkg *packages.Package, pkgPath string) string { + caller := GetMostInnerAstIdent(sel) + if caller != nil { + if pkg.TypesInfo.Uses[caller] != nil { + if !strings.Contains(pkg.TypesInfo.Uses[caller].Type().String(), "invalid") { + pkgPath = pkg.TypesInfo.Uses[caller].Type().String() + // We don't care if that's pointer, remove it from + // type id + if _, ok := pkg.TypesInfo.Uses[caller].Type().(*types.Pointer); ok { + pkgPath = strings.TrimPrefix(pkgPath, "*") + } + // We don't care if called via index, remove it from + // type id + if _, ok := pkg.TypesInfo.Uses[caller].Type().(*types.Slice); ok { + pkgPath = strings.TrimPrefix(pkgPath, "[]") + } + } + } + } + return pkgPath +} + +// GetPkgNameFromUsesTable. +func GetPkgNameFromUsesTable(pkg *packages.Package, ident *ast.Ident) string { + if pkg.TypesInfo.Uses[ident].Pkg() != nil { + return pkg.TypesInfo.Uses[ident].Pkg().Path() + } + return "" +} + +// GetPkgNameFromDefsTable. +func GetPkgNameFromDefsTable(pkg *packages.Package, ident *ast.Ident) string { + if pkg.TypesInfo.Defs[ident] == nil { + return "" + } + if pkg.TypesInfo.Defs[ident].Pkg() != nil { + return pkg.TypesInfo.Defs[ident].Pkg().Path() + } + return "" +} + +// BuildCallGraph. +func BuildCallGraph( + projectPath string, + packagePattern string, + funcDecls map[FuncDescriptor]bool, + interfaces map[string]bool) map[FuncDescriptor][]FuncDescriptor { + fset := token.NewFileSet() + cfg := &packages.Config{Fset: fset, Mode: LoadMode, Dir: projectPath} + pkgs, err := packages.Load(cfg, packagePattern) + if err != nil { + log.Println(err) + } + fmt.Println("BuildCallGraph") + currentFun := FuncDescriptor{"nil", "", false} + backwardCallGraph := make(map[FuncDescriptor][]FuncDescriptor) + for _, pkg := range pkgs { + fmt.Println("\t", pkg) + for _, node := range pkg.Syntax { + fmt.Println("\t\t", fset.File(node.Pos()).Name()) + ast.Inspect(node, func(n ast.Node) bool { + switch x := n.(type) { + case *ast.CallExpr: + if id, ok := x.Fun.(*ast.Ident); ok { + pkgPath := GetPkgNameFromUsesTable(pkg, id) + funId := pkgPath + "." + pkg.TypesInfo.Uses[id].Name() + fmt.Println("\t\t\tFuncCall:", funId, pkg.TypesInfo.Uses[id].Type().String(), + " @called : ", + fset.File(node.Pos()).Name()) + fun := FuncDescriptor{funId, pkg.TypesInfo.Uses[id].Type().String(), false} + if !Contains(backwardCallGraph[fun], currentFun) { + if funcDecls[fun] { + backwardCallGraph[fun] = append(backwardCallGraph[fun], currentFun) + } + } + } + if sel, ok := x.Fun.(*ast.SelectorExpr); ok { + if pkg.TypesInfo.Uses[sel.Sel] != nil { + pkgPath := GetPkgNameFromUsesTable(pkg, sel.Sel) + if sel.X != nil { + pkgPath = GetSelectorPkgPath(sel, pkg, pkgPath) + } + funId := pkgPath + "." + pkg.TypesInfo.Uses[sel.Sel].Name() + fmt.Println("\t\t\tFuncCall via selector:", funId, pkg.TypesInfo.Uses[sel.Sel].Type().String(), + " @called : ", + fset.File(node.Pos()).Name()) + fun := FuncDescriptor{funId, pkg.TypesInfo.Uses[sel.Sel].Type().String(), false} + if !Contains(backwardCallGraph[fun], currentFun) { + if funcDecls[fun] { + backwardCallGraph[fun] = append(backwardCallGraph[fun], currentFun) + } + } + } + } + case *ast.FuncDecl: + pkgPath := "" + if x.Recv != nil { + pkgPath = GetPackagePathHashFromFunc(pkg, pkgs, x, interfaces) + } else { + pkgPath = GetPkgNameFromDefsTable(pkg, x.Name) + } + if pkg.TypesInfo.Defs[x.Name] != nil { + funId := pkgPath + "." + pkg.TypesInfo.Defs[x.Name].Name() + funcDecls[FuncDescriptor{funId, pkg.TypesInfo.Defs[x.Name].Type().String(), false}] = true + currentFun = FuncDescriptor{funId, pkg.TypesInfo.Defs[x.Name].Type().String(), false} + fmt.Println("\t\t\tFuncDecl:", funId, pkg.TypesInfo.Defs[x.Name].Type().String()) + } + } + return true + }) + } + } + return backwardCallGraph +} + +// FindFuncDecls. +func FindFuncDecls(projectPath string, packagePattern string, interfaces map[string]bool) map[FuncDescriptor]bool { + fset := token.NewFileSet() + cfg := &packages.Config{Fset: fset, Mode: LoadMode, Dir: projectPath} + pkgs, err := packages.Load(cfg, packagePattern) + if err != nil { + log.Println(err) + } + fmt.Println("FindFuncDecls") + funcDecls := make(map[FuncDescriptor]bool) + for _, pkg := range pkgs { + fmt.Println("\t", pkg) + for _, node := range pkg.Syntax { + fmt.Println("\t\t", fset.File(node.Pos()).Name()) + ast.Inspect(node, func(n ast.Node) bool { + if x, ok := n.(*ast.FuncDecl); ok { + pkgPath := "" + if x.Recv != nil { + pkgPath = GetPackagePathHashFromFunc(pkg, pkgs, x, interfaces) + } else { + pkgPath = GetPkgNameFromDefsTable(pkg, x.Name) + } + if pkg.TypesInfo.Defs[x.Name] != nil { + funId := pkgPath + "." + pkg.TypesInfo.Defs[x.Name].Name() + fmt.Println("\t\t\tFuncDecl:", funId, pkg.TypesInfo.Defs[x.Name].Type().String()) + funcDecls[FuncDescriptor{funId, pkg.TypesInfo.Defs[x.Name].Type().String(), false}] = true + } + } + return true + }) + } + } + return funcDecls +} + +// FindInterfaces. +func FindInterfaces(projectPath string, packagePattern string) map[string]bool { + fset := token.NewFileSet() + cfg := &packages.Config{Fset: fset, Mode: LoadMode, Dir: projectPath} + pkgs, err := packages.Load(cfg, packagePattern) + if err != nil { + log.Println(err) + } + fmt.Println("FindInterfaces") + interaceTable := make(map[string]bool) + for _, pkg := range pkgs { + fmt.Println("\t", pkg) + for _, node := range pkg.Syntax { + fmt.Println("\t\t", fset.File(node.Pos()).Name()) + ast.Inspect(node, func(n ast.Node) bool { + if x, ok := n.(*ast.TypeSpec); ok { + if _, ok := x.Type.(*ast.InterfaceType); ok { + fmt.Println("\t\t\tInterface:", pkg.TypesInfo.Defs[x.Name].Type().String()) + interaceTable[pkg.TypesInfo.Defs[x.Name].Type().String()] = true + } + } + return true + }) + } + } + return interaceTable +} + +// InferRootFunctionsFromGraph. +func InferRootFunctionsFromGraph(callgraph map[FuncDescriptor][]FuncDescriptor) []FuncDescriptor { + var allFunctions map[FuncDescriptor]bool + var rootFunctions []FuncDescriptor + allFunctions = make(map[FuncDescriptor]bool) + for k, v := range callgraph { + allFunctions[k] = true + for _, childFun := range v { + allFunctions[childFun] = true + } + } + for k := range allFunctions { + _, exists := callgraph[k] + if !exists { + rootFunctions = append(rootFunctions, k) + } + } + return rootFunctions +} + +// var callgraph = { +// nodes: [ +// { data: { id: 'fun1' } }, +// { data: { id: 'fun2' } }, +// ], +// edges: [ +// { data: { id: 'e1', source: 'fun1', target: 'fun2' } }, +// ] +// }; + +// Generatecfg. +func Generatecfg(callgraph map[FuncDescriptor][]FuncDescriptor, path string) { + functions := make(map[FuncDescriptor]bool, 0) + for k, childFuns := range callgraph { + if !functions[k] { + functions[k] = true + } + for _, v := range childFuns { + if !functions[v] { + functions[v] = true + } + } + } + for f := range functions { + fmt.Println(f) + } + out, err := os.Create(path) + if err != nil { + defer out.Close() + } + if err != nil { + return + } + _, err = out.WriteString("var callgraph = {") + if err != nil { + return + } + _, err = out.WriteString("\n\tnodes: [") + if err != nil { + return + } + for f := range functions { + _, err = out.WriteString("\n\t\t { data: { id: '") + if err != nil { + return + } + _, err = out.WriteString(f.TypeHash()) + if err != nil { + return + } + _, err = out.WriteString("' } },") + if err != nil { + return + } + } + _, err = out.WriteString("\n\t],") + if err != nil { + return + } + _, err = out.WriteString("\n\tedges: [") + if err != nil { + return + } + edgeCounter := 0 + for k, children := range callgraph { + for _, childFun := range children { + _, err = out.WriteString("\n\t\t { data: { id: '") + if err != nil { + return + } + _, err = out.WriteString("e" + strconv.Itoa(edgeCounter)) + if err != nil { + return + } + _, err = out.WriteString("', ") + if err != nil { + return + } + _, err = out.WriteString("source: '") + if err != nil { + return + } + _, err = out.WriteString(childFun.TypeHash()) + if err != nil { + return + } + _, err = out.WriteString("', ") + if err != nil { + return + } + _, err = out.WriteString("target: '") + if err != nil { + return + } + _, err = out.WriteString(k.TypeHash()) + if err != nil { + return + } + _, err = out.WriteString("' ") + if err != nil { + return + } + _, err = out.WriteString("} },") + if err != nil { + return + } + edgeCounter++ + } + } + _, err = out.WriteString("\n\t]") + if err != nil { + return + } + _, err = out.WriteString("\n};") + if err != nil { + return + } +} diff --git a/instrgen/lib/context_propagation.go b/instrgen/lib/context_propagation.go new file mode 100644 index 00000000000..ae40bbdf0e6 --- /dev/null +++ b/instrgen/lib/context_propagation.go @@ -0,0 +1,238 @@ +// 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. + +package lib // import "go.opentelemetry.io/contrib/instrgen/lib" + +import ( + "fmt" + "go/ast" + + "golang.org/x/tools/go/packages" +) + +func isFunPartOfCallGraph(fun FuncDescriptor, callgraph map[FuncDescriptor][]FuncDescriptor) bool { + // TODO this is not optimap o(n) + for k, v := range callgraph { + if k.TypeHash() == fun.TypeHash() { + return true + } + for _, e := range v { + if fun.TypeHash() == e.TypeHash() { + return true + } + } + } + return false +} + +// ContextPropagationPass. +type ContextPropagationPass struct { +} + +// Execute. +func (pass *ContextPropagationPass) Execute( + node *ast.File, + analysis *Analysis, + pkg *packages.Package, + pkgs []*packages.Package) []Import { + var imports []Import + addImports := false + // below variable is used + // when callexpr is inside var decl + // instead of functiondecl + currentFun := FuncDescriptor{} + emitEmptyContext := func(x *ast.CallExpr, fun FuncDescriptor, ctxArg *ast.Ident) { + addImports = true + if currentFun != (FuncDescriptor{}) { + visited := map[FuncDescriptor]bool{} + if isPath(analysis.Callgraph, currentFun, analysis.RootFunctions[0], visited) { + x.Args = append([]ast.Expr{ctxArg}, x.Args...) + } else { + contextTodo := &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_context", + }, + Sel: &ast.Ident{ + Name: "TODO", + }, + }, + Lparen: 62, + Ellipsis: 0, + } + x.Args = append([]ast.Expr{contextTodo}, x.Args...) + } + return + } + contextTodo := &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_context", + }, + Sel: &ast.Ident{ + Name: "TODO", + }, + }, + Lparen: 62, + Ellipsis: 0, + } + x.Args = append([]ast.Expr{contextTodo}, x.Args...) + } + emitCallExpr := func(ident *ast.Ident, n ast.Node, ctxArg *ast.Ident) { + if x, ok := n.(*ast.CallExpr); ok { + if pkg.TypesInfo.Uses[ident] == nil { + return + } + pkgPath := GetPkgNameFromUsesTable(pkg, ident) + funId := pkgPath + "." + pkg.TypesInfo.Uses[ident].Name() + fun := FuncDescriptor{ + Id: funId, + DeclType: pkg.TypesInfo.Uses[ident].Type().String(), + CustomInjection: false} + found := analysis.FuncDecls[fun] + + // inject context parameter only + // to these functions for which function decl + // exists + + if found { + visited := map[FuncDescriptor]bool{} + if isPath(analysis.Callgraph, fun, analysis.RootFunctions[0], visited) { + fmt.Println("\t\t\tContextPropagation FuncCall:", funId, pkg.TypesInfo.Uses[ident].Type().String()) + emitEmptyContext(x, fun, ctxArg) + } + } + } + } + emitCallExprFromSelector := func(sel *ast.SelectorExpr, n ast.Node, ctxArg *ast.Ident) { + if x, ok := n.(*ast.CallExpr); ok { + if pkg.TypesInfo.Uses[sel.Sel] == nil { + return + } + pkgPath := GetPkgNameFromUsesTable(pkg, sel.Sel) + if sel.X != nil { + pkgPath = GetSelectorPkgPath(sel, pkg, pkgPath) + } + funId := pkgPath + "." + pkg.TypesInfo.Uses[sel.Sel].Name() + fun := FuncDescriptor{ + Id: funId, + DeclType: pkg.TypesInfo.Uses[sel.Sel].Type().String(), + CustomInjection: false} + + found := analysis.FuncDecls[fun] + // inject context parameter only + // to these functions for which function decl + // exists + + if found { + visited := map[FuncDescriptor]bool{} + if isPath(analysis.Callgraph, fun, analysis.RootFunctions[0], visited) { + fmt.Println("\t\t\tContextPropagation FuncCall via selector:", funId, + pkg.TypesInfo.Uses[sel.Sel].Type().String()) + emitEmptyContext(x, fun, ctxArg) + } + } + } + } + ast.Inspect(node, func(n ast.Node) bool { + ctxArg := &ast.Ident{ + Name: "__atel_child_tracing_ctx", + } + ctxField := &ast.Field{ + Names: []*ast.Ident{ + { + Name: "__atel_tracing_ctx", + }, + }, + Type: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_context", + }, + Sel: &ast.Ident{ + Name: "Context", + }, + }, + } + switch x := n.(type) { + case *ast.FuncDecl: + pkgPath := "" + if x.Recv != nil { + pkgPath = GetPackagePathHashFromFunc(pkg, pkgs, x, analysis.Interfaces) + } else { + pkgPath = GetPkgNameFromDefsTable(pkg, x.Name) + } + funId := pkgPath + "." + pkg.TypesInfo.Defs[x.Name].Name() + fun := FuncDescriptor{ + Id: funId, + DeclType: pkg.TypesInfo.Defs[x.Name].Type().String(), + CustomInjection: false} + currentFun = fun + // inject context only + // functions available in the call graph + if !isFunPartOfCallGraph(fun, analysis.Callgraph) { + break + } + + if Contains(analysis.RootFunctions, fun) { + break + } + visited := map[FuncDescriptor]bool{} + + if isPath(analysis.Callgraph, fun, analysis.RootFunctions[0], visited) { + fmt.Println("\t\t\tContextPropagation FuncDecl:", funId, + pkg.TypesInfo.Defs[x.Name].Type().String()) + addImports = true + x.Type.Params.List = append([]*ast.Field{ctxField}, x.Type.Params.List...) + } + case *ast.CallExpr: + if ident, ok := x.Fun.(*ast.Ident); ok { + emitCallExpr(ident, n, ctxArg) + } + + if sel, ok := x.Fun.(*ast.SelectorExpr); ok { + emitCallExprFromSelector(sel, n, ctxArg) + } + + case *ast.TypeSpec: + iname := x.Name + iface, ok := x.Type.(*ast.InterfaceType) + if !ok { + return true + } + for _, method := range iface.Methods.List { + funcType, ok := method.Type.(*ast.FuncType) + if !ok { + return true + } + visited := map[FuncDescriptor]bool{} + pkgPath := GetPkgNameFromDefsTable(pkg, method.Names[0]) + funId := pkgPath + "." + iname.Name + "." + pkg.TypesInfo.Defs[method.Names[0]].Name() + fun := FuncDescriptor{ + Id: funId, + DeclType: pkg.TypesInfo.Defs[method.Names[0]].Type().String(), + CustomInjection: false} + if isPath(analysis.Callgraph, fun, analysis.RootFunctions[0], visited) { + fmt.Println("\t\t\tContext Propagation InterfaceType", fun.Id, fun.DeclType) + addImports = true + funcType.Params.List = append([]*ast.Field{ctxField}, funcType.Params.List...) + } + } + } + return true + }) + if addImports { + imports = append(imports, Import{"__atel_context", "context", Add}) + } + return imports +} diff --git a/instrgen/lib/instrumentation.go b/instrgen/lib/instrumentation.go new file mode 100644 index 00000000000..74fe696769a --- /dev/null +++ b/instrgen/lib/instrumentation.go @@ -0,0 +1,533 @@ +// 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. + +package lib // import "go.opentelemetry.io/contrib/instrgen/lib" + +import ( + "fmt" + "go/ast" + "go/token" + + "golang.org/x/tools/go/packages" +) + +// InstrumentationPass. +type InstrumentationPass struct { +} + +// Execute. +func (pass *InstrumentationPass) Execute( + node *ast.File, + analysis *Analysis, + pkg *packages.Package, + pkgs []*packages.Package) []Import { + var imports []Import + addImports := false + addContext := false + + childTracingSupress := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "_", + }, + }, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + }, + } + // store all function literals positions + // that are part of assignment statement + // it's used to avoid injection into literal + // more than once + var functionLiteralPositions []token.Pos + ast.Inspect(node, func(n ast.Node) bool { + switch x := n.(type) { + case *ast.FuncDecl: + pkgPath := "" + + if x.Recv != nil { + pkgPath = GetPackagePathHashFromFunc(pkg, pkgs, x, analysis.Interfaces) + } else { + pkgPath = GetPkgNameFromDefsTable(pkg, x.Name) + } + fundId := pkgPath + "." + pkg.TypesInfo.Defs[x.Name].Name() + fun := FuncDescriptor{ + Id: fundId, + DeclType: pkg.TypesInfo.Defs[x.Name].Type().String(), + CustomInjection: false} + // check if it's root function or + // one of function in call graph + // and emit proper ast nodes + _, exists := analysis.Callgraph[fun] + if !exists { + if !Contains(analysis.RootFunctions, fun) { + return false + } + } + + for _, root := range analysis.RootFunctions { + visited := map[FuncDescriptor]bool{} + fmt.Println("\t\t\tInstrumentation FuncDecl:", fundId, pkg.TypesInfo.Defs[x.Name].Type().String()) + if isPath(analysis.Callgraph, fun, root, visited) && fun.TypeHash() != root.TypeHash() { + s2 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + &ast.Ident{ + Name: "__atel_span", + }, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_otel", + }, + Sel: &ast.Ident{ + Name: "Tracer", + }, + }, + Lparen: 50, + Args: []ast.Expr{ + &ast.Ident{ + Name: `"` + x.Name.Name + `"`, + }, + }, + Ellipsis: 0, + }, + Sel: &ast.Ident{ + Name: "Start", + }, + }, + Lparen: 62, + Args: []ast.Expr{ + &ast.Ident{ + Name: "__atel_tracing_ctx", + }, + &ast.Ident{ + Name: `"` + x.Name.Name + `"`, + }, + }, + Ellipsis: 0, + }, + }, + } + + s3 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "_", + }, + }, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + }, + } + + s4 := &ast.DeferStmt{ + Defer: 27, + Call: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_span", + }, + Sel: &ast.Ident{ + Name: "End", + }, + }, + Lparen: 41, + Ellipsis: 0, + }, + } + x.Body.List = append([]ast.Stmt{s2, s3, s4}, x.Body.List...) + addContext = true + addImports = true + } else { + // check whether this function is root function + if !Contains(analysis.RootFunctions, fun) { + return false + } + s2 := + &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_ts", + }, + }, + Tok: token.DEFINE, + + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "rtlib", + }, + Sel: &ast.Ident{ + Name: "NewTracingState", + }, + }, + Lparen: 54, + Ellipsis: 0, + }, + }, + } + s3 := &ast.DeferStmt{ + Defer: 27, + Call: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "rtlib", + }, + Sel: &ast.Ident{ + Name: "Shutdown", + }, + }, + Lparen: 48, + Args: []ast.Expr{ + &ast.Ident{ + Name: "__atel_ts", + }, + }, + Ellipsis: 0, + }, + } + + s4 := &ast.ExprStmt{ + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_otel", + }, + Sel: &ast.Ident{ + Name: "SetTracerProvider", + }, + }, + Lparen: 49, + Args: []ast.Expr{ + &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_ts", + }, + Sel: &ast.Ident{ + Name: "Tp", + }, + }, + }, + Ellipsis: 0, + }, + } + s5 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_ctx", + }, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_context", + }, + Sel: &ast.Ident{ + Name: "Background", + }, + }, + Lparen: 52, + Ellipsis: 0, + }, + }, + } + s6 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + &ast.Ident{ + Name: "__atel_span", + }, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_otel", + }, + Sel: &ast.Ident{ + Name: "Tracer", + }, + }, + Lparen: 50, + Args: []ast.Expr{ + &ast.Ident{ + Name: `"` + x.Name.Name + `"`, + }, + }, + Ellipsis: 0, + }, + Sel: &ast.Ident{ + Name: "Start", + }, + }, + Lparen: 62, + Args: []ast.Expr{ + &ast.Ident{ + Name: "__atel_ctx", + }, + &ast.Ident{ + Name: `"` + x.Name.Name + `"`, + }, + }, + Ellipsis: 0, + }, + }, + } + + s8 := &ast.DeferStmt{ + Defer: 27, + Call: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_span", + }, + Sel: &ast.Ident{ + Name: "End", + }, + }, + Lparen: 41, + Ellipsis: 0, + }, + } + x.Body.List = append([]ast.Stmt{s2, s3, s4, s5, s6, childTracingSupress, s8}, x.Body.List...) + addContext = true + addImports = true + } + } + case *ast.AssignStmt: + + for _, e := range x.Lhs { + if ident, ok := e.(*ast.Ident); ok { + _ = ident + pkgPath := "" + pkgPath = GetPkgNameFromDefsTable(pkg, ident) + if pkg.TypesInfo.Defs[ident] == nil { + return false + } + fundId := pkgPath + "." + pkg.TypesInfo.Defs[ident].Name() + fun := FuncDescriptor{ + Id: fundId, + DeclType: pkg.TypesInfo.Defs[ident].Type().String(), + CustomInjection: true} + _, exists := analysis.Callgraph[fun] + if exists { + return false + } + } + } + for _, e := range x.Rhs { + if funLit, ok := e.(*ast.FuncLit); ok { + functionLiteralPositions = append(functionLiteralPositions, funLit.Pos()) + s2 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + &ast.Ident{ + Name: "__atel_span", + }, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_otel", + }, + Sel: &ast.Ident{ + Name: "Tracer", + }, + }, + Lparen: 50, + Args: []ast.Expr{ + &ast.Ident{ + Name: `"` + "anonymous" + `"`, + }, + }, + Ellipsis: 0, + }, + Sel: &ast.Ident{ + Name: "Start", + }, + }, + Lparen: 62, + Args: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + &ast.Ident{ + Name: `"` + "anonymous" + `"`, + }, + }, + Ellipsis: 0, + }, + }, + } + + s3 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "_", + }, + }, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + }, + } + + s4 := &ast.DeferStmt{ + Defer: 27, + Call: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_span", + }, + Sel: &ast.Ident{ + Name: "End", + }, + }, + Lparen: 41, + Ellipsis: 0, + }, + } + funLit.Body.List = append([]ast.Stmt{s2, s3, s4}, funLit.Body.List...) + addImports = true + addContext = true + } + } + case *ast.FuncLit: + for _, pos := range functionLiteralPositions { + if pos == x.Pos() { + return false + } + } + s2 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + &ast.Ident{ + Name: "__atel_span", + }, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_otel", + }, + Sel: &ast.Ident{ + Name: "Tracer", + }, + }, + Lparen: 50, + Args: []ast.Expr{ + &ast.Ident{ + Name: `"` + "anonymous" + `"`, + }, + }, + Ellipsis: 0, + }, + Sel: &ast.Ident{ + Name: "Start", + }, + }, + Lparen: 62, + Args: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + &ast.Ident{ + Name: `"` + "anonymous" + `"`, + }, + }, + Ellipsis: 0, + }, + }, + } + + s3 := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: "_", + }, + }, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + &ast.Ident{ + Name: "__atel_child_tracing_ctx", + }, + }, + } + + s4 := &ast.DeferStmt{ + Defer: 27, + Call: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "__atel_span", + }, + Sel: &ast.Ident{ + Name: "End", + }, + }, + Lparen: 41, + Ellipsis: 0, + }, + } + x.Body.List = append([]ast.Stmt{s2, s3, s4}, x.Body.List...) + addImports = true + addContext = true + } + + return true + }) + if addContext { + imports = append(imports, Import{"__atel_context", "context", Add}) + } + if addImports { + imports = append(imports, Import{"__atel_otel", "go.opentelemetry.io/otel", Add}) + } + return imports +} diff --git a/instrgen/lib/otel_pruning.go b/instrgen/lib/otel_pruning.go new file mode 100644 index 00000000000..cd55138a99f --- /dev/null +++ b/instrgen/lib/otel_pruning.go @@ -0,0 +1,157 @@ +// 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. + +package lib // import "go.opentelemetry.io/contrib/instrgen/lib" + +import ( + "go/ast" + "strings" + + "golang.org/x/tools/go/packages" +) + +func removeStmt(slice []ast.Stmt, s int) []ast.Stmt { + return append(slice[:s], slice[s+1:]...) +} + +func removeField(slice []*ast.Field, s int) []*ast.Field { + return append(slice[:s], slice[s+1:]...) +} + +func removeExpr(slice []ast.Expr, s int) []ast.Expr { + return append(slice[:s], slice[s+1:]...) +} + +// OtelPruner. +type OtelPruner struct { +} + +func inspectFuncContent(fType *ast.FuncType, fBody *ast.BlockStmt) { + for index := 0; index < len(fType.Params.List); index++ { + param := fType.Params.List[index] + for _, ident := range param.Names { + if strings.Contains(ident.Name, "__atel_") { + fType.Params.List = removeField(fType.Params.List, index) + index-- + } + } + } + for index := 0; index < len(fBody.List); index++ { + stmt := fBody.List[index] + switch bodyStmt := stmt.(type) { + case *ast.AssignStmt: + if ident, ok := bodyStmt.Lhs[0].(*ast.Ident); ok { + if strings.Contains(ident.Name, "__atel_") { + fBody.List = removeStmt(fBody.List, index) + index-- + } + } + if ident, ok := bodyStmt.Rhs[0].(*ast.Ident); ok { + if strings.Contains(ident.Name, "__atel_") { + fBody.List = removeStmt(fBody.List, index) + index-- + } + } + case *ast.ExprStmt: + if call, ok := bodyStmt.X.(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if strings.Contains(sel.Sel.Name, "SetTracerProvider") { + fBody.List = removeStmt(fBody.List, index) + index-- + } + } + } + case *ast.DeferStmt: + if sel, ok := bodyStmt.Call.Fun.(*ast.SelectorExpr); ok { + if strings.Contains(sel.Sel.Name, "Shutdown") { + if ident, ok := sel.X.(*ast.Ident); ok { + if strings.Contains(ident.Name, "rtlib") { + fBody.List = removeStmt(fBody.List, index) + index-- + } + } + } + if ident, ok := sel.X.(*ast.Ident); ok { + if strings.Contains(ident.Name, "__atel_") { + fBody.List = removeStmt(fBody.List, index) + index-- + } + } + } + } + } +} + +// Execute. +func (pass *OtelPruner) Execute( + node *ast.File, + analysis *Analysis, + pkg *packages.Package, + pkgs []*packages.Package) []Import { + var imports []Import + ast.Inspect(node, func(n ast.Node) bool { + switch x := n.(type) { + case *ast.FuncDecl: + inspectFuncContent(x.Type, x.Body) + case *ast.CallExpr: + for argIndex := 0; argIndex < len(x.Args); argIndex++ { + if ident, ok := x.Args[argIndex].(*ast.Ident); ok { + if strings.Contains(ident.Name, "__atel_") { + x.Args = removeExpr(x.Args, argIndex) + argIndex-- + } + } + } + for argIndex := 0; argIndex < len(x.Args); argIndex++ { + if c, ok := x.Args[argIndex].(*ast.CallExpr); ok { + if sel, ok := c.Fun.(*ast.SelectorExpr); ok { + if ident, ok := sel.X.(*ast.Ident); ok { + if strings.Contains(ident.Name, "__atel_") { + x.Args = removeExpr(x.Args, argIndex) + argIndex-- + } + } + } + } + } + case *ast.FuncLit: + inspectFuncContent(x.Type, x.Body) + case *ast.TypeSpec: + iface, ok := x.Type.(*ast.InterfaceType) + if !ok { + return true + } + for _, method := range iface.Methods.List { + funcType, ok := method.Type.(*ast.FuncType) + if !ok { + continue + } + for argIndex := 0; argIndex < len(funcType.Params.List); argIndex++ { + for _, ident := range funcType.Params.List[argIndex].Names { + if strings.Contains(ident.Name, "__atel_") { + funcType.Params.List = removeField(funcType.Params.List, argIndex) + argIndex-- + } + } + } + } + } + return true + }) + imports = append(imports, Import{"__atel_context", "context", Remove}) + imports = append(imports, Import{"__atel_otel", "go.opentelemetry.io/otel", Remove}) + imports = append(imports, Import{"__atel_otelhttp", "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp", Remove}) + + return imports +} diff --git a/instrgen/lib/tools.go b/instrgen/lib/tools.go new file mode 100644 index 00000000000..c09007dcaac --- /dev/null +++ b/instrgen/lib/tools.go @@ -0,0 +1,70 @@ +// 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. + +package lib // import "go.opentelemetry.io/contrib/instrgen/lib" + +import ( + "os" + "path/filepath" +) + +// SearchFiles. +func SearchFiles(root string, ext string) []string { + var files []string + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if filepath.Ext(path) == ext { + files = append(files, path) + } + return nil + }) + if err != nil { + panic(err) + } + return files +} + +func isPath( + callGraph map[FuncDescriptor][]FuncDescriptor, + current FuncDescriptor, + goal FuncDescriptor, + visited map[FuncDescriptor]bool) bool { + if current == goal { + return true + } + + value, ok := callGraph[current] + if ok { + for _, child := range value { + exists := visited[child] + if exists { + continue + } + visited[child] = true + if isPath(callGraph, child, goal, visited) { + return true + } + } + } + return false +} + +// Contains. +func Contains(a []FuncDescriptor, x FuncDescriptor) bool { + for _, n := range a { + if x.TypeHash() == n.TypeHash() { + return true + } + } + return false +} diff --git a/instrgen/rtlib/rtlib.go b/instrgen/rtlib/rtlib.go new file mode 100644 index 00000000000..8c35d2b5308 --- /dev/null +++ b/instrgen/rtlib/rtlib.go @@ -0,0 +1,98 @@ +// 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. + +// Basic runtime library + +package rtlib // import "go.opentelemetry.io/contrib/instrgen/rtlib" + +import ( + "context" + "io" + "log" + "os" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/resource" + trace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" +) + +// TracingState type. +type TracingState struct { + Logger *log.Logger + File *os.File + Tp *trace.TracerProvider +} + +// NewTracingState. +func NewTracingState() TracingState { + var tracingState TracingState + tracingState.Logger = log.New(os.Stdout, "", 0) + + // Write telemetry data to a file. + var err error + tracingState.File, err = os.Create("traces.txt") + + if err != nil { + tracingState.Logger.Fatal(err) + } + var exp trace.SpanExporter + exp, err = NewExporter(tracingState.File) + if err != nil { + tracingState.Logger.Fatal(err) + } + tracingState.Tp = trace.NewTracerProvider( + trace.WithBatcher(exp), + trace.WithResource(NewResource()), + ) + return tracingState +} + +// NewExporter returns a console exporter. +func NewExporter(w io.Writer) (trace.SpanExporter, error) { + return stdouttrace.New( + stdouttrace.WithWriter(w), + // Use human readable output. + stdouttrace.WithPrettyPrint(), + // Do not print timestamps for the demo. + stdouttrace.WithoutTimestamps(), + ) +} + +// NewResource returns a resource describing this application. +func NewResource() *resource.Resource { + r, _ := resource.Merge( + resource.Default(), + resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("fib"), + semconv.ServiceVersionKey.String("v0.1.0"), + attribute.String("environment", "demo"), + ), + ) + return r +} + +// Shutdown. +func Shutdown(ts TracingState) { + if err := ts.Tp.Shutdown(context.Background()); err != nil { + ts.Logger.Fatal(err) + } +} + +// AutoEntryPoint. +func AutotelEntryPoint() { + +}