Skip to content

itzloop/misura

Repository files navigation

Misura

Misura (Italian for measure) gives insight about a golang type by generating a wrapper. See usage seciton for more information

Misura Wallpaper

⚠️⚠️ Misura IS UNDER HEAVY DEVELOPMENT ⚠️⚠️

Features

  • 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

Installation

  • 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

Usage

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:

  1. 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)
}

Explaination

  • -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.
  1. 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:

  1. sample.FooType.misura.go
  2. 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
}

Testing

go test ./...
  • Test generated wrappers for compliation
  • Test generated code is as expected using ast, or maybe run them with a utilty program and run it that way. This is too much for now

Todos

  • 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 with MisuraWrapper.

Contrubuting

TODO

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published