master
go 177 lines 4.42 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package mysql
4
5 import (
6 "context"
7 "database/sql"
8 _ "embed"
9 "errors"
10 "fmt"
11 "strings"
12 "sync"
13 "time"
14
15 "github.com/blang/semver/v4"
16 "github.com/go-sql-driver/mysql"
17
18 "github.com/netdata/netdata/go/plugins/pkg/confopt"
19 "github.com/netdata/netdata/go/plugins/pkg/funcapi"
20 "github.com/netdata/netdata/go/plugins/pkg/metrix"
21 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
22 "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/mysql/mysqlfunc"
23 )
24
25 //go:embed "config_schema.json"
26 var configSchema string
27
28 //go:embed "charts.yaml"
29 var mysqlChartTemplateV2 string
30
31 func init() {
32 collectorapi.Register("mysql", collectorapi.Creator{
33 JobConfigSchema: configSchema,
34 CreateV2: func() collectorapi.CollectorV2 { return New() },
35 Config: func() any { return &Config{} },
36 Methods: mysqlfunc.Methods,
37 MethodHandler: func(job collectorapi.RuntimeJob) funcapi.MethodHandler {
38 c, ok := job.Collector().(*Collector)
39 if !ok {
40 return nil
41 }
42 return c.funcRouter
43 },
44 })
45 }
46
47 func New() *Collector {
48 store := metrix.NewCollectorStore()
49 mx := newCollectorMetrics(store)
50
51 return &Collector{
52 Config: Config{
53 DSN: "root@tcp(localhost:3306)/",
54 Timeout: confopt.Duration(time.Second),
55 Functions: mysqlfunc.FunctionsConfig{
56 TopQueries: mysqlfunc.TopQueriesConfig{
57 Limit: 500,
58 },
59 },
60 },
61
62 doDisableSessionQueryLog: true,
63 doSlaveStatus: true,
64 doUserStatistics: true,
65
66 recheckGlobalVarsEvery: time.Minute * 10,
67
68 // innodb_log_files_in_group is available in mysql and <mariadb-10.6,
69 // otherwise it defaults to 1.
70 // see https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_files_in_group
71 varInnoDBLogFilesInGroup: 1,
72 store: store,
73 mx: mx,
74 }
75 }
76
77 type Config struct {
78 Vnode string `yaml:"vnode,omitempty" json:"vnode"`
79 UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
80 AutoDetectionRetry int `yaml:"autodetection_retry,omitempty" json:"autodetection_retry"`
81 DSN string `yaml:"dsn" json:"dsn"`
82 MyCNF string `yaml:"my.cnf,omitempty" json:"my.cnf"`
83 Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
84 Functions mysqlfunc.FunctionsConfig `yaml:"functions,omitempty" json:"functions"`
85 }
86
87 type Collector struct {
88 collectorapi.Base
89 Config `yaml:",inline" json:""`
90
91 dbMu sync.RWMutex // protects db pointer lifecycle across collect/functions/cleanup
92 db *sql.DB
93
94 safeDSN string
95 version *semver.Version
96
97 doDisableSessionQueryLog bool
98 doSlaveStatus bool
99 doUserStatistics bool
100
101 isMariaDB bool
102 isPercona bool
103
104 galeraDetected bool
105 qcacheDetected bool
106
107 recheckGlobalVarsTime time.Time
108 recheckGlobalVarsEvery time.Duration
109
110 varDisabledStorageEngine string
111 varLogBin string
112 varInnoDBLogFileSize int64
113 varInnoDBLogFilesInGroup int64
114 varMaxConns int64
115 varTableOpenCache int64
116 varPerformanceSchema string
117
118 funcRouter funcapi.MethodHandler
119
120 store metrix.CollectorStore
121 mx *collectorMetrics
122 }
123
124 func (c *Collector) Configuration() any {
125 return c.Config
126 }
127
128 func (c *Collector) Init(context.Context) error {
129 if c.MyCNF != "" {
130 dsn, err := dsnFromFile(c.MyCNF)
131 if err != nil {
132 return err
133 }
134 c.DSN = dsn
135 }
136
137 if c.DSN == "" {
138 return errors.New("config: dsn not set")
139 }
140
141 cfg, err := mysql.ParseDSN(c.DSN)
142 if err != nil {
143 return fmt.Errorf("error on parsing DSN: %v", err)
144 }
145
146 cfg.Passwd = strings.Repeat("x", len(cfg.Passwd))
147 c.safeDSN = cfg.FormatDSN()
148
149 c.Debugf("using DSN [%s]", c.safeDSN)
150
151 funcCfg := c.Functions
152 funcCfg.Timeout = c.Timeout
153 c.funcRouter = mysqlfunc.NewRouter(funcDepsAdapter{collector: c}, c.Logger, funcCfg)
154
155 return nil
156 }
157
158 func (c *Collector) Check(ctx context.Context) error {
159 return c.check(ctx)
160 }
161
162 func (c *Collector) Collect(ctx context.Context) error {
163 return c.collect(ctx)
164 }
165
166 func (c *Collector) MetricStore() metrix.CollectorStore { return c.store }
167
168 func (c *Collector) ChartTemplateYAML() string { return mysqlChartTemplateV2 }
169
170 func (c *Collector) Cleanup(ctx context.Context) {
171 if c.funcRouter != nil {
172 c.funcRouter.Cleanup(ctx)
173 }
174 if err := c.closeDB(); err != nil {
175 c.Errorf("cleanup: error on closing the mysql database [%s]: %v", c.safeDSN, err)
176 }
177 }