Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/quangtung97/otelwrap

OpenTelemetry Go code generation tool
https://github.com/quangtung97/otelwrap

code-generation open-telemetry

Last synced: about 1 month ago
JSON representation

OpenTelemetry Go code generation tool

Awesome Lists containing this project

README

        

## OtelWrap: code generation tool for Go OpenTelemetry

[![otelwrap](https://github.com/QuangTung97/otelwrap/actions/workflows/go.yml/badge.svg)](https://github.com/QuangTung97/otelwrap/actions/workflows/go.yml)
[![Coverage Status](https://coveralls.io/repos/github/QuangTung97/otelwrap/badge.svg?branch=master)](https://coveralls.io/github/QuangTung97/otelwrap?branch=master)

### What is OtelWrap?

**OtelWrap** is a tool that generates a decorator implementation of any interfaces that can be used for instrumentation
with Go OpenTelemetry library. Inspired by https://github.com/matryer/moq

Supporting:

* Any interface and any method with **context.Context** as the first parameter.
* Detecting **error** return and set the span's error status accordingly.
* Only tested using **go generate**.
* Interface embedding.

### Installing

Using conventional **tools.go** file for pinning version in **go.mod** / **go.sum**.

```go
// +build tools

package tools

import (
_ "github.com/QuangTung97/otelwrap"
)
```

And then download and install the binary with commands:

```shell
$ go mod tidy
$ go install github.com/QuangTung97/otelwrap
```

### Usage

```
otelwrap [flags] -source-dir interface [interface2 interface3 ...]
--out string (required)
output file
```

Using **go generate**:

```go
package example

import "context"

//go:generate otelwrap --out interface_wrappers.go . MyInterface

type MyInterface interface {
Method1(ctx context.Context) error
Method2(ctx context.Context, x int)
Method3()
}
```

The run ``go generate ./...`` in your module. The generated file looks like:

```go
// Code generated by otelwrap; DO NOT EDIT.
// github.com/QuangTung97/otelwrap

package example

import (
"context"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
)

// MyInterfaceWrapper wraps OpenTelemetry's span
type MyInterfaceWrapper struct {
MyInterface
tracer trace.Tracer
prefix string
}

// NewMyInterfaceWrapper creates a wrapper
func NewMyInterfaceWrapper(wrapped MyInterface, tracer trace.Tracer, prefix string) *MyInterfaceWrapper {
return &MyInterfaceWrapper{
MyInterface: wrapped,
tracer: tracer,
prefix: prefix,
}
}

// Method1 ...
func (w *MyInterfaceWrapper) Method1(ctx context.Context) (err error) {
ctx, span := w.tracer.Start(ctx, w.prefix+"Method1")
defer span.End()

err = w.MyInterface.Method1(ctx)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
return err
}

// Method2 ...
func (w *MyInterfaceWrapper) Method2(ctx context.Context, x int) {
ctx, span := w.tracer.Start(ctx, w.prefix+"Method2")
defer span.End()

w.MyInterface.Method2(ctx, x)
}
```

To use the generated struct, simply wraps the original implementation. The generated code is very easy to read.

```go
package example

import "go.opentelemetry.io/otel"

func InitMyInterface() MyInterface {
original := NewMyInterfaceImpl()
return NewMyInterfaceWrapper(original, otel.GetTracerProvider().Tracer("example"), "prefix")
}

```

Can also generate for interfaces in other packages:

```go
package example

import "path/to/another"

var _ another.Interface1 // not necessary, only for keeping the import statement

//go:generate otelwrap --out interface_wrappers.go . another.Interface1 another.Interface2
```

Or generate to another package:

```go
package example

import "context"

//go:generate otelwrap --out ../another/interface_wrappers.go . MyInterface

type MyInterface interface {
Method1(ctx context.Context) error
Method2(ctx context.Context, x int)
Method3()
}
```