Misura (Italian for measure) gives insight about a golang type by generating a wrapper. See usage seciton for more information
- Can wrap any interface not matter the input or output
- it's quite versatile by receiving a
metrics
interface in the form of:
interface {
Failure(ctx context.Context, name, pkg, intr, method string, duration time.Duration, err error)
Success(ctx context.Context, name, pkg, intr, method string, duration time.Duration)
Total(ctx context.Context, name, pkg, intr, method string)
}
- You can use it to easily add Prometheus metrics to any interface you want or enable tracing (i.e. opentracing) without cluttering the actual logic.
- It's smart enough not to polute git changes everytime
go generate
is ran. - TODO
-
Latest version of Misura can be obtained from the Rleases.
-
Misura can also be installed with
go install
command:
$ go install github.com/itzloop/misura@latest
Assume we have these interfaces in a file called sample.go
.
// filename: sample.go
type FooType interface {
Foo(int, string) error
}
type BarType interface {
Bar() (string, error)
Baz(string)
}
Now to generate a wrapper for this interface we have 2 options:
- Put a magic comment for the entire file and passing each interface name with the -t flag.
// filename: sample.go
//go:generate misura -m all -t FooType -t BarType
type FooType interface {
Foo(int, string) error
}
type BarType interface {
Bar() (string, error)
Baz(string)
}
-m
receives specifies what to measure.all
measures everything (total calls, error and success count and the duration of that call).- You can repeadedly pass
-m
like-m total -m duration
or pass it as a comma-seperated string like-m total,duration
. - When
all
is passed other measures will be ignored. -t
specifies what types to generate a wrapper for.-t
also supports comma-seperated and repeated or both.
- Add a magic comment on top of the file then use
//misura:<taget-name>
syntax. This method makes the file readable.
// filename: sample.go
package main
// passed args will be used for all types
// right now having per-type args is NOT supported!
//go:generate misura -m all
import (
...
)
//misura:FooType
type FooType interface {
Foo(int, string) error
}
//misura:BarType
type BarType interface {
Bar() (string, error)
Baz(string)
}
The second approach is more readable as it keeps comments close to the actual type istead of having a single comment.
After running go generate ./...
on the above file, two files will be generated:
sample.FooType.misura.go
sample.BarType.misura.go
Here is the contents of the first file:
// Code generated by github.com/itzloop/misura. DO NOT EDIT!
// RANDOM_HEX=69679DA8
// This is used to avoid name colision. as start and duration are common names.
...
type FooTypePrometheusWrapperImpl struct {
name string
intr string
wrapped FooType
metrics interface {
Failure(ctx context.Context, name, pkg, intr, method string, duration time.Duration, err error)
Success(ctx context.Context, name, pkg, intr, method string, duration time.Duration)
Total(ctx context.Context, name, pkg, intr, method string)
}
}
func NewFooTypePrometheusWrapperImpl(/* removed for clarity */) *FooTypePrometheusWrapperImpl {
// constructor logic, removed for clarity.
}
func (w *FooTypePrometheusWrapperImpl) Foo(a int, b string) error {
start69679DA8 := time.Now()
w.metrics.Total(context.Background(), w.name, "main", w.intr, "Foo")
err := w.wrapped.Foo(a, b)
duration69679DA8 := time.Since(start69679DA8)
if err != nil {
w.metrics.Failure(context.Background(), w.name, "main", w.intr, "Foo", duration69679DA8, err)
return err
}
w.metrics.Success(context.Background(), w.name, "main", w.intr, "Foo", duration69679DA8)
return err
}
go test ./...
- Test generated wrappers for compliation
-
Test generated code is as expected usingThis is too much for nowast
, or maybe run them with a utilty program and run it that way.
- Handle slice ... operator
- Only work on types passed not all interfaces in file
- Pass method name and other method related information Total, Success and Error
- Get list of types not just one
-
Check generated file exists, if yes append to it. - Create a seperate file for each type.
-
- Let users decided what metrics they want
- Handle
time
package conflict - Add struct wrapping support?
- Only methods in the same file will be included
- Add an options to create an interface for the struct aswell
- Enable users to extend wrapping functionallity to add custom logic to their interfaces
-
Custom metrics?This is solved by accepting metrics interface. - Per type method inclusion and exlusion
- Support both go:generate misura [args] and //misura: [args]
- Support per type args with //misura:
- Support third party types
- Rename metrics with measures
- Rename targets with types
- Change
PrometheusWrapper
strings withMisuraWrapper
.
TODO