spur

package module
v0.0.0-...-995da59 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 20, 2020 License: MIT Imports: 9 Imported by: 0

README

spur

Structured Processing Uniform Results (spur) implements a set of common result types used to report processing success and or issues in a consistent manner.

Spur can be though of as structured logging that is returned to the caller rather than output.

Build Status PkgGoDev GoReportCard

Installation

Install the project to your GOPATH using

go get -u https://github.com/nehemming/spur

or clone this repo to your local machine using

git clone https://github.com/nehemming/spur

This project requires Go 1.15 or newer and supports modules.

Key features

  • Standardized result model, with severity levels, error codes and timestamps.
  • Processing results can be returned from a processing unit to its caller
  • Attach structured meta data
  • Error messages can be embedded or extracted from pulp TextProviders
  • Supports marshalling to and from JSON or YAML
  • Aggregate sets of results in a Results object

Getting started

Simple example of using as a function result

package main

import (
    "fmt"

    "github.com/nehemming/spur"
)

var (
    WorkerDone = spur.Make(1, 34)
)

func worker(input int) spur.Result {

    // worker
    // basic example with fixed error message
    return spur.NewInfo(WorkerDone, spur.NMeta("worker", 1)).
        WithMessage("Done ${worker} ${1:%03d}", input).Result()
}

func main() {

    res := worker(10)
    fmt.Println(res.Message())

    // run a few more

    results := spur.New(worker(11), worker(12))

    for _, v := range results.Results() {

        fmt.Println(v.Level(), v.Message())
    }
}

// Output:
// Done 1 010
// Info Done 1 011
// Info Done 1 012

Levels

Level Description
Success No issues and nothing to report
Info Like success but informational data logged
Warn Processing completed but there are warnings that should be investigated
Error Processing issues were encounter that prevented completion of processing
Failure A problem occurred that meant processing could not complete but can be retried later
Critical A severe issue was encounter and further processing should not continue

Success results are never stored, as such an empty Results collection can be consider successful

Embedded error messages

The result builder WithMessage function is used to add a message to the result. The message supports the formatting with expansion of either the optional args or the structured meta data.

Meta data arguments can be expanded via their meta data key in the format ${key}.

The positional arguments are expanded using ${n} where n is the args position, starting at 1.

Both positional and meta data args may have a optional format specifier added after the key name separated by a :
The format uses the standard Go formatting strings. For example ${1:%05d} output arg 1 in format %05d.
If no format is specified %v is assumed.

Integration with Pulp

The result builder can also create messages using Pulp's TextProvider framework.

To use, call the builder WithLookupMessage. This accepts a Go context which is used to locate the active message provider. If no provider is found the function uses the ShareProvider. It is also possible to append positional arguments. These are expanded using the ${n} format as above.

The TextID for the message is located using ResultCoder param passed in to the result message New function

package spur_test

import (
    "context"
    "fmt"

    "github.com/nehemming/pulp"
    "github.com/nehemming/spur"
    "golang.org/x/text/language"
)

// myPackID is the unique type to identify my language packs in pulp
type myPackID int

const (
    // Create a langPack language pack id
    // See pulp for more info on language pack ids
    LangPack = myPackID(iota)
)

// MyResultCode is the unique code type that we will use for this packages results
// The result code implements the ResultCoder interface so it can be used with spur and
// also Stringer so that the result codes output the same string as the ResultCoder interface
// will generate.
type MyResultCode int

// Create unique error code ids
const (

    // Good practice to create a Zero value messages for all types
    NoProblem = MyResultCode(iota)

    // MyWorkIsDone is the messaged id that work is complete
    MyWorkIsDone
)

func (c MyResultCode) ResultCode() spur.ResultCode {

    // The MyWorkIsDone has a underlying value of int 1
    // This demonstrates how the id can be used to create a
    // different result code value (and show its not the result code thats used to locate the message)
    return spur.Make(int(c), 19)
}

func (c MyResultCode) String() string {

    // Having gon to the effort to make result codes different
    // we can now use the result code string function to create a consistent
    // output string.
    // (ResultCode().String() actually uses pulp to find the standard output format)
    return c.ResultCode().String()
}

//myWorker does some work
func myWorker(ctx context.Context, input int) spur.Result {

    // worker
    // basic example with looked up message

    // Meta "worker" is passed in as is the input as pos arg $1
    // WithLookupMessage will use the MyWorkIsDone id to locate the result
    // message.
    return spur.NewInfo(MyWorkIsDone, spur.NMeta("worker", 1)).
        WithLookupMessage(ctx, input).Result()
}

func init() {

    // Register formats and english language pack
    pulp.Register(LangPack, func(packID pulp.LangPackID, langTag language.Tag) (pulp.TextMap, []pulp.NamedArg) {

        return pulp.TextMap{
            // creating an in line text map for simplicity.
            // the ${@id} format is a special pulp parameter that returns the string representation of the
            // the code used to look up this error message (essentially MyWorkIsDone.String() here)
            MyWorkIsDone: "Done ${worker} ${1:%03d} today ${@id}",
        }, nil
    }, pulp.Package, language.English)
}

func main() {

    res := myWorker(context.TODO(), 10)

    if res.ResultCode() != NoProblem.ResultCode() {
        fmt.Println(res.Message())
    }
    // Output:
    // Done 1 010 today 013-00001
}

Contributing

We would welcome contributions to this project. Please read our CONTRIBUTION file for further details on how you can participate or report any issues.

License

MIT

Documentation

Overview

Package spur the structured processing uniform results package. Implements a way to return uniform processing results across packages

Package spur the structured processing uniform results package. Implements a way to return uniform processing results across packages

Example
package main

import (
	"fmt"

	"github.com/nehemming/spur"
)

var (
	WorkerDone = spur.Make(1, 34)
)

func worker(input int) *spur.Result {

	// worker
	// basic example with fixed error message
	return spur.NewInfo(WorkerDone, spur.NMeta("worker", 1)).
		WithMessage("Done ${worker} ${1:%03d}", input).Result()
}

func main() {

	res := worker(10)
	fmt.Println(res.Message())

	// run a few more

	results := spur.New(worker(11), worker(12))

	for _, v := range results.Results() {

		fmt.Println(v.Level(), v.Message())
	}
}

func main() {

	main()

}
Output:

Done 1 010
Info Done 1 011
Info Done 1 012
Example (Two)
package main

import (
	"context"
	"fmt"

	"github.com/nehemming/pulp"
	"github.com/nehemming/spur"
	"golang.org/x/text/language"
)

// myPackID is the unique type to identify my language packs in pulp
type myPackID int

const (
	// Create a langPack language pack id
	// See pulp for more info on language pack ids
	LangPack = myPackID(iota)
)

// MyResultCode is the unique code type that we will use for this packages results
// The result code implements the ResultCoder interface so it can be used with spur and
// also Stringer so that the result codes output the same string as the ResultCoder interface
// will generate.
type MyResultCode int

// Create unique error code ids
const (

	// Good practice to create a Zero value messages for all types
	NoProblem = MyResultCode(iota)

	// MyWorkIsDone is the messagee id that work is complete
	MyWorkIsDone
)

func (c MyResultCode) ResultCode() spur.ResultCode {

	// The MyWorkIsDone has a underlying value of int 1
	// This demonstrates how the id can be used to create a
	// different result code value (and show its not the result code thats used to locate the message)
	return spur.Make(int(c), 19)
}

func (c MyResultCode) String() string {

	// Having gon to the effort to make result codes different
	// we can now use the result code string function to create a consistent
	// output string.
	// (ResultCode().String() actually uses pulp to find the standard output format)
	return c.ResultCode().String()
}

// myWorker does some work
func myWorker(ctx context.Context, input int) *spur.Result {

	// worker
	// basic example with looked up message

	// Meta "worker" is passed in as is the input as pos arg $1
	// WithLookupMessage will use the MyWorkIsDone id to locate the result
	// message.
	return spur.NewInfo(MyWorkIsDone, spur.NMeta("worker", 1)).
		WithLookupMessage(ctx, input).Result()
}

func init() {

	// Register formats and english language pack
	pulp.Register(LangPack, func(packID pulp.LangPackID, langTag language.Tag) (pulp.TextMap, []pulp.NamedArg) {

		return pulp.TextMap{
			// creating an in line text map for simplicity.
			// the ${@id} format is a special pulp parameter that returns the string representation of the
			// the code used to look up this error message (essentally MyWorkIsDone.String() here)
			MyWorkIsDone: "Done ${worker} ${1:%03d} today ${@id}",
		}, nil
	}, pulp.Package, language.English)
}

func main2() {

	res := myWorker(context.TODO(), 10)

	if res.ResultCode() != NoProblem.ResultCode() {
		fmt.Println(res.Message())
	}
}

func main() {

	main2()
}
Output:

Done 1 010 today 013-00001

Index

Examples

Constants

View Source
const (
	// Success success
	Success = Level(iota)

	// Info info message, non error
	Info

	// Warn non erroneous warning
	Warn

	// Error processing an item, not necessarily fatal
	Error

	// Failure in processing, possibly recoverable with a retry
	Failure

	// Critical failure, stop all further processing
	Critical
)
View Source
const GenericError = ResultCode(1)

GenericError code

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

type Builder interface {

	// WithMeta attaches meta data to a result
	WithMeta(key MetaKey, value MetaValue) Builder

	// WithMetaPairs attaches meta data to a result
	WithMetaPairs(meta ...MetaPair) Builder

	// WithMessage sets the message text
	WithMessage(message string, args ...interface{}) Builder

	// WithLookupMessage looks up the message using the pulp provider found from the context
	WithLookupMessage(ctx context.Context, args ...interface{}) Builder

	//Result the result
	Result() *Result

	//Build a results set from the single result
	Results() *Results
}

Builder creates one or more immutable results Call Result() to create a result and Results() to create a result set with one result member

func NewCritical

func NewCritical(code ResultCoder, meta ...MetaPair) Builder

NewCritical new Critical result

func NewError

func NewError(code ResultCoder, meta ...MetaPair) Builder

NewError new Error result

func NewFailure

func NewFailure(code ResultCoder, meta ...MetaPair) Builder

NewFailure new Failure result

func NewInfo

func NewInfo(code ResultCoder, meta ...MetaPair) Builder

NewInfo new Info result

func NewResult

func NewResult(level Level, code ResultCoder, meta ...MetaPair) Builder

NewResult creates a new result builder

func NewSuccess

func NewSuccess(meta ...MetaPair) Builder

NewSuccess new Success result

func NewWarn

func NewWarn(code ResultCoder, meta ...MetaPair) Builder

NewWarn new Warn result

type Level

type Level int

Level result level

func (Level) CanContinue

func (level Level) CanContinue() bool

CanContinue is true if level is less than or equal to Error

func (Level) IsSuccessful

func (level Level) IsSuccessful() bool

IsSuccessful is true if the result level is Success or Info

func (Level) String

func (level Level) String() string

String converts the errors into simple strings. This function is not localisable and is provided for development use. If localisation is needed, create an alternative textmap and convert during output

type MetaKey

type MetaKey string

MetaKey is a key used to identify a structured meta value

type MetaMap

type MetaMap map[MetaKey]MetaValue

MetaMap map of meta data

func (MetaMap) NamedArgs

func (m MetaMap) NamedArgs() []pulp.NamedArg

NamedArgs converts a MetaMap to a slice of pulp.NamedArg's This function can be used to pass meta data into the pulp GetText tall.

type MetaPair

type MetaPair struct {
	Key   MetaKey
	Value MetaValue
}

MetaPair represents a meta key value pair

func NMeta

func NMeta(key MetaKey, value MetaValue) MetaPair

NMeta create a new meta pair

type MetaValue

type MetaValue interface{}

MetaValue is the value associated with a MetaKey value

type Result

type Result struct {
	// contains filtered or unexported fields
}

Result irepresents a single result Result is best instanciated using the New functions

func (*Result) Error

func (r *Result) Error() string

func (*Result) Level

func (r *Result) Level() Level

Level gets the result level

func (*Result) MarshalJSON

func (r *Result) MarshalJSON() ([]byte, error)

MarshalJSON outputs the result in the JSON format

func (*Result) MarshalYAML

func (r *Result) MarshalYAML() (interface{}, error)

MarshalYAML outputs the result in the YAML format

func (*Result) Message

func (r *Result) Message() string

Message is the text associated with the result

func (*Result) Meta

func (r *Result) Meta(key MetaKey) MetaValue

Meta returns a specific meta value

func (*Result) MetaKeys

func (r *Result) MetaKeys() []MetaKey

MetaKeys returns the keys used in the result

func (*Result) ResultCode

func (r *Result) ResultCode() ResultCode

ResultCode gets the result code

func (*Result) String

func (r *Result) String() string

func (*Result) Timestamp

func (r *Result) Timestamp() Timestamp

Timestamp is the time the result was created

func (*Result) TryMeta

func (r *Result) TryMeta(key MetaKey) (val MetaValue, found bool)

TryMeta returns a specific meta value

func (*Result) UnmarshalJSON

func (r *Result) UnmarshalJSON(data []byte) error

UnmarshalJSON unmarshal the result from JSON

func (*Result) UnmarshalYAML

func (r *Result) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML converts YAML back to a result

type ResultCode

type ResultCode int

ResultCode is the numeric code fr the error

func Make

func Make(ids ...int) ResultCode

Make builds a result code from multiple parts

func (ResultCode) ResultCode

func (r ResultCode) ResultCode() ResultCode

ResultCode converts a result code into its self, so it can be used as a Code

func (ResultCode) String

func (r ResultCode) String() string

Convert the standard result code into XXX-ddddd format

type ResultCoder

type ResultCoder interface {
	ResultCode() ResultCode
}

ResultCoder represents any type that can be converted to a result code If pulp is used the code is used to resolve the error message string

type Results

type Results struct {
	// contains filtered or unexported fields
}

Results is a collection of results and outputs

func New

func New(r ...*Result) *Results

New create a results collection

func (*Results) AppendError

func (r *Results) AppendError(level Level, err error) *Results

AppendError appends a result to the exiting results set

func (*Results) AppendResult

func (r *Results) AppendResult(addition ...*Result) *Results

AppendResult appends a result to the exiting results set

func (*Results) AppendResults

func (r *Results) AppendResults(addition ...*Results) *Results

AppendResults appends one or more results sets to the receiver

func (*Results) Results

func (r *Results) Results() []Result

Results returns the results

func (*Results) Severity

func (r *Results) Severity() Level

Severity returns the highest severity of the results

type Timestamp

type Timestamp time.Time

Timestamp is used to record the time for logging

func (Timestamp) MarshalText

func (ts Timestamp) MarshalText() ([]byte, error)

MarshalText implements the encoding.TextMarshaler interface. Format is provided by the language pack

func (*Timestamp) UnmarshalText

func (ts *Timestamp) UnmarshalText(data []byte) error

UnmarshalText implements the encoding.TextUnmarshaler interface. The time is expected to match the format provided by the language pack

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL