github.com/netdata/go.d.plugin@v0.58.1/modules/mysql/mysql.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package mysql 4 5 import ( 6 "database/sql" 7 _ "embed" 8 "strings" 9 "sync" 10 "time" 11 12 "github.com/blang/semver/v4" 13 "github.com/go-sql-driver/mysql" 14 _ "github.com/go-sql-driver/mysql" 15 16 "github.com/netdata/go.d.plugin/agent/module" 17 "github.com/netdata/go.d.plugin/pkg/web" 18 ) 19 20 //go:embed "config_schema.json" 21 var configSchema string 22 23 func init() { 24 module.Register("mysql", module.Creator{ 25 JobConfigSchema: configSchema, 26 Create: func() module.Module { return New() }, 27 }) 28 } 29 30 func New() *MySQL { 31 return &MySQL{ 32 Config: Config{ 33 DSN: "root@tcp(localhost:3306)/", 34 Timeout: web.Duration{Duration: time.Second}, 35 }, 36 37 charts: baseCharts.Copy(), 38 addInnoDBOSLogOnce: &sync.Once{}, 39 addBinlogOnce: &sync.Once{}, 40 addMyISAMOnce: &sync.Once{}, 41 addInnodbDeadlocksOnce: &sync.Once{}, 42 addGaleraOnce: &sync.Once{}, 43 addQCacheOnce: &sync.Once{}, 44 addTableOpenCacheOverflowsOnce: &sync.Once{}, 45 doSlaveStatus: true, 46 doUserStatistics: true, 47 collectedReplConns: make(map[string]bool), 48 collectedUsers: make(map[string]bool), 49 50 recheckGlobalVarsEvery: time.Minute * 10, 51 } 52 } 53 54 type Config struct { 55 DSN string `yaml:"dsn"` 56 MyCNF string `yaml:"my.cnf"` 57 UpdateEvery int `yaml:"update_every"` 58 Timeout web.Duration `yaml:"timeout"` 59 } 60 61 type MySQL struct { 62 module.Base 63 Config `yaml:",inline"` 64 65 db *sql.DB 66 safeDSN string 67 version *semver.Version 68 isMariaDB bool 69 isPercona bool 70 71 charts *module.Charts 72 73 addInnoDBOSLogOnce *sync.Once 74 addBinlogOnce *sync.Once 75 addMyISAMOnce *sync.Once 76 addInnodbDeadlocksOnce *sync.Once 77 addGaleraOnce *sync.Once 78 addQCacheOnce *sync.Once 79 addTableOpenCacheOverflowsOnce *sync.Once 80 81 doSlaveStatus bool 82 collectedReplConns map[string]bool 83 doUserStatistics bool 84 collectedUsers map[string]bool 85 86 recheckGlobalVarsTime time.Time 87 recheckGlobalVarsEvery time.Duration 88 varMaxConns int64 89 varTableOpenCache int64 90 varDisabledStorageEngine string 91 varLogBin string 92 varPerformanceSchema string 93 } 94 95 func (m *MySQL) Init() bool { 96 if m.MyCNF != "" { 97 dsn, err := dsnFromFile(m.MyCNF) 98 if err != nil { 99 m.Error(err) 100 return false 101 } 102 m.DSN = dsn 103 } 104 105 if m.DSN == "" { 106 m.Error("DSN not set") 107 return false 108 } 109 110 cfg, err := mysql.ParseDSN(m.DSN) 111 if err != nil { 112 m.Errorf("error on parsing DSN: %v", err) 113 return false 114 } 115 116 cfg.Passwd = strings.Repeat("*", len(cfg.Passwd)) 117 m.safeDSN = cfg.FormatDSN() 118 119 m.Debugf("using DSN [%s]", m.DSN) 120 return true 121 } 122 123 func (m *MySQL) Check() bool { 124 return len(m.Collect()) > 0 125 } 126 127 func (m *MySQL) Charts() *module.Charts { 128 return m.charts 129 } 130 131 func (m *MySQL) Collect() map[string]int64 { 132 mx, err := m.collect() 133 if err != nil { 134 m.Error(err) 135 } 136 137 if len(mx) == 0 { 138 return nil 139 } 140 return mx 141 } 142 143 func (m *MySQL) Cleanup() { 144 if m.db == nil { 145 return 146 } 147 if err := m.db.Close(); err != nil { 148 m.Errorf("cleanup: error on closing the mysql database [%s]: %v", m.safeDSN, err) 149 } 150 m.db = nil 151 }