diff --git a/compose/app.go b/compose/app.go index bc22a5c53..e01bf2c98 100644 --- a/compose/app.go +++ b/compose/app.go @@ -62,7 +62,8 @@ func (app *App) Upgrade(ctx context.Context) (err error) { func (app *App) Initialize(ctx context.Context) (err error) { // Connects to all services it needs to err = service.Initialize(ctx, app.Log, service.Config{ - Storage: app.Opts.Storage, + ActionLog: app.Opts.ActionLog, + Storage: app.Opts.Storage, }) if err != nil { diff --git a/compose/service/service.go b/compose/service/service.go index 5b1352c37..2341644b6 100644 --- a/compose/service/service.go +++ b/compose/service/service.go @@ -30,6 +30,7 @@ type ( } Config struct { + ActionLog options.ActionLogOpt Storage options.StorageOpt GRPCClientSystem options.GRPCServerOpt } @@ -77,12 +78,22 @@ func Initialize(ctx context.Context, log *zap.Logger, c Config) (err error) { DefaultLogger = log.Named("service") - DefaultActionlog = actionlog.NewService( - // will log directly to system schema for now - actionlogRepository.Mysql(repository.DB(ctx), "sys_actionlog"), - log, - log, - ) + { + tee := log + policy := actionlog.MakeProductionPolicy() + if c.ActionLog.Debug { + tee = zap.NewNop() + policy = actionlog.MakeDebugPolicy() + } + + DefaultActionlog = actionlog.NewService( + // will log directly to system schema for now + actionlogRepository.Mysql(repository.DB(ctx).Quiet(), "sys_actionlog"), + log, + tee, + policy, + ) + } if DefaultPermissions == nil { // Do not override permissions service stored under DefaultPermissions diff --git a/messaging/app.go b/messaging/app.go index 2826dd4d7..b5acd502d 100644 --- a/messaging/app.go +++ b/messaging/app.go @@ -67,7 +67,8 @@ func (app *App) Upgrade(ctx context.Context) (err error) { func (app *App) Initialize(ctx context.Context) (err error) { // Connects to all services it needs to err = service.Initialize(ctx, app.Log, service.Config{ - Storage: app.Opts.Storage, + ActionLog: app.Opts.ActionLog, + Storage: app.Opts.Storage, }) if err != nil { diff --git a/messaging/service/service.go b/messaging/service/service.go index ac3875401..896edc344 100644 --- a/messaging/service/service.go +++ b/messaging/service/service.go @@ -31,7 +31,8 @@ type ( } Config struct { - Storage options.StorageOpt + ActionLog options.ActionLogOpt + Storage options.StorageOpt } ) @@ -60,12 +61,22 @@ var ( func Initialize(ctx context.Context, log *zap.Logger, c Config) (err error) { DefaultLogger = log.Named("service") - DefaultActionlog = actionlog.NewService( - // will log directly to system schema for now - actionlogRepository.Mysql(repository.DB(ctx), "sys_actionlog"), - log, - log, - ) + { + tee := log + policy := actionlog.MakeProductionPolicy() + if c.ActionLog.Debug { + tee = zap.NewNop() + policy = actionlog.MakeDebugPolicy() + } + + DefaultActionlog = actionlog.NewService( + // will log directly to system schema for now + actionlogRepository.Mysql(repository.DB(ctx).Quiet(), "sys_actionlog"), + log, + tee, + policy, + ) + } if DefaultPermissions == nil { // Do not override permissions service stored under DefaultPermissions diff --git a/pkg/actionlog/service.go b/pkg/actionlog/service.go index 36c21aa8e..2686b4743 100644 --- a/pkg/actionlog/service.go +++ b/pkg/actionlog/service.go @@ -22,6 +22,8 @@ type ( // logger for repository errors logger *zap.Logger + + policy policyMatcher } loggable interface { @@ -39,17 +41,18 @@ type ( } ) -// NewService initializes auditlog service +// NewService initializes action log service // -func NewService(r recordKeeper, logger, tee *zap.Logger) (svc *service) { +func NewService(r recordKeeper, logger, tee *zap.Logger, policy policyMatcher) (svc *service) { if tee == nil { tee = zap.NewNop() } svc = &service{ - tee: tee, - logger: logger, + tee: tee.Named("actionlog"), + logger: logger.Named("actionlog"), repo: r, + policy: policy, } return @@ -63,10 +66,19 @@ func (svc service) Record(ctx context.Context, l loggable) { a := enrich(ctx, l.LoggableAction()) - var ( - log = svc.logger - ) + svc.log(a) + if !svc.policy.Match(a) { + // policy does not allow us to record this + return + } + + if err := svc.repo.Record(ctx, a); err != nil { + svc.logger.With(zap.Error(err)).Error("could not record audit event") + } +} + +func (svc service) log(a *Action) { zlf := []zap.Field{ zap.Time("timestamp", a.Timestamp), zap.String("requestOrigin", a.RequestOrigin), @@ -78,18 +90,11 @@ func (svc service) Record(ctx context.Context, l loggable) { zap.Uint8("severity", uint8(a.Severity)), zap.String("error", a.Error), zap.String("description", a.Description), + zap.Bool("policy-match", svc.policy.Match(a)), zap.Any("meta", a.Meta), } - for k, v := range a.Meta { - zlf = append(zlf, zap.Any("meta."+k, v)) - } - - log.Debug(a.Description, zlf...) - - if err := svc.repo.Record(ctx, a); err != nil { - log.With(zap.Error(err)).Error("could not record audit event") - } + svc.tee.With(zlf...).Debug(a.Description) } func (svc service) Find(ctx context.Context, flt Filter) (ActionSet, Filter, error) { diff --git a/pkg/app/options.go b/pkg/app/options.go index abc1f617b..4a92f9f06 100644 --- a/pkg/app/options.go +++ b/pkg/app/options.go @@ -6,6 +6,7 @@ import ( type ( Options struct { + ActionLog options.ActionLogOpt SMTP options.SMTPOpt Auth options.AuthOpt HTTPClient options.HTTPClientOpt @@ -30,6 +31,7 @@ func NewOptions(prefix ...string) *Options { } return &Options{ + ActionLog: *options.ActionLog(), Auth: *options.Auth(), SMTP: *options.SMTP(p), HTTPClient: *options.HttpClient(p), diff --git a/pkg/app/options/actionlog.go b/pkg/app/options/actionlog.go new file mode 100644 index 000000000..c15d1d1ed --- /dev/null +++ b/pkg/app/options/actionlog.go @@ -0,0 +1,17 @@ +package options + +type ( + ActionLogOpt struct { + Debug bool `env:"ACTIONLOG_DEBUG"` + } +) + +func ActionLog() (o *ActionLogOpt) { + o = &ActionLogOpt{ + Debug: false, + } + + fill(o, "") + + return +} diff --git a/system/app.go b/system/app.go index be37a54ce..9fe950013 100644 --- a/system/app.go +++ b/system/app.go @@ -63,7 +63,8 @@ func (app *App) Upgrade(ctx context.Context) (err error) { func (app *App) Initialize(ctx context.Context) (err error) { // Connects to all services it needs to err = service.Initialize(ctx, app.Log, service.Config{ - Storage: app.Opts.Storage, + ActionLog: app.Opts.ActionLog, + Storage: app.Opts.Storage, }) if err != nil { diff --git a/system/service/service.go b/system/service/service.go index 104afda5d..70ca5acdf 100644 --- a/system/service/service.go +++ b/system/service/service.go @@ -30,6 +30,7 @@ type ( } Config struct { + ActionLog options.ActionLogOpt Storage options.StorageOpt GRPCClientSystem options.GRPCServerOpt } @@ -94,11 +95,21 @@ var ( func Initialize(ctx context.Context, log *zap.Logger, c Config) (err error) { DefaultLogger = log.Named("service") - DefaultActionlog = actionlog.NewService( - actionlogRepository.Mysql(repository.DB(ctx), "sys_actionlog"), - log, - log, - ) + { + tee := log + policy := actionlog.MakeProductionPolicy() + if c.ActionLog.Debug { + tee = zap.NewNop() + policy = actionlog.MakeDebugPolicy() + } + + DefaultActionlog = actionlog.NewService( + actionlogRepository.Mysql(repository.DB(ctx).Quiet(), "sys_actionlog"), + log, + tee, + policy, + ) + } if DefaultPermissions == nil { // Do not override permissions service stored under DefaultPermissions