GoWrap

repository·master·Indexed 23 days ago

https://github.com/hexdigest/gowrap

A command-line tool that generates decorator implementations for Go interfaces using templates. It enables developers to add cross-cutting concerns such as metrics, logging, retries, circuit breakers, and rate limiting to existing code. GoWrap includes built-in templates for Prometheus, OpenTelemetry, OpenCensus, and others, and supports custom templates using the Sprig library and built-in string manipulation functions.

Tokens
3.1K
Snippets
8
Records
17
Agent score
74%

What's inside gowrap

  1. Create custom GoWrap templates

    master

    You can write custom templates to provide specific functionality to your interfaces.

    Template Capabilities:

    • Sprig Library: All functions from the Sprig template library are available.
    • GoWrap Built-in Functions:
      • up: Converts input to UPPERCASE.
      • down: Converts input to lowercase.
      • upFirst: Converts the first letter to Uppercase.
      • downFirst: Converts the first letter to lowercase.
      • replace: Replaces occurrences of the first argument with the second.
      • snake: Converts input to snake_case.

    Data Structure: The information passed to your templates is defined by the TemplateInputs struct (see TemplateInputs documentation).

  2. Install GoWrap CLI or as a module

    master

    You can install GoWrap as a standalone command-line tool or include it as a dependency in your Go project.

    To install the CLI:

    go install github.com/hexdigest/gowrap/cmd/gowrap@latest

    To add as a module:

    go get -u github.com/hexdigest/gowrap/cmd/gowrap
    go install github.com/hexdigest/gowrap/cmd/gowrap@latest
  3. Copy templates to local files for offline use

    master

    By default, GoWrap adds a //go:generate instruction to generated files. If you use a remote template (via URL), regeneration will require an internet connection. To avoid this, copy the template to your local version control system.

    Command to copy a template:

    gowrap template copy <template_name> <local_destination>

    Example: To copy the fallback template to a local directory named templates/fallback:

    gowrap template copy fallback templates/fallback

    Then, generate code using the local path:

    gowrap gen -p io -i Reader -t templates/fallback reader_with_fallback.go
    gowrap template copy fallback templates/fallback
  4. Use hosted GoWrap templates

    master

    GoWrap provides a variety of built-in templates that you can reference by name using the -t flag. When you use a name, GoWrap first looks for a local file with that name; if not found, it fetches the template from the official GoWrap repository.

    Available Templates:

    • circuitbreaker: Stops execution after consecutive errors and resumes after a delay.
    • fallback: Runs multiple implementations concurrently, returning the first non-error result.
    • log: Instruments with the standard log package.
    • logrus: Instruments with sirupsen/logrus.
    • opencensus: Instruments with OpenCensus spans.
    • opentelemetry: Instruments with OpenTelemetry spans.
    • opentracing: Instruments with OpenTracing spans.
    • prometheus: Instruments with Prometheus metrics.
    • ratelimit: Implements RPS and concurrent call limits.
    • retry: Implements retries.
    • robinpool: Uses Round-robin algorithm to pick implementations from a slice.
    • syncpool: Uses sync.Pool to manage implementations.
    • timeout: Adds configurable timeouts to methods accepting a context.Context.
    • validate: Runs func Validate() error on arguments if present.
    • twirp_error: Injects request data into twirp.Error metadata.
    • twirp_validate: Runs Validate() and wraps errors with twirp.Malformed.
    • grpc_validate: Runs Validate() and returns InvalidArgument error on failure.
    • elasticapm: Instruments with Elastic APM spans.
    • caching: Implements in-memory caching using go-cache.
  5. Generate interface decorators with `gowrap gen`

    master

    Use the gen command to generate decorator implementations for Go interfaces. This allows you to wrap existing interfaces with features like metrics, logging, or retries.

    Command Syntax: gowrap gen -p package -i interfaceName -t template -o output_file.go

    Arguments:

    • -p string: The source package import path (e.g., io, github.com/user/repo, or a relative path like ./pkg).
    • -i string: The name of the source interface (e.g., Reader).
    • -t template: The template to use. This can be a local file path, an HTTPS URL, or a built-in template name.
    • -o string: The name of the output file.
    • -g: (Optional) Prevents adding the //go:generate instruction to the generated file.
    • -v value: (Optional) Key-value pairs to parameterize the template. Arguments without an = are treated as booleans (e.g., -v DecoratorName=MyDecorator -v disableChecks).

    Examples:

    Generate a prometheus metrics decorator for the io.Reader interface:

    gowrap gen -p io -i Reader -t prometheus -o reader_with_metrics.go

    Generate a fallback decorator for a Connector interface located in the ./connector subpackage:

    gowrap gen -p ./connector -i Connector -t fallback -o ./connector/with_metrics.go
    gowrap gen -p io -i Reader -t prometheus -o reader_with_metrics.go
  6. Generate the global usage message with Usage

    master

    The Usage(w io.Writer) function generates a formatted help message that lists all registered commands, their names, and their short descriptions. This is typically used when the user provides invalid arguments or requests help.

    // Usage writes gowrap usage message to w
    func Usage(w io.Writer) error {
    	return usageTemplate.Execute(w, struct {
    		Commands map[string]Command
    		Version  string
    	}{
    		commands, version})
    }
  7. Implement the Command interface to create subcommands

    master

    To add a new subcommand to the gowrap CLI, you must implement the Command interface. This interface defines how the command handles flags, execution, and help documentation.

    Required methods:

    • FlagSet() *flag.FlagSet: Returns the command-specific flag set. Return nil if the command has no flags.
    • Run(args []string, stdout io.Writer) error: The core logic of the command. It receives the remaining arguments and an output writer.
    • ShortDescription() string: A brief summary of the command for the main help menu.
    • UsageLine() string: The usage syntax for the command (e.g., gowrap mycmd [args]).
    • HelpMessage(w io.Writer) error: Writes detailed help information to the provided writer.
    type Command interface {
    	FlagSet() *flag.FlagSet
    	Run(args []string, stdout io.Writer) error
    	ShortDescription() string
    	UsageLine() string
    	HelpMessage(w io.Writer) error
    }
  8. Initialize the `template` command with `NewTemplateCommand`

    master

    To programmatically use the template command, use NewTemplateCommand(loader). This requires an implementation of the remoteTemplateLoader interface to handle the fetching and listing of templates.

    Interface: remoteTemplateLoader

    Any object passed to NewTemplateCommand must implement these methods:

    • List() ([]string, error): Returns a slice of available template names.
    • Load(path string) (tmpl []byte, url string, err error): Given a template path, returns the template content as bytes, the source URL, and any error encountered.
  9. Register and retrieve commands via RegisterCommand

    master

    Commands are managed in a global registry. Use RegisterCommand to add a command to the gowrap CLI. When a command is registered, if it has a FlagSet, it is automatically initialized with flag.ContinueOnError and its output is redirected to io.Discard to prevent premature printing during registration.

    Use GetCommand(name string) to retrieve a registered command by its name.

    // RegisterCommand adds command to the global Commands map
    func RegisterCommand(name string, cmd Command) {
    	commands[name] = cmd
    	if fs := cmd.FlagSet(); fs != nil {
    		fs.Init("", flag.ContinueOnError)
    		fs.SetOutput(io.Discard)
    	}
    }
    
    // GetCommand returns command from the global Commands map
    func GetCommand(name string) Command {
    	return commands[name]
    }
  10. Configure 'gen' command flags

    master

    The gen command uses the following flag definitions:

    FlagTypeDescription
    -gboolDon't put //go:generate instruction to the generated code
    -istringThe source interface name, i.e. "Reader"
    -pstringThe source package import path, i.e. "io", "github.com/hexdigest/gowrap" or a relative import path like "./generator"
    -ostringThe output file name
    -tstringThe template to use (HTTPS URL, local file, or gowrap reference)
    -vvarA key-value pair to parametrize the template (e.g. -v foo=bar -v disableChecks)
    -lstringPut imports beginning with this string after 3rd-party packages; comma-separated list
  11. Template functions available in gowrap

    master

    When using templates with gowrap, you have access to sprig functions plus several custom helper functions for string manipulation:

    • up: Converts string to uppercase.
    • down: Converts string to lowercase.
    • upFirst: Capitalizes the first character of a string.
    • downFirst: Lowercases the first character of a string.
    • replace: Performs string replacement (alias for strings.ReplaceAll).
    • snake: Converts a string to snake_case.