logtags

package module
v0.0.0-...-21c5414 Latest Latest
Warning

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

Go to latest
Published: Jan 18, 2023 License: Apache-2.0 Imports: 3 Imported by: 883

README

logtags: key/value annotations for Go contexts

This package provides a way to attach key/value annotations to a Go context.Context.

This feature is used e.g. in CockroachDB to annotate contexts with user-facing details from the call stack, for use in logging output.

How to use:

  • adding k/v data to a context:

    func AddTag(ctx context.Context, key string, value interface{}) context.Context
    

    For example:

    func foo(ctx context.Context) {
        ctx = logtags.AddTag(ctx, "foo", 123)
        bar(ctx)
    }
    
  • retrieving k/v data from a context:

    func FromContext(ctx context.Context) *Buffer
    func (b *Buffer) Get() []Tag
    func (t *Tag) Key() string
    func (t *Tag) Value() interface{}
    

How it works:

logtags stores the provided key/value pairs into an object of type Buffer, then uses Go's standard context.WithValue to attach the buffer.

An instance of Buffer inside a context is immutable. When adding a new k/v pair to a context that already carries a Buffer, a new one is created with all previous k/v pair, and the new k/v pair is added to that.

The FromContext() function retrieves the topmost (most recent) Buffer.

Advanced uses:

To add multiple k/v pairs in one go, without using quadratic space in Buffer instances:

  1. manually instantiate a Buffer.
  2. use func (*Buffer) Add(key string, value interface{}) to populate the buffer.
  3. use func AddTags(ctx context.Context, tags *Buffer) context.Context to embark all the k/v pairs at once.

To format all the contained k/v pairs in a Buffer, use its String() or FormatToString(*strings.Builder) methods:

  • when the value part is nil, only the key is displayed.
  • when the value part is non-nil, and the key is just one character long, the key and value are concatenated for display. This enables e.g. printing k="n", v=123 as n123.
  • otherwise, the key and value are printed with = as separator.

For example:

   ctx = logtags.AddTag(ctx, "foo", 123)
   ctx = logtags.AddTag(ctx, "x", 456)
   ctx = logtags.AddTag(ctx, "bar", nil)
   fmt.Println(logtags.FromContext(ctx).String())
   // prints foo=123,x456,bar

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddTag

func AddTag(ctx context.Context, key string, value interface{}) context.Context

AddTag returns a context that has the tags in the given context plus another tag. Tags are deduplicated (see Buffer.AddTag).

func AddTags

func AddTags(ctx context.Context, tags *Buffer) context.Context

AddTags returns a context that has the tags in the given context plus another set of tags. Tags are deduplicated (see Buffer.AddTags).

func RemoveTag

func RemoveTag(ctx context.Context, key string) context.Context

RemoveTag returns a context that has the tags in the given context except the tag with key `key`. If such a tag does not exist, the given context is returned.

func WithTags

func WithTags(ctx context.Context, tags *Buffer) context.Context

WithTags returns a context with the given tags. Any existing tags are ignored.

Types

type Buffer

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

Buffer is an immutable list of Tags.

func FromContext

func FromContext(ctx context.Context) *Buffer

FromContext returns the tags stored in the context (by WithTags, AddTag, or AddTags).

func SingleTagBuffer

func SingleTagBuffer(key string, value interface{}) *Buffer

SingleTagBuffer returns a Buffer with a single tag.

func (*Buffer) Add

func (b *Buffer) Add(key string, value interface{}) *Buffer

Add returns a new buffer with one more tag. If the tag has the same key as an earlier tag, that tag is overwritten. The receiver can be nil.

func (*Buffer) FormatToString

func (b *Buffer) FormatToString(buf *strings.Builder)

FormatToString emits the k/v pairs to a strings.Builder.

  • the k/v pairs are separated by commas (& no spaces).
  • if there is no value, only the key is printed.
  • if there is a value, and the key is just 1 character long, the key and the value are concatenated. This supports e.g. printing k="n", v=123 as "n123".
  • otherwise, it prints "k=v".

func (*Buffer) Get

func (b *Buffer) Get() []Tag

Get returns the tags, as a slice. This slice must not be modified.

func (*Buffer) GetTag

func (b *Buffer) GetTag(key string) (Tag, bool)

GetTag returns the tag corresponding to the given key. If the tag doesn't exist, the bool return value will be false.

func (*Buffer) Merge

func (b *Buffer) Merge(other *Buffer) *Buffer

Merge returns a new buffer which contains tags from the receiver, followed by the tags from <other>.

If both buffers have the same tag, the tag will appear only one time, with the value it has in <other>. It can appear either in the place of the tag in <b> or the tag in <other> (depending on which is deemed more efficient).

The method can return <b> or <other> if the result is identical with one of them.

The receiver can be nil.

func (*Buffer) Remove

func (b *Buffer) Remove(key string) (*Buffer, bool)

Remove returns a new Buffer with the tag with key `key` removed. If the tag does not exist, the receiver is returned (unchanged). The bool return value is true if the tag existed.

func (*Buffer) String

func (b *Buffer) String() string

String returns a string representation of the tags.

type Tag

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

Tag is a log tag, which has a string key and an arbitrary value. The value must support testing for equality. It can be nil.

func (*Tag) Key

func (t *Tag) Key() string

Key returns the key.

func (*Tag) Value

func (t *Tag) Value() interface{}

Value returns the value.

func (*Tag) ValueStr

func (t *Tag) ValueStr() string

ValueStr returns the value as a string.

Jump to

Keyboard shortcuts

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