-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
865 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
package newdbplugin | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"net/url" | ||
"strings" | ||
"time" | ||
|
||
metrics "github.com/armon/go-metrics" | ||
"github.com/hashicorp/errwrap" | ||
log "github.com/hashicorp/go-hclog" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
// /////////////////////////////////////////////////// | ||
// Tracing Middleware | ||
// /////////////////////////////////////////////////// | ||
|
||
var _ Database = databaseTracingMiddleware{} | ||
|
||
// databaseTracingMiddleware wraps a implementation of Database and executes | ||
// trace logging on function call. | ||
type databaseTracingMiddleware struct { | ||
next Database | ||
logger log.Logger | ||
} | ||
|
||
func (mw databaseTracingMiddleware) Initialize(ctx context.Context, req InitializeRequest) (resp InitializeResponse, err error) { | ||
defer func(then time.Time) { | ||
mw.logger.Trace("initialize", | ||
"status", "finished", | ||
"verify", req.VerifyConnection, | ||
"err", err, | ||
"took", time.Since(then)) | ||
}(time.Now()) | ||
|
||
mw.logger.Trace("initialize", "status", "started") | ||
return mw.next.Initialize(ctx, req) | ||
} | ||
|
||
func (mw databaseTracingMiddleware) NewUser(ctx context.Context, req NewUserRequest) (resp NewUserResponse, err error) { | ||
defer func(then time.Time) { | ||
mw.logger.Trace("create user", | ||
"status", "finished", | ||
"err", err, | ||
"took", time.Since(then)) | ||
}(time.Now()) | ||
|
||
mw.logger.Trace("create user", | ||
"status", "started") | ||
return mw.next.NewUser(ctx, req) | ||
} | ||
|
||
func (mw databaseTracingMiddleware) UpdateUser(ctx context.Context, req UpdateUserRequest) (resp UpdateUserResponse, err error) { | ||
defer func(then time.Time) { | ||
mw.logger.Trace("update user", | ||
"status", "finished", | ||
"err", err, | ||
"took", time.Since(then)) | ||
}(time.Now()) | ||
|
||
mw.logger.Trace("update user", "status", "started") | ||
return mw.next.UpdateUser(ctx, req) | ||
} | ||
|
||
func (mw databaseTracingMiddleware) DeleteUser(ctx context.Context, req DeleteUserRequest) (resp DeleteUserResponse, err error) { | ||
defer func(then time.Time) { | ||
mw.logger.Trace("delete user", | ||
"status", "finished", | ||
"err", err, | ||
"took", time.Since(then)) | ||
}(time.Now()) | ||
|
||
mw.logger.Trace("delete user", | ||
"status", "started") | ||
return mw.next.DeleteUser(ctx, req) | ||
} | ||
|
||
func (mw databaseTracingMiddleware) Type() (string, error) { | ||
return mw.next.Type() | ||
} | ||
|
||
func (mw databaseTracingMiddleware) Close() (err error) { | ||
defer func(then time.Time) { | ||
mw.logger.Trace("close", | ||
"status", "finished", | ||
"err", err, | ||
"took", time.Since(then)) | ||
}(time.Now()) | ||
|
||
mw.logger.Trace("close", | ||
"status", "started") | ||
return mw.next.Close() | ||
} | ||
|
||
// /////////////////////////////////////////////////// | ||
// Metrics Middleware Domain | ||
// /////////////////////////////////////////////////// | ||
|
||
var _ Database = databaseMetricsMiddleware{} | ||
|
||
// databaseMetricsMiddleware wraps an implementation of Databases and on | ||
// function call logs metrics about this instance. | ||
type databaseMetricsMiddleware struct { | ||
next Database | ||
|
||
typeStr string | ||
} | ||
|
||
func (mw databaseMetricsMiddleware) Initialize(ctx context.Context, req InitializeRequest) (resp InitializeResponse, err error) { | ||
defer func(now time.Time) { | ||
metrics.MeasureSince([]string{"database", "Initialize"}, now) | ||
metrics.MeasureSince([]string{"database", mw.typeStr, "Initialize"}, now) | ||
|
||
if err != nil { | ||
metrics.IncrCounter([]string{"database", "Initialize", "error"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "Initialize", "error"}, 1) | ||
} | ||
}(time.Now()) | ||
|
||
metrics.IncrCounter([]string{"database", "Initialize"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "Initialize"}, 1) | ||
return mw.next.Initialize(ctx, req) | ||
} | ||
|
||
func (mw databaseMetricsMiddleware) NewUser(ctx context.Context, req NewUserRequest) (resp NewUserResponse, err error) { | ||
defer func(start time.Time) { | ||
metrics.MeasureSince([]string{"database", "CreateUser"}, start) | ||
metrics.MeasureSince([]string{"database", mw.typeStr, "CreateUser"}, start) | ||
|
||
if err != nil { | ||
metrics.IncrCounter([]string{"database", "CreateUser", "error"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "CreateUser", "error"}, 1) | ||
} | ||
}(time.Now()) | ||
|
||
metrics.IncrCounter([]string{"database", "CreateUser"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "CreateUser"}, 1) | ||
return mw.next.NewUser(ctx, req) | ||
} | ||
|
||
func (mw databaseMetricsMiddleware) UpdateUser(ctx context.Context, req UpdateUserRequest) (resp UpdateUserResponse, err error) { | ||
defer func(now time.Time) { | ||
metrics.MeasureSince([]string{"database", "UpdateUser"}, now) | ||
metrics.MeasureSince([]string{"database", mw.typeStr, "UpdateUser"}, now) | ||
|
||
if err != nil { | ||
metrics.IncrCounter([]string{"database", "UpdateUser", "error"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "UpdateUser", "error"}, 1) | ||
} | ||
}(time.Now()) | ||
|
||
metrics.IncrCounter([]string{"database", "UpdateUser"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "UpdateUser"}, 1) | ||
return mw.next.UpdateUser(ctx, req) | ||
} | ||
|
||
func (mw databaseMetricsMiddleware) DeleteUser(ctx context.Context, req DeleteUserRequest) (resp DeleteUserResponse, err error) { | ||
defer func(now time.Time) { | ||
metrics.MeasureSince([]string{"database", "DeleteUser"}, now) | ||
metrics.MeasureSince([]string{"database", mw.typeStr, "DeleteUser"}, now) | ||
|
||
if err != nil { | ||
metrics.IncrCounter([]string{"database", "DeleteUser", "error"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "DeleteUser", "error"}, 1) | ||
} | ||
}(time.Now()) | ||
|
||
metrics.IncrCounter([]string{"database", "DeleteUser"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "DeleteUser"}, 1) | ||
return mw.next.DeleteUser(ctx, req) | ||
} | ||
|
||
func (mw databaseMetricsMiddleware) Type() (string, error) { | ||
return mw.next.Type() | ||
} | ||
|
||
func (mw databaseMetricsMiddleware) Close() (err error) { | ||
defer func(now time.Time) { | ||
metrics.MeasureSince([]string{"database", "Close"}, now) | ||
metrics.MeasureSince([]string{"database", mw.typeStr, "Close"}, now) | ||
|
||
if err != nil { | ||
metrics.IncrCounter([]string{"database", "Close", "error"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "Close", "error"}, 1) | ||
} | ||
}(time.Now()) | ||
|
||
metrics.IncrCounter([]string{"database", "Close"}, 1) | ||
metrics.IncrCounter([]string{"database", mw.typeStr, "Close"}, 1) | ||
return mw.next.Close() | ||
} | ||
|
||
// /////////////////////////////////////////////////// | ||
// Error Sanitizer Middleware Domain | ||
// /////////////////////////////////////////////////// | ||
|
||
var _ Database = DatabaseErrorSanitizerMiddleware{} | ||
|
||
// DatabaseErrorSanitizerMiddleware wraps an implementation of Databases and | ||
// sanitizes returned error messages | ||
type DatabaseErrorSanitizerMiddleware struct { | ||
next Database | ||
secretsFn secretsFn | ||
} | ||
|
||
type secretsFn func() map[string]string | ||
|
||
func NewDatabaseErrorSanitizerMiddleware(next Database, secrets secretsFn) DatabaseErrorSanitizerMiddleware { | ||
return DatabaseErrorSanitizerMiddleware{ | ||
next: next, | ||
secretsFn: secrets, | ||
} | ||
} | ||
|
||
func (mw DatabaseErrorSanitizerMiddleware) Initialize(ctx context.Context, req InitializeRequest) (resp InitializeResponse, err error) { | ||
resp, err = mw.next.Initialize(ctx, req) | ||
return resp, mw.sanitize(err) | ||
} | ||
|
||
func (mw DatabaseErrorSanitizerMiddleware) NewUser(ctx context.Context, req NewUserRequest) (resp NewUserResponse, err error) { | ||
resp, err = mw.next.NewUser(ctx, req) | ||
return resp, mw.sanitize(err) | ||
} | ||
|
||
func (mw DatabaseErrorSanitizerMiddleware) UpdateUser(ctx context.Context, req UpdateUserRequest) (UpdateUserResponse, error) { | ||
resp, err := mw.next.UpdateUser(ctx, req) | ||
return resp, mw.sanitize(err) | ||
} | ||
|
||
func (mw DatabaseErrorSanitizerMiddleware) DeleteUser(ctx context.Context, req DeleteUserRequest) (DeleteUserResponse, error) { | ||
resp, err := mw.next.DeleteUser(ctx, req) | ||
return resp, mw.sanitize(err) | ||
} | ||
|
||
func (mw DatabaseErrorSanitizerMiddleware) Type() (string, error) { | ||
dbType, err := mw.next.Type() | ||
return dbType, mw.sanitize(err) | ||
} | ||
|
||
func (mw DatabaseErrorSanitizerMiddleware) Close() (err error) { | ||
return mw.sanitize(mw.next.Close()) | ||
} | ||
|
||
// sanitize | ||
func (mw DatabaseErrorSanitizerMiddleware) sanitize(err error) error { | ||
if err == nil { | ||
return nil | ||
} | ||
if errwrap.ContainsType(err, new(url.Error)) { | ||
return errors.New("unable to parse connection url") | ||
} | ||
if mw.secretsFn == nil { | ||
return err | ||
} | ||
for find, replace := range mw.secretsFn() { | ||
if find == "" { | ||
continue | ||
} | ||
|
||
// Attempt to keep the status code attached to the | ||
// error while changing the actual error message | ||
s, ok := status.FromError(err) | ||
if ok { | ||
err = status.Error(s.Code(), strings.Replace(s.Message(), find, replace, -1)) | ||
continue | ||
} | ||
|
||
err = errors.New(strings.Replace(err.Error(), find, replace, -1)) | ||
} | ||
return err | ||
} |
Oops, something went wrong.