open-vault/vault/activity_log.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
}
}