Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add --inst-all and --rm-all options to generator #73

Merged
merged 3 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ versioning](https://go.dev/doc/modules/version-numbers).

### Added

- [All] `autometrics` the go-generator binary accepts an `--instrument-all` flag, to process all
functions in the file even if they do not have any annotation
- [All] `autometrics` the go-generator binary accepts a `--rm-all` flag (that overrides the `--instrument-all` flag)
to remove autometrics from all annotated functions. This is useful to offboard autometrics after trying it:
```bash
AM_RM_ALL=true go generate ./... # Will remove all godoc and instrumentation calls
sed -i '/\/\/.*autometrics/d' **/*.go # A similar sed command will remove all comments containing 'autometrics'
# A go linter/formatter of your choice can then clean up all unused imports to remove the automatically added ones.
```

### Changed

### Deprecated
Expand Down
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,28 @@ compatibility comes out of the box).

### 3. Add directives for each function you want to instrument

#### 3a. The VERY quick way

Use find and sed to insert a `//go:generate` directive that will instrument all
the functions in all source files under the current directory:

(Replace `gsed` with `sed` on linux; `gsed` is installed with `brew gsed`)

``` bash
find . \
-type f \
-path ./vendor -prune -or \
-name '*.go*' \
-print0 | xargs -0 gsed -i -e '/package/{a\//go:generate autometrics --instrument-all --no-doc' -e ':a;n;ba}'
```

You can remove the `--no-doc` to get the full experience, but the generator will add a lot of comments if so.

#### 3b. The slower quick way

This grants you more control over what gets instrumented, but it is longer
to add.

> **Warning**
> You must both add the `//go:generate` directive, and one `//autometrics:inst`
directive per function you want to instrument
Expand All @@ -133,7 +155,7 @@ subsection to see details:

Once it is done, you can call the [generator](#4-generate-the-documentation-and-instrumentation-code)

#### For error-returning functions
##### For error-returning functions

<details><summary><i>Expand to instrument error returning functions</i></summary>

Expand Down Expand Up @@ -165,7 +187,7 @@ _must_ name the error return value. This is why we recommend to name the error
value you return for the function you want to instrument.
</details>

#### For HTTP handler functions
##### For HTTP handler functions

<details><summary><i>Expand to instrument HTTP handlers functions</i></summary>

Expand Down Expand Up @@ -477,6 +499,23 @@ instrumentation only, you have multiple options:
$ AM_NO_DOCGEN=true go generate ./...
```

##### Offboarding

If for some reason you want to stop using autometrics, the easiest way includes 3 steps.

First is to use the environment variable `AM_RM_ALL` to remove all generated documentation
and code:

``` console
$ AM_RM_ALL=true go generate ./...
```

Second step is to use grep/your text-editor/your IDE of choice to remove all lines starting with
`//go:generate autometrics` from your files so `go generate` will stop creating autometrics code.

Last step is to use your text-editor IDE to remove remnants:
- a "go imports" cleaner to remove the `autometrics` imports (or grep-ing again)
- remove the `autometrics.Init` call from the main entrypoint of your code.

# Contributing

Expand Down
4 changes: 4 additions & 0 deletions cmd/autometrics/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ type args struct {
UseOtel bool `arg:"--otel" default:"false" help:"Use OpenTelemetry client library to instrument code instead of default Prometheus."`
AllowCustomLatencies bool `arg:"--custom-latency" default:"false" help:"Allow non-default latencies to be used in latency-based SLOs."`
DisableDocGeneration bool `arg:"--no-doc,env:AM_NO_DOCGEN" default:"false" help:"Disable documentation links generation for all instrumented functions. Has the same effect as --no-doc in the //autometrics:inst directive."`
ProcessAllFunctions bool `arg:"-i,--instrument-all,--inst-all,env:AM_INSTRUMENT_ALL" default:"false" help:"Instrument all function declared in the file to transform. Overwritten by the --rm-all argument if both are set."`
RemoveAllFunctions bool `arg:"--rm-all,env:AM_RM_ALL" default:"false" help:"Remove all function instrumentation in the file to transform."`
}

func (args) Version() string {
Expand Down Expand Up @@ -69,6 +71,8 @@ func main() {
args.PrometheusUrl,
args.AllowCustomLatencies,
args.DisableDocGeneration,
args.ProcessAllFunctions,
args.RemoveAllFunctions,
)
if err != nil {
log.Fatalf("error initialising autometrics context: %s", err)
Expand Down
10 changes: 9 additions & 1 deletion internal/autometrics/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ type GeneratorContext struct {
//
// This can be set in the command for the generator or through the environment.
DisableDocGeneration bool
// Flag to ask the generator to process all function declaration even if they
// do not have any annotation. The flag is overriden by the RemoveEverything one.
InstrumentEverything bool
// Flag to ask the generator to only remove all autometrics generated code in the
// file.
RemoveEverything bool
// ImportMap maps the alias to import in the current file, to canonical names associated with that name.
ImportsMap map[string]string
}
Expand Down Expand Up @@ -143,11 +149,13 @@ func (c *GeneratorContext) SetCommentIdx(i int) {
c.FuncCtx.CommentIndex = i
}

func NewGeneratorContext(implementation autometrics.Implementation, prometheusUrl string, allowCustomLatencies, disableDocGeneration bool) (GeneratorContext, error) {
func NewGeneratorContext(implementation autometrics.Implementation, prometheusUrl string, allowCustomLatencies, disableDocGeneration, instrumentEverything, removeEverything bool) (GeneratorContext, error) {
ctx := GeneratorContext{
Implementation: implementation,
AllowCustomLatencies: allowCustomLatencies,
DisableDocGeneration: disableDocGeneration,
InstrumentEverything: instrumentEverything,
RemoveEverything: removeEverything,
RuntimeCtx: DefaultRuntimeCtxInfo(),
FuncCtx: GeneratorFunctionContext{},
ImportsMap: make(map[string]string),
Expand Down
30 changes: 15 additions & 15 deletions internal/generate/defer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func main(thisIsAContext context.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -110,7 +110,7 @@ func main(thisIsAContext vanilla.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -167,7 +167,7 @@ func main(thisIsAContext Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -224,7 +224,7 @@ func main(w http.ResponseWriter, req *http.Request) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -281,7 +281,7 @@ func main(w vanilla.ResponseWriter, req *vanilla.Request) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -338,7 +338,7 @@ func main(w ResponseWriter, req *Request) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -395,7 +395,7 @@ func main(thisIsAContext buffalo.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -452,7 +452,7 @@ func main(thisIsAContext vanilla.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -509,7 +509,7 @@ func main(thisIsAContext Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -568,7 +568,7 @@ func main(thisIsAContext echo.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -627,7 +627,7 @@ func main(thisIsAContext vanilla.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -686,7 +686,7 @@ func main(thisIsAContext Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -745,7 +745,7 @@ func main(thisIsAContext *gin.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -804,7 +804,7 @@ func main(thisIsAContext *vanilla.Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down Expand Up @@ -863,7 +863,7 @@ func main(thisIsAContext *Context) {
" fmt.Println(hello) // line comment 3\n" +
"}\n"

ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true)
ctx, err := internal.NewGeneratorContext(autometrics.PROMETHEUS, defaultPrometheusInstanceUrl, false, true, false, false)
if err != nil {
t.Fatalf("error creating the generation context: %s", err)
}
Expand Down
17 changes: 15 additions & 2 deletions internal/generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func GenerateDocumentationAndInstrumentation(ctx internal.GeneratorContext, sour
}
}

if !foundAmImport {
if !ctx.RemoveEverything && !foundAmImport {
err = addAutometricsImport(&ctx, fileTree)
if err != nil {
return "", fmt.Errorf("error adding the autometrics import: %w", err)
Expand Down Expand Up @@ -125,7 +125,7 @@ func GenerateDocumentationAndInstrumentation(ctx internal.GeneratorContext, sour

// walkFuncDeclaration uses the context to generate documentation and code if necessary for a function declaration in a file.
func walkFuncDeclaration(ctx *internal.GeneratorContext, funcDeclaration *dst.FuncDecl, moduleName string) error {
if ctx.FuncCtx.ImplImportName == "" {
if !ctx.RemoveEverything && ctx.FuncCtx.ImplImportName == "" {
if ctx.Implementation == autometrics.PROMETHEUS {
return fmt.Errorf("the source file is missing a %v import", AmPromPackage)
} else if ctx.Implementation == autometrics.OTEL {
Expand Down Expand Up @@ -155,6 +155,12 @@ func walkFuncDeclaration(ctx *internal.GeneratorContext, funcDeclaration *dst.Fu
err)
}

// Early exit if we wanted to remove everything
if ctx.RemoveEverything {
funcDeclaration.Decorations().Start.Replace(docComments...)
return nil
}

// Detect autometrics directive
err = parseAutometricsFnContext(ctx, docComments)
if err != nil {
Expand Down Expand Up @@ -250,6 +256,13 @@ func parseAutometricsFnContext(ctx *internal.GeneratorContext, commentGroup []st
}
}

// If the function didn't have any directive, BUT we asked to process all functions, we change the context still
if ctx.InstrumentEverything {
ctx.FuncCtx.CommentIndex = len(commentGroup)
ctx.RuntimeCtx = internal.DefaultRuntimeCtxInfo()
return nil
}

ctx.FuncCtx.CommentIndex = -1
ctx.RuntimeCtx = internal.DefaultRuntimeCtxInfo()
return nil
Expand Down
Loading
Loading