Documentation ¶
Overview ¶
Package whatnot is a low-footprint, high-speed, cluster-friendly volatile system for providing etcd-like distributed semaphores on hierarchical resource identifiers with subscribable watch notifications.
It is intended to replace the functionality of systems like Redis and Etcd, in situations where data persistence over long periods of time is not an issue, additional infrastructure is not desired, and peer-to-peer sharing of data is a preferable solution for extreme low-latency
Whatnot (a far more informal rendering of 'etcetera') was driven by a desire to utilize the namespace subscription capabilities of Etcd, without the investment in storage and memory it required to maintain persistent data, a feature I did not require at the time.
Index ¶
- Constants
- Variables
- func HealthHandler(r *http.Request, w http.ResponseWriter)
- func Healthy() bool
- type AbsolutePath
- type ConfigError
- type ElementValue
- type ElementWatchSubscription
- func (n ElementWatchSubscription) Debug(msg string)
- func (n ElementWatchSubscription) Debugf(format string, a ...interface{})
- func (n ElementWatchSubscription) Error(msg string)
- func (n ElementWatchSubscription) Errorf(format string, a ...interface{})
- func (m *ElementWatchSubscription) Events() <-chan WatchEvent
- func (n ElementWatchSubscription) Info(msg string)
- func (n ElementWatchSubscription) Infof(format string, a ...interface{})
- func (n ElementWatchSubscription) Warn(msg string)
- func (n ElementWatchSubscription) Warnf(format string, a ...interface{})
- type EventMultiplexer
- func (t *EventMultiplexer) BroadcastAsync(evt WatchEvent)
- func (n EventMultiplexer) Debug(msg string)
- func (n EventMultiplexer) Debugf(format string, a ...interface{})
- func (n EventMultiplexer) Error(msg string)
- func (n EventMultiplexer) Errorf(format string, a ...interface{})
- func (n EventMultiplexer) Info(msg string)
- func (n EventMultiplexer) Infof(format string, a ...interface{})
- func (t *EventMultiplexer) Register(ch chan<- WatchEvent, recursive bool)
- func (t *EventMultiplexer) Unregister(ch chan<- WatchEvent)
- func (n EventMultiplexer) Warn(msg string)
- func (n EventMultiplexer) Warnf(format string, a ...interface{})
- type LeaseContext
- func (l *LeaseContext) Cancel()
- func (l *LeaseContext) Deadline() (time.Time, bool)
- func (n LeaseContext) Debug(msg string)
- func (n LeaseContext) Debugf(format string, a ...interface{})
- func (l *LeaseContext) Done() <-chan struct{}
- func (l *LeaseContext) Err() error
- func (n LeaseContext) Error(msg string)
- func (n LeaseContext) Errorf(format string, a ...interface{})
- func (n LeaseContext) Info(msg string)
- func (n LeaseContext) Infof(format string, a ...interface{})
- func (l *LeaseContext) Value(key interface{}) interface{}
- func (n LeaseContext) Warn(msg string)
- func (n LeaseContext) Warnf(format string, a ...interface{})
- type Logger
- type ManagerOption
- type NameSpaceManager
- func (n NameSpaceManager) Debug(msg string)
- func (n NameSpaceManager) Debugf(format string, a ...interface{})
- func (n NameSpaceManager) Error(msg string)
- func (n NameSpaceManager) Errorf(format string, a ...interface{})
- func (m *NameSpaceManager) FetchNamespace(name string) (ns *Namespace, err error)
- func (n NameSpaceManager) Info(msg string)
- func (n NameSpaceManager) Infof(format string, a ...interface{})
- func (m *NameSpaceManager) RegisterNamespace(ns *Namespace) error
- func (m *NameSpaceManager) UnRegisterNamespace(ns *Namespace) error
- func (n NameSpaceManager) Warn(msg string)
- func (n NameSpaceManager) Warnf(format string, a ...interface{})
- type Namespace
- func (ns *Namespace) FetchAbsolutePath(path PathString) *PathElement
- func (ns *Namespace) FetchAllAbsolutePaths() (allpaths []AbsolutePath, err error)
- func (ns *Namespace) FetchOrCreateAbsolutePath(path PathString) (elem *PathElement, err error)
- func (ns *Namespace) FindPathTail(path PathString) *PathElement
- func (ns *Namespace) RegisterAbsolutePath(path AbsolutePath) error
- type NamespaceManagerOpt
- type PathElement
- func (p *PathElement) AbsolutePath() (path AbsolutePath)
- func (p *PathElement) Add(path SubPath) (elem *PathElement, err error)
- func (p *PathElement) AppendRelativePath(subPath PathString) (*PathElement, error)
- func (p *PathElement) Chain() (chain []*PathElement)
- func (p *PathElement) ContextLockPrefixWithLease(octx context.Context, ttl time.Duration) (ctx *LeaseContext, release func())
- func (p *PathElement) ContextLockWithLease(octx context.Context, ttl time.Duration) (ctx *LeaseContext, release func())
- func (p *PathElement) CreateSemaphorePool(prefix bool, purge bool, opts SemaphorePoolOpts) (err error)
- func (n PathElement) Debug(msg string)
- func (n PathElement) Debugf(format string, a ...interface{})
- func (p *PathElement) Delete() (err error)
- func (p *PathElement) EnablePruningAfter(age time.Duration)
- func (n PathElement) Error(msg string)
- func (n PathElement) Errorf(format string, a ...interface{})
- func (p *PathElement) FetchAllSubPaths() (allpaths [][]SubPath, err error)
- func (p *PathElement) FetchClosestSubPath(subPath PathString) (pathchain []*PathElement)
- func (p PathElement) FetchClosestSubPathTail(subPath PathString) *PathElement
- func (p *PathElement) FetchSubPath(subPath PathString) (*PathElement, error)
- func (p *PathElement) GetValue() (value ElementValue)
- func (n PathElement) Info(msg string)
- func (n PathElement) Infof(format string, a ...interface{})
- func (p *PathElement) Lock()
- func (p *PathElement) LockPrefixWithLease(ttl time.Duration) (ctx *LeaseContext, release func())
- func (p *PathElement) LockSubs()
- func (p *PathElement) LockWithLease(ttl time.Duration) (ctx *LeaseContext, release func())
- func (p *PathElement) Parent() *PathElement
- func (p *PathElement) ParentChain() (parents []*PathElement)
- func (p *PathElement) PreventPruning()
- func (p *PathElement) SetValue(value ElementValue, change changeType, actor access.Role)
- func (p *PathElement) SubPath() (path SubPath)
- func (p *PathElement) SubscribeToEvents(prefix bool) *ElementWatchSubscription
- func (p *PathElement) UnLock()
- func (p *PathElement) UnLockSubs()
- func (p *PathElement) UnSubscribeFromEvents(sub *ElementWatchSubscription)
- func (n PathElement) Warn(msg string)
- func (n PathElement) Warnf(format string, a ...interface{})
- type PathError
- type PathString
- type RelativePath
- type SemaphoreClaim
- type SemaphorePool
- type SemaphorePoolOpts
- type SubPath
- type WatchEvent
- type WatchEvents
- type WithLogger
Constants ¶
const ( MaxPathDepth = 50 MaxPathLength = 4096 )
const ( ChangeUnknown changeType = iota + 1 ChangeLocked ChangeUnlocked ChangeAdded ChangeEdited ChangeDeleted ChangePruned ChangeReleased )
Variables ¶
var WithAcls managerOptionFunc = func() optionName {
return optionAcls
}
WithAcls turns on Whatnot's Access Control Management on individual Path Elements
var WithDeadlockBreak managerOptionFunc = func() optionName {
return optionBreak
}
WithDeadlockBreak turns on Whatnot's Self-healing breaking of Mutex Deadlocks
var WithGossip managerOptionFunc = func() optionName {
return optionDiscoverGossip
}
WithGossip enables Gossip protocol Cluster member discovery of other instances running the whatNot gRPC connector
var WithPruning managerOptionFunc = func() optionName {
return optionAcls
}
WithPruning turns on Whatnot's automatic pruning of Unused PathElement Tree sections after they remain unused for a given amount of time
var WithRaft managerOptionFunc = func() optionName {
return optionSyncRaft
}
WithRaft enables Raft Quorum synchromization - improving cluster accuracy at a slight speed and bandwith cost
var WithRateLimit = func() optionName {
return optionRateLimit
}
var WithTrace managerOptionFunc = func() optionName {
return optionTrace
}
WithTrace enables extended tracing of Resource Locking and Wait Queues
Functions ¶
func HealthHandler ¶ added in v0.6.0
func HealthHandler(r *http.Request, w http.ResponseWriter)
HealthHandler is an HTTP HandlerFunc to attach this to your appropriate HTTP Healthcheck Endpoint
Types ¶
type AbsolutePath ¶
type AbsolutePath []SubPath
AbsolutePath is the fully-qualified path to a single PathElement from the root of the Namespace it resides in
func (AbsolutePath) SubtractPath ¶
func (m AbsolutePath) SubtractPath(path AbsolutePath) PathString
SubtractPath removes the right-hand-size RelativePath from the AbsolutePath
func (AbsolutePath) ToPathString ¶
func (m AbsolutePath) ToPathString() PathString
ToPathString converts an absolute path back into a delimited string
type ConfigError ¶ added in v0.7.0
type ConfigError struct {
// contains filtered or unexported fields
}
type ElementValue ¶
type ElementValue struct {
Val interface{}
}
type ElementWatchSubscription ¶
type ElementWatchSubscription struct {
// contains filtered or unexported fields
}
ElementWatchSubscription is a contract to be notified of all events on a given Path Element, and optionally all its child elements
func (ElementWatchSubscription) Debug ¶ added in v0.6.0
func (n ElementWatchSubscription) Debug(msg string)
func (ElementWatchSubscription) Debugf ¶ added in v0.6.0
func (n ElementWatchSubscription) Debugf(format string, a ...interface{})
func (ElementWatchSubscription) Error ¶ added in v0.6.0
func (n ElementWatchSubscription) Error(msg string)
func (ElementWatchSubscription) Errorf ¶ added in v0.6.0
func (n ElementWatchSubscription) Errorf(format string, a ...interface{})
func (*ElementWatchSubscription) Events ¶
func (m *ElementWatchSubscription) Events() <-chan WatchEvent
Events returns a channel of subscriberNotify occurring to this Key (or its subKeys
func (ElementWatchSubscription) Info ¶ added in v0.6.0
func (n ElementWatchSubscription) Info(msg string)
func (ElementWatchSubscription) Infof ¶ added in v0.6.0
func (n ElementWatchSubscription) Infof(format string, a ...interface{})
type EventMultiplexer ¶
type EventMultiplexer struct { // Broadcast is the channel to set events to for them to be multiplexed out Broadcast chan<- WatchEvent // contains filtered or unexported fields }
EventMultiplexer is a pub-sub mechanism where consumers can Register to receive messages sent to Broadcast.
func NewEventsMultiplexer ¶ added in v0.6.0
func NewEventsMultiplexer() *EventMultiplexer
NewEventsMultiplexer creates a new event multiplexer that will duplicate incoming WatchEvents to multiple watcher channels
func (*EventMultiplexer) BroadcastAsync ¶
func (t *EventMultiplexer) BroadcastAsync(evt WatchEvent)
BroadcastAsync has the multiplexer submit the WatchEvent instead of the caller attaching directly to a channel delivery is not guaranteed in this case and the goroutine will eventually exit if it deadlocks
func (EventMultiplexer) Debugf ¶ added in v0.6.0
func (n EventMultiplexer) Debugf(format string, a ...interface{})
func (EventMultiplexer) Errorf ¶ added in v0.6.0
func (n EventMultiplexer) Errorf(format string, a ...interface{})
func (EventMultiplexer) Infof ¶ added in v0.6.0
func (n EventMultiplexer) Infof(format string, a ...interface{})
func (*EventMultiplexer) Register ¶
func (t *EventMultiplexer) Register(ch chan<- WatchEvent, recursive bool)
Register starts receiving messages on the given channel. If a channel close is seen, either the topic has been shut down, or the consumer was too slow, and should re-register.
func (*EventMultiplexer) Unregister ¶
func (t *EventMultiplexer) Unregister(ch chan<- WatchEvent)
Unregister stops receiving messages on this channel.
type LeaseContext ¶
type LeaseContext struct {
// contains filtered or unexported fields
}
LeaseContext implements Element Locking Lease control as a Context Interface object it is heavily recommend to use this as the context object for the rest of your functions lifetime to keep it in sync with the accordant lease it was generated with to enable your code to control and react to lease expiration
func (*LeaseContext) Cancel ¶
func (l *LeaseContext) Cancel()
Cancel implements the Context interface
func (*LeaseContext) Deadline ¶
func (l *LeaseContext) Deadline() (time.Time, bool)
Deadline implements the Context interface
func (LeaseContext) Debugf ¶ added in v0.6.0
func (n LeaseContext) Debugf(format string, a ...interface{})
func (*LeaseContext) Done ¶
func (l *LeaseContext) Done() <-chan struct{}
Done implements the Context interface
func (LeaseContext) Errorf ¶ added in v0.6.0
func (n LeaseContext) Errorf(format string, a ...interface{})
func (LeaseContext) Infof ¶ added in v0.6.0
func (n LeaseContext) Infof(format string, a ...interface{})
func (*LeaseContext) Value ¶
func (l *LeaseContext) Value(key interface{}) interface{}
Value implements the Context interface
type Logger ¶
type Logger interface { Debug(msg string) Debugf(format string, a ...interface{}) Info(msg string) Infof(format string, a ...interface{}) Warn(msg string) Warnf(format string, a ...interface{}) Error(msg string) Errorf(format string, a ...interface{}) }
Logger allows you to implement/attach your own logger
type ManagerOption ¶
type ManagerOption interface {
// contains filtered or unexported methods
}
type NameSpaceManager ¶
type NameSpaceManager struct {
// contains filtered or unexported fields
}
NameSpaceManager provides top-level management of unique element namespaces
func NewNamespaceManager ¶
func NewNamespaceManager(opts ...ManagerOption) (nsm *NameSpaceManager, err error)
NewNamespaceManager create a top-level namespace manager, to contain multiple subscribable namespaces you probably only want to call this once, to initialize WhatNot, but who am I to tell you what your use cases are
func (NameSpaceManager) Debugf ¶ added in v0.7.0
func (n NameSpaceManager) Debugf(format string, a ...interface{})
func (NameSpaceManager) Errorf ¶ added in v0.7.0
func (n NameSpaceManager) Errorf(format string, a ...interface{})
func (*NameSpaceManager) FetchNamespace ¶
func (m *NameSpaceManager) FetchNamespace(name string) (ns *Namespace, err error)
FetchNamespace gets you access to the requested namespace understandably most other operations involving a namespace's contents begin here
func (NameSpaceManager) Infof ¶ added in v0.7.0
func (n NameSpaceManager) Infof(format string, a ...interface{})
func (*NameSpaceManager) RegisterNamespace ¶
func (m *NameSpaceManager) RegisterNamespace(ns *Namespace) error
RegisterNamespace actives a name Namespace into the list of actively available and subscribable namespaces
func (*NameSpaceManager) UnRegisterNamespace ¶
func (m *NameSpaceManager) UnRegisterNamespace(ns *Namespace) error
UnRegisterNamespace will completely remove a given namespace all the properties, leases, subscriptions, etc within it.
type Namespace ¶
type Namespace struct {
// contains filtered or unexported fields
}
Namespace provides unique namespaces for keyval trees
func NewNamespace ¶
NewNamespace creates a new Namespace Instance. If this is intended to be persisted it should be registered to a NamespaceManager via RegisterNameSpace
func (*Namespace) FetchAbsolutePath ¶
func (ns *Namespace) FetchAbsolutePath(path PathString) *PathElement
FetchAbsolutePath will return the PathElement instance at the end of the provided Path assuming it exists, otherwise it returns Nil
func (*Namespace) FetchAllAbsolutePaths ¶
func (ns *Namespace) FetchAllAbsolutePaths() (allpaths []AbsolutePath, err error)
FetchAllAbsolutePaths returns an array of all distinct terminayted absolute paths effectively dumping all possible paths in the entire namespace
func (*Namespace) FetchOrCreateAbsolutePath ¶ added in v0.8.1
func (ns *Namespace) FetchOrCreateAbsolutePath(path PathString) (elem *PathElement, err error)
func (*Namespace) FindPathTail ¶
func (ns *Namespace) FindPathTail(path PathString) *PathElement
FindPathTail attempts to locate the last element that most closely matches the given path fragment if no suitable match can be found, it returns Nil, if multiple elements are found, it returns the first one going from alphabetically-sorted pathing
func (*Namespace) RegisterAbsolutePath ¶
func (ns *Namespace) RegisterAbsolutePath(path AbsolutePath) error
RegisterAbsolutePath constructs a complete path in the Namespace, with all required structure instances to make the path immediately available and active
type NamespaceManagerOpt ¶
type NamespaceManagerOpt interface {
// contains filtered or unexported methods
}
type PathElement ¶
type PathElement struct {
// contains filtered or unexported fields
}
PathElement is an individual section of a complete path
func (*PathElement) AbsolutePath ¶
func (p *PathElement) AbsolutePath() (path AbsolutePath)
AbsolutePath returns the full Path of this Element, as a single AbsolutePath instance
func (*PathElement) Add ¶
func (p *PathElement) Add(path SubPath) (elem *PathElement, err error)
Add a Single subpath Element to this Element
func (*PathElement) AppendRelativePath ¶
func (p *PathElement) AppendRelativePath(subPath PathString) (*PathElement, error)
AppendRelativePath constructs an element-relative subpath, append it to an Existing PathElement, creating all PathElements along the way
func (*PathElement) Chain ¶
func (p *PathElement) Chain() (chain []*PathElement)
Chain returns the full Path of this Element, as a slice of individual PathElements
func (*PathElement) ContextLockPrefixWithLease ¶
func (p *PathElement) ContextLockPrefixWithLease(octx context.Context, ttl time.Duration) (ctx *LeaseContext, release func())
ContextLockPrefixWithLease will lock a path element and all sub-elements with a timed lease on the lock you provide the context instance to have external control to cancel it before timeout
func (*PathElement) ContextLockWithLease ¶
func (p *PathElement) ContextLockWithLease(octx context.Context, ttl time.Duration) (ctx *LeaseContext, release func())
ContextLockWithLease will lock a single path element with a timed lease on the lock you provide the context instance to have external control to cancel it before timeout
func (*PathElement) CreateSemaphorePool ¶ added in v0.8.0
func (p *PathElement) CreateSemaphorePool(prefix bool, purge bool, opts SemaphorePoolOpts) (err error)
CreateSemaphorePool instantiates a semaphore pool on this path element. prefix will attach the pool to all child elements purge will remove any existing semaphore pool, including from all children if prefix is true
func (PathElement) Debugf ¶ added in v0.6.0
func (n PathElement) Debugf(format string, a ...interface{})
func (*PathElement) Delete ¶ added in v0.8.0
func (p *PathElement) Delete() (err error)
func (*PathElement) EnablePruningAfter ¶ added in v0.8.0
func (p *PathElement) EnablePruningAfter(age time.Duration)
func (PathElement) Errorf ¶ added in v0.6.0
func (n PathElement) Errorf(format string, a ...interface{})
func (*PathElement) FetchAllSubPaths ¶
func (p *PathElement) FetchAllSubPaths() (allpaths [][]SubPath, err error)
FetchAllSubPaths returns the SubPath location of all descendent PathElements underneath this PathElement
func (*PathElement) FetchClosestSubPath ¶
func (p *PathElement) FetchClosestSubPath(subPath PathString) (pathchain []*PathElement)
FetchClosestSubPath will attempt to find the final Path Element that has the leading subpath string - this is relative to the pathelement itself, and is not an absolute path.
func (PathElement) FetchClosestSubPathTail ¶
func (p PathElement) FetchClosestSubPathTail(subPath PathString) *PathElement
FetchClosestSubPathTail finds the last element in a path chain that most closely resembles the requested path
func (*PathElement) FetchSubPath ¶
func (p *PathElement) FetchSubPath(subPath PathString) (*PathElement, error)
func (*PathElement) GetValue ¶
func (p *PathElement) GetValue() (value ElementValue)
func (PathElement) Infof ¶ added in v0.6.0
func (n PathElement) Infof(format string, a ...interface{})
func (*PathElement) Lock ¶
func (p *PathElement) Lock()
Lock places a Mutex on this pathElement and sends a notification of this lock to its chain of parent elements this also fulfills the interface Sync.Locker
func (*PathElement) LockPrefixWithLease ¶
func (p *PathElement) LockPrefixWithLease(ttl time.Duration) (ctx *LeaseContext, release func())
LockPrefixWithLease will lock a path element and all sub-elements with a timed lease on the lock it uses a a background context so cannot be cancelled before the lease expires
func (*PathElement) LockSubs ¶
func (p *PathElement) LockSubs()
LockSubs will lock this Path Element and every Path Element it is a parent to
func (*PathElement) LockWithLease ¶
func (p *PathElement) LockWithLease(ttl time.Duration) (ctx *LeaseContext, release func())
LockWithLease will lock a single path element with a timed lease on the lock it uses a a background context so cannot be cancelled before the lease expires
func (*PathElement) Parent ¶
func (p *PathElement) Parent() *PathElement
Parent returns the parent PathElement of this PathElement
func (*PathElement) ParentChain ¶
func (p *PathElement) ParentChain() (parents []*PathElement)
ParentChain returns a slice of this Path Elements parent Pathelements, in order of parentage i.e, the first item is this elements immediate parent the last item is always the top-level (leftmost) pathelement
func (*PathElement) PreventPruning ¶ added in v0.8.0
func (p *PathElement) PreventPruning()
func (*PathElement) SetValue ¶
func (p *PathElement) SetValue(value ElementValue, change changeType, actor access.Role)
func (*PathElement) SubPath ¶
func (p *PathElement) SubPath() (path SubPath)
SubPath returns the name of this Path Element without the parent section of the path eg the 'file' portion of the path
func (*PathElement) SubscribeToEvents ¶
func (p *PathElement) SubscribeToEvents(prefix bool) *ElementWatchSubscription
SubscribeToEvents generates a Watch Subscription that produces a single channel of notification events on the accompanying Path Element, and optionally all of its child path elements
func (*PathElement) UnLock ¶
func (p *PathElement) UnLock()
UnLock will release the Mutex Lock on this path element Note that it will NOT unlock mutexes on sub-element unlocking will sent a notification event to the chain of parent elements this also fulfills the interface Sync.Locker
func (*PathElement) UnLockSubs ¶
func (p *PathElement) UnLockSubs()
func (*PathElement) UnSubscribeFromEvents ¶
func (p *PathElement) UnSubscribeFromEvents(sub *ElementWatchSubscription)
UnSubscribeFromEvents will unregister the notification channel and then nil out the watch subscription that is passed to it. preventing any further reception of events
type PathError ¶
type PathError struct { }
PathError indicates that processing a provided path was not possible either it a not a valid path identifier, or not a path that can be resolved.
type PathString ¶
type PathString string
PathString is a string representation of all or part of a hierarchical set of resources in a namespace
func (PathString) ToAbsolutePath ¶
func (m PathString) ToAbsolutePath() AbsolutePath
ToAbsolutePath converts a PathString into an AbsolutePath (a slice of ordered SubPath sections)
func (PathString) ToRelativePath ¶
func (m PathString) ToRelativePath() RelativePath
ToRelativePath breaks down a path string into a relative Path
type RelativePath ¶
type RelativePath []SubPath
RelativePath is the path to a single PathElement relative to a single PathElement somewhere in its parent chain
type SemaphoreClaim ¶ added in v0.8.0
type SemaphoreClaim struct {
// contains filtered or unexported fields
}
func (*SemaphoreClaim) Return ¶ added in v0.8.0
func (p *SemaphoreClaim) Return() error
Return releases the semaphore claim back to the pool
type SemaphorePool ¶ added in v0.8.0
type SemaphorePool struct {
// contains filtered or unexported fields
}
SemaphorePool is a combined semaphore for use by a PathElement and all its sub Elements
func (*SemaphorePool) Claim ¶ added in v0.8.1
func (p *SemaphorePool) Claim(ctx context.Context, slots int64) (claim *SemaphoreClaim, err error)
with use the provided context for timeout/cancellation
type SemaphorePoolOpts ¶ added in v0.8.0
type SubPath ¶
type SubPath string
SubPath is a path element identifier akin to the directory names between path delimeters
type WatchEvent ¶
type WatchEvent struct { TS time.Time Change changeType Actor access.Role Note string // contains filtered or unexported fields }
WatchEvent describes an event on a Path Element or optionally any of its children, obtained and consumed via an ElementWatchSubscription
func (WatchEvent) OnElement ¶
func (e WatchEvent) OnElement() *PathElement
type WatchEvents ¶
type WatchEvents chan WatchEvent
type WithLogger ¶ added in v0.7.0
type WithLogger struct {
// contains filtered or unexported fields
}
WithLogger attaches a Logger to the Namespace manager allowing you to insert your own logging solution into Whatnot