109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
|
package vault
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"os"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
log "github.com/hashicorp/go-hclog"
|
||
|
"github.com/hashicorp/vault/sdk/logical"
|
||
|
"github.com/hashicorp/vault/vault/activity"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// activitySubPath is the directory under the system view where
|
||
|
// the log will be stored.
|
||
|
activitySubPath = "activity/"
|
||
|
)
|
||
|
|
||
|
// ActivityLog tracks unique entity counts and non-entity token counts.
|
||
|
// It handles assembling log fragments (and sending them to the active
|
||
|
// node), writing log segments, and precomputing queries.
|
||
|
type ActivityLog struct {
|
||
|
// log destination
|
||
|
logger log.Logger
|
||
|
|
||
|
// view is the storage location used by ActivityLog,
|
||
|
// defaults to sys/activity.
|
||
|
view logical.Storage
|
||
|
|
||
|
// nodeID is the ID to use for all fragments that
|
||
|
// are generated.
|
||
|
// TODO: use secondary ID when available?
|
||
|
nodeID string
|
||
|
|
||
|
// current log fragment (may be nil) and a mutex to protect it
|
||
|
fragmentLock sync.RWMutex
|
||
|
fragment *activity.LogFragment
|
||
|
fragmentCreation time.Time
|
||
|
}
|
||
|
|
||
|
// NewActivityLog creates an activity log.
|
||
|
func NewActivityLog(_ context.Context, logger log.Logger, view logical.Storage) (*ActivityLog, error) {
|
||
|
hostname, err := os.Hostname()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &ActivityLog{
|
||
|
logger: logger,
|
||
|
view: view,
|
||
|
nodeID: hostname,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// setupActivityLog hooks up the singleton ActivityLog into Core.
|
||
|
func (c *Core) setupActivityLog(ctx context.Context) error {
|
||
|
view := c.systemBarrierView.SubView(activitySubPath)
|
||
|
logger := c.baseLogger.Named("activity")
|
||
|
c.AddLogger(logger)
|
||
|
|
||
|
manager, err := NewActivityLog(ctx, logger, view)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
c.activityLog = manager
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (a *ActivityLog) AddEntityToFragment(entityID string, namespaceID string, timestamp time.Time) {
|
||
|
a.fragmentLock.Lock()
|
||
|
defer a.fragmentLock.Unlock()
|
||
|
|
||
|
// TODO: check whether entity ID already recorded
|
||
|
|
||
|
a.createCurrentFragment()
|
||
|
|
||
|
a.fragment.Entities = append(a.fragment.Entities,
|
||
|
&activity.EntityRecord{
|
||
|
EntityID: entityID,
|
||
|
NamespaceID: namespaceID,
|
||
|
Timestamp: timestamp.UnixNano(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (a *ActivityLog) AddTokenToFragment(namespaceID string) {
|
||
|
a.fragmentLock.Lock()
|
||
|
defer a.fragmentLock.Unlock()
|
||
|
|
||
|
a.createCurrentFragment()
|
||
|
|
||
|
a.fragment.NonEntityTokens[namespaceID] += 1
|
||
|
}
|
||
|
|
||
|
// Create the current fragment if it doesn't already exist.
|
||
|
// Must be called with the lock held.
|
||
|
func (a *ActivityLog) createCurrentFragment() {
|
||
|
if a.fragment == nil {
|
||
|
a.fragment = &activity.LogFragment{
|
||
|
OriginatingNode: a.nodeID,
|
||
|
Entities: make([]*activity.EntityRecord, 0, 120),
|
||
|
NonEntityTokens: make(map[string]uint64),
|
||
|
}
|
||
|
a.fragmentCreation = time.Now()
|
||
|
|
||
|
// TODO: start a timer to send it, if we're a performance standby
|
||
|
}
|
||
|
}
|