Documentation
¶
Overview ¶
Type conversions for Scan.
The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses)
Copyright (c) 2013-2019, DATA-DOG team All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- The name DataDog.lt may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Index ¶
- Constants
- Variables
- func ConvertAssign(dest, src any) error
- func DefaultShouldAudit(query string) bool
- func MarshalMetric(name string) string
- func Wrap(driver driver.Driver, wrapper Middleware) driver.Driver
- type API
- type AlarmType
- type ArgsRewriter
- type Audit
- func (audit *Audit) AddBlacklistQuery(query string, alarmType AlarmType, reason string)
- func (audit *Audit) AddWhitelistQuery(query string)
- func (audit *Audit) After(ctx context.Context, query string, args ...interface{}) (context.Context, error)
- func (audit *Audit) Before(ctx context.Context, query string, args ...interface{}) (context.Context, error)
- func (audit *Audit) BlacklistAPI(w http.ResponseWriter, r *http.Request)
- func (audit *Audit) ClearSqls() error
- func (audit *Audit) ConfigAPI(w http.ResponseWriter, r *http.Request)
- func (audit *Audit) DelWhitelistQuery(query string)
- func (audit *Audit) DeleteSql(query string) error
- func (audit *Audit) DetectAlarmType(ers []mysql.ExplainRow) (alarmType AlarmType, reason string)
- func (audit *Audit) ExecContext(next ExecContext) ExecContext
- func (audit *Audit) Explain(ctx context.Context, query string, args ...interface{}) ([]mysql.ExplainRow, error)
- func (audit *Audit) GetSql(query string) *Sql
- func (audit *Audit) MetricsAPI(w http.ResponseWriter, r *http.Request)
- func (audit *Audit) Provision(ctx context.Context) error
- func (audit *Audit) QueryContext(next QueryContext) QueryContext
- func (audit *Audit) SetDB(db *sql.DB) error
- func (audit *Audit) SetLogger(logger *zap.Logger) error
- func (audit *Audit) SetSeenSqlLogLevel(level int32)
- func (audit *Audit) SetSeenSqlLogLevelAPI(w http.ResponseWriter, r *http.Request)
- func (audit *Audit) SetSql(s *Sql) error
- func (audit *Audit) ShouldAudit(query string) bool
- func (audit *Audit) Sqls() map[string]*Sql
- func (audit *Audit) SqlsAPI(w http.ResponseWriter, r *http.Request)
- func (audit *Audit) Tables(ctx context.Context) (map[string]*mysql.Table, error)
- func (audit *Audit) TablesAPI(w http.ResponseWriter, r *http.Request)
- func (audit *Audit) Validate() error
- func (audit *Audit) WhitelistAPI(w http.ResponseWriter, r *http.Request)
- func (audit *Audit) Whitelists() []string
- type BlacklistRequest
- type Conn
- func (conn *Conn) Begin() (driver.Tx, error)
- func (conn *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)
- func (conn *Conn) Close() error
- func (conn *Conn) Prepare(query string) (driver.Stmt, error)
- func (conn *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)
- type DecimalDecompose
- type Driver
- type EmptyRows
- type ExecContext
- type ExecerContext
- type ExecerQueryerContext
- type ExecerQueryerContextWithSessionResetter
- type LogHooks
- func (h *LogHooks) After(ctx context.Context, query string, args ...interface{}) (context.Context, error)
- func (h *LogHooks) Before(ctx context.Context, query string, args ...interface{}) (context.Context, error)
- func (h *LogHooks) OnError(ctx context.Context, err error, query string, args ...interface{}) error
- type Middleware
- type Mock
- func (m *Mock) AddExec(query string, ret *Return[driver.Result])
- func (m *Mock) AddQuery(query string, ret *Return[driver.Rows])
- func (m *Mock) Dump() error
- func (m *Mock) ExecContext(next ExecContext) ExecContext
- func (m *Mock) Load() error
- func (m *Mock) QueryContext(next QueryContext) QueryContext
- type MockOption
- type QueryContext
- type QueryerContext
- type Return
- type Rewrite
- type Rewriter
- type RewriterBase
- type RewriterInterface
- type Rows
- type SessionResetter
- type ShadowTable
- func (st *ShadowTable) Enter(in ast.Node) (ast.Node, bool)
- func (st *ShadowTable) Leave(in ast.Node) (ast.Node, bool)
- func (st *ShadowTable) Name() string
- func (st *ShadowTable) Provision(ctx context.Context) error
- func (st *ShadowTable) RewriteSql(sql string) (string, error)
- func (st *ShadowTable) SetLogger(logger *zap.Logger)
- func (st *ShadowTable) Sqls() map[string]string
- type Sql
- type SqlRewriter
- type Stmt
- func (stmt *Stmt) Close() error
- func (stmt *Stmt) Exec(args []driver.Value) (driver.Result, error)
- func (stmt *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error)
- func (stmt *Stmt) NumInput() int
- func (stmt *Stmt) Query(args []driver.Value) (driver.Rows, error)
- func (stmt *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error)
- type SyncMap
- func (m *SyncMap[K, V]) Delete(key K)
- func (m *SyncMap[K, V]) Load(key K) (value V, ok bool)
- func (m *SyncMap[K, V]) LoadAndDelete(key K) (value any, loaded bool)
- func (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual any, loaded bool)
- func (m *SyncMap[K, V]) Range(f func(key, value any) bool)
- func (m *SyncMap[K, V]) Store(key K, value V)
Constants ¶
const (
// MysqlAuditDriverName msyql+audit database driver name
MysqlAuditDriverName = "audit:mysql"
)
Variables ¶
var ( // App app name App = "" // DefaultAlarmThreshold default alarm threshold(scan rows) DefaultAlarmThreshold int64 = 500 // DefaultBannedThreshold default banned threshold(scan rows) DefaultBannedThreshold int64 = 100000 // Now is time.Now Now = time.Now // used for test )
var ( // ErrBanned sql banned error, use errors.Is(err, ErrBanned) to assert ErrBanned = errors.WithError(errors.New("sql is banned"), errors.InvalidArgument) // ErrAlarm sql warning, use errors.Is(err, ErrAlarm) to assert ErrAlarm = errors.New("sql is alarmed") )
var CSVColumnParser = func(s string) []byte { switch { case strings.ToLower(s) == "null": return nil } return []byte(s) }
CSVColumnParser is a function which converts trimmed csv column string to a []byte representation. Currently transforms NULL to nil
var DefaultSeenSqlLogLevel = int(Alarm)
DefaultSeenSqlLogLevel default log level for seen sql
Functions ¶
func ConvertAssign ¶
ConvertAssign is the same as convertAssignRows, but without the optional rows argument.
func DefaultShouldAudit ¶
DefaultShouldAudit sql是否审计的默认实现
func MarshalMetric ¶
Types ¶
type AlarmType ¶
type AlarmType int
AlarmType alarm type
const ( // Normal normal, means not alarm Normal AlarmType = iota // Alarm warning, means index missing but the number of scan lines is not large, still let the sql go through Alarm // Banned banned, means index missing and the number of scan lines is not large, still let the sql will be banned Banned )
func (AlarmType) MarshalJSON ¶
func (*AlarmType) UnmarshalJSON ¶
type ArgsRewriter ¶
type ArgsRewriter interface { RewriterBase RewriteArgs(args []any) ([]any, error) }
type Audit ¶
type Audit struct { // DatabaseName database name DatabaseName string `json:"database_name"` // AlarmThreshold sql will be alarmed if scan rows great than this threshold, default to 500 AlarmThreshold *int64 `json:"alarm_threshold"` // BannedThreshold sql will be banned if scan rows great than this threshold, default to 10w BannedThreshold int64 `json:"banned_threshold"` // SeenSqlLogLevel log level for seen sqls(not new found), if SeenSqlLogLevel <= AlarmType will be logged SeenSqlLogLevel *atomic.Int32 `json:"seen_sql_log_level,omitempty"` // Whitelist contains sqls which will not be audited Whitelist []string `json:"whitelist,omitempty"` // SqlCacheDuration sql explain result cache duration, default is forever SqlCacheDuration *utils.Duration `json:"sql_cache_duration,omitempty"` // ExplainExtraAlarmSubstrs alarm when explain extra contains the sub-string in this list ExplainExtraAlarmSubstrs []string `json:"explain_extra_alarm_substrs,omitempty"` // ShouldAuditFunc used to determine if a sql should be audited, default behavior is detect if startss with `select|insert|update|delete` // NOTE: it does contains the whitelist ShouldAuditFunc func(query string) bool `json:"-"` // ContextLogFields extract zap fileds list for logging, e.g. traceid... ContextLogFields func(context.Context) []zap.Field `json:"-"` // contains filtered or unexported fields }
Audit audit sqls and alarm or ban according to some conditions
Usage:
import ( sql "database/sql" "github.com/qustavo/sqlhooks/v2" "github.com/go-sql-driver/mysql" "gitlab.alibaba-inc.com/t3/pkg/sqlkit" ) audit := &sqlkit.Audit{ DatabaseName: "xxx", } err := audit.Provision(ctx) sql.Register(sql.DriverName, sqlhooks.Wrap(&mysql.MySQLDriver{}, audit)) db, err := sql.Open(sqlkit.DriverName, ...) err = audit.SetDB(db) // NOTE: reuse the same pool err = audit.Validate() // if err == nil, then you can use the db ...
func (*Audit) AddBlacklistQuery ¶
AddBlacklistQuery 用于动态设定黑名单查询, 用于止血 注意:未持久化
func (*Audit) AddWhitelistQuery ¶
SetWhitelistQuery 用于动态设定白名单查询, 如出现误判场景 NOTE: no persistence!
func (*Audit) BlacklistAPI ¶
func (audit *Audit) BlacklistAPI(w http.ResponseWriter, r *http.Request)
BlacklistQueryAPI
func (*Audit) ConfigAPI ¶
func (audit *Audit) ConfigAPI(w http.ResponseWriter, r *http.Request)
ConfigAPI list config
func (*Audit) DelWhitelistQuery ¶
func (*Audit) DetectAlarmType ¶
func (audit *Audit) DetectAlarmType(ers []mysql.ExplainRow) (alarmType AlarmType, reason string)
DetectAlarmType 根据Explain结果判断AlarmType
func (*Audit) ExecContext ¶
func (audit *Audit) ExecContext(next ExecContext) ExecContext
func (*Audit) Explain ¶
func (audit *Audit) Explain(ctx context.Context, query string, args ...interface{}) ([]mysql.ExplainRow, error)
Explain do mysql explain
func (*Audit) MetricsAPI ¶
func (audit *Audit) MetricsAPI(w http.ResponseWriter, r *http.Request)
MetricsAPI list metrics
func (*Audit) QueryContext ¶
func (audit *Audit) QueryContext(next QueryContext) QueryContext
func (*Audit) SetSeenSqlLogLevel ¶
SetSeenSqlLogLevel 用于动态调整日志级别, 如用于trace分析问题
func (*Audit) SetSeenSqlLogLevelAPI ¶
func (audit *Audit) SetSeenSqlLogLevelAPI(w http.ResponseWriter, r *http.Request)
SetSeenSqlLogLevelAPI set seen_sql_log_level
func (*Audit) ShouldAudit ¶
func (*Audit) SqlsAPI ¶
func (audit *Audit) SqlsAPI(w http.ResponseWriter, r *http.Request)
SqlsAPI list sqls
func (*Audit) TablesAPI ¶
func (audit *Audit) TablesAPI(w http.ResponseWriter, r *http.Request)
TablesAPI list tables
func (*Audit) WhitelistAPI ¶
func (audit *Audit) WhitelistAPI(w http.ResponseWriter, r *http.Request)
WhitelistQueryAPI
func (*Audit) Whitelists ¶
Whitelists 返回所有白名单查询, 包括静态配置和动态添加
type BlacklistRequest ¶
type BlacklistRequest struct { Query string `json:"query"` AlarmType AlarmType `json:"alarm_type"` Reason string `json:"reason"` }
func (BlacklistRequest) String ¶
func (br BlacklistRequest) String() string
type DecimalDecompose ¶
type DecimalDecompose = decimalDecompose // used for tests
type ExecContext ¶
type ExecerContext ¶
type ExecerContext struct {
*Conn
}
ExecerContext implements a database/sql.driver.ExecerContext
func (*ExecerContext) ExecContext ¶
func (conn *ExecerContext) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)
type ExecerQueryerContext ¶
type ExecerQueryerContext struct { *Conn *ExecerContext *QueryerContext }
ExecerQueryerContext implements database/sql.driver.ExecerContext and database/sql.driver.QueryerContext
type ExecerQueryerContextWithSessionResetter ¶
type ExecerQueryerContextWithSessionResetter struct { *Conn *ExecerContext *QueryerContext *SessionResetter }
ExecerQueryerContext implements database/sql.driver.ExecerContext and database/sql.driver.QueryerContext
type LogHooks ¶
type LogHooks struct { Logger *zap.Logger Level zapcore.Level `json:"level,omitempty"` FieldSize int `json:"field_size,omitempty"` FieldNameMap map[string]string `json:"field_name_map,omitempty"` }
LogHooks log sqls with rt and traceid
func (*LogHooks) After ¶
func (h *LogHooks) After(ctx context.Context, query string, args ...interface{}) (context.Context, error)
After hook will get the timestamp registered on the Before hook and print the elapsed time
type Middleware ¶
type Middleware interface { ExecContext(ExecContext) ExecContext QueryContext(QueryContext) QueryContext }
Middleware is a middleware which wrap a driver to another This work is based on `sqlhooks`, why define a new `Hook`? For `sqlhooks.Hooks` can not operate the arguments & returns but only ctx, which is not applicable for some scenarios, e.g. mock, cache, tranform, ... Experimental!!!
type Mock ¶
type Mock struct { Name string Playback bool ExecReturns *SyncMap[string, *Return[driver.Result]] QueryReturns *SyncMap[string, *Return[driver.Rows]] }
func NewMock ¶
func NewMock(opts ...MockOption) *Mock
func (*Mock) ExecContext ¶
func (m *Mock) ExecContext(next ExecContext) ExecContext
func (*Mock) QueryContext ¶
func (m *Mock) QueryContext(next QueryContext) QueryContext
type MockOption ¶
type MockOption func(*Mock)
func WithMockExecReturns ¶
func WithMockExecReturns(m map[string]*Return[driver.Result]) MockOption
func WithMockName ¶
func WithMockName(name string) MockOption
func WithMockPlayback ¶
func WithMockPlayback(pb bool) MockOption
func WithMockQueryReturns ¶
func WithMockQueryReturns(m map[string]*Return[driver.Rows]) MockOption
type QueryContext ¶
type QueryerContext ¶
type QueryerContext struct {
*Conn
}
QueryerContext implements a database/sql.driver.QueryerContext
func (*QueryerContext) QueryContext ¶
func (conn *QueryerContext) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error)
type Rewrite ¶
type Rewrite struct { GlobalRewriter *Rewriter `json:"global_rewriter,omitempty"` CustomRewriters map[string]*Rewriter `json:"custom_rewriters,omitempty"` }
Rewrite an aggregate rewriter, usually can be used in most cases
type Rewriter ¶
type Rewriter struct { SqlRewriters []SqlRewriter `json:"sql_rewriters,omitempty"` ArgsRewriters []ArgsRewriter `json:"args_rewriters,omitempty"` }
type RewriterBase ¶
type RewriterInterface ¶
type Rows ¶
type Rows struct { Converter driver.ValueConverter Cols []string Rows [][]driver.Value CloseErr error Pos int NextErr map[int]error }
Rows mainly copy from `sqlmock`, and used with `sqlkit.Mock` Experimental!!!
func (*Rows) AddRow ¶
AddRow composed from database driver.Value slice return the same instance to perform subsequent actions. Note that the number of values must match the number of columns
func (*Rows) CloseError ¶
CloseError allows to set an error which will be returned by rows.Close function.
The close error will be triggered only in cases when rows.Next() EOF was not yet reached, that is a default sql library behavior
func (*Rows) FromCSVString ¶
FromCSVString build rows from csv string. return the same instance to perform subsequent actions. Note that the number of values must match the number of columns
type SessionResetter ¶
type SessionResetter struct {
*Conn
}
func (*SessionResetter) ResetSession ¶
func (s *SessionResetter) ResetSession(ctx context.Context) error
type ShadowTable ¶
type ShadowTable struct { Prefix string `json:"prefix,omitempty"` Suffix string `json:"suffix,omitempty"` // contains filtered or unexported fields }
func (*ShadowTable) Name ¶
func (st *ShadowTable) Name() string
func (*ShadowTable) RewriteSql ¶
func (st *ShadowTable) RewriteSql(sql string) (string, error)
func (*ShadowTable) SetLogger ¶
func (st *ShadowTable) SetLogger(logger *zap.Logger)
func (*ShadowTable) Sqls ¶
func (st *ShadowTable) Sqls() map[string]string
type Sql ¶
type Sql struct { Query string `json:"query"` Args []interface{} `json:"args"` Explain []mysql.ExplainRow `json:"explain"` AlarmType AlarmType `json:"alarm_type"` Reason string `json:"reason"` CreatedAt time.Time `json:"created_at"` }
Sql sql statement
type SqlRewriter ¶
type SqlRewriter interface { RewriterBase RewriteSql(sql string) (string, error) }
type Stmt ¶
Stmt implements a database/sql/driver.Stmt
func (*Stmt) ExecContext ¶
func (*Stmt) QueryContext ¶
type SyncMap ¶
type SyncMap[K comparable, V any] struct { // contains filtered or unexported fields }
func NewSyncMap ¶
func NewSyncMap[K comparable, V any]() *SyncMap[K, V]
NewSyncMap creates a new map
func (*SyncMap[K, V]) Delete ¶
func (m *SyncMap[K, V]) Delete(key K)
Set set a V's instance with key, if exists then override