master
go 161 lines 3.54 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package proxysql
4
5 import (
6 "context"
7 "database/sql"
8 _ "embed"
9 "errors"
10 "sync"
11 "time"
12
13 _ "github.com/go-sql-driver/mysql"
14
15 "github.com/netdata/netdata/go/plugins/pkg/confopt"
16 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
17 )
18
19 //go:embed "config_schema.json"
20 var configSchema string
21
22 func init() {
23 collectorapi.Register("proxysql", collectorapi.Creator{
24 JobConfigSchema: configSchema,
25 Create: func() collectorapi.CollectorV1 { return New() },
26 Config: func() any { return &Config{} },
27 Methods: proxysqlMethods,
28 MethodHandler: proxysqlFunctionHandler,
29 })
30 }
31
32 func New() *Collector {
33 c := &Collector{
34 Config: Config{
35 DSN: "stats:stats@tcp(127.0.0.1:6032)/",
36 Timeout: confopt.Duration(time.Second),
37 Functions: FunctionsConfig{
38 TopQueries: TopQueriesConfig{
39 Limit: 500,
40 },
41 },
42 },
43
44 charts: baseCharts.Copy(),
45 once: &sync.Once{},
46 cache: &cache{
47 commands: make(map[string]*commandCache),
48 users: make(map[string]*userCache),
49 backends: make(map[string]*backendCache),
50 hostgroups: make(map[string]*hostgroupCache),
51 },
52 }
53
54 c.funcRouter = newFuncRouter(c)
55
56 return c
57 }
58
59 type Config struct {
60 Vnode string `yaml:"vnode,omitempty" json:"vnode"`
61 UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
62 AutoDetectionRetry int `yaml:"autodetection_retry,omitempty" json:"autodetection_retry"`
63 DSN string `yaml:"dsn" json:"dsn"`
64 Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
65 Functions FunctionsConfig `yaml:"functions,omitempty" json:"functions"`
66 }
67
68 type FunctionsConfig struct {
69 TopQueries TopQueriesConfig `yaml:"top_queries,omitempty" json:"top_queries"`
70 }
71
72 type TopQueriesConfig struct {
73 Disabled bool `yaml:"disabled" json:"disabled"`
74 Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
75 Limit int `yaml:"limit,omitempty" json:"limit"`
76 }
77
78 func (c Config) topQueriesTimeout() time.Duration {
79 if c.Functions.TopQueries.Timeout == 0 {
80 return c.Timeout.Duration()
81 }
82 return c.Functions.TopQueries.Timeout.Duration()
83 }
84
85 func (c Config) topQueriesLimit() int {
86 if c.Functions.TopQueries.Limit <= 0 {
87 return 500
88 }
89 return c.Functions.TopQueries.Limit
90 }
91
92 type Collector struct {
93 collectorapi.Base
94 Config `yaml:",inline" json:""`
95
96 charts *collectorapi.Charts
97
98 db *sql.DB
99
100 once *sync.Once
101 cache *cache
102
103 funcRouter *funcRouter // function router for method handlers
104
105 queryDigestCols map[string]bool
106 queryDigestColsMu sync.RWMutex
107 }
108
109 func (c *Collector) Configuration() any {
110 return c.Config
111 }
112
113 func (c *Collector) Init(context.Context) error {
114 if c.DSN == "" {
115 return errors.New("dsn not set")
116 }
117
118 c.Debugf("using DSN [%s]", c.DSN)
119
120 return nil
121 }
122
123 func (c *Collector) Check(context.Context) error {
124 mx, err := c.collect()
125 if err != nil {
126 return err
127 }
128 if len(mx) == 0 {
129 return errors.New("no metrics collected")
130 }
131 return nil
132 }
133
134 func (c *Collector) Charts() *collectorapi.Charts {
135 return c.charts
136 }
137
138 func (c *Collector) Collect(context.Context) map[string]int64 {
139 mx, err := c.collect()
140 if err != nil {
141 c.Error(err)
142 }
143
144 if len(mx) == 0 {
145 return nil
146 }
147 return mx
148 }
149
150 func (c *Collector) Cleanup(ctx context.Context) {
151 if c.funcRouter != nil {
152 c.funcRouter.Cleanup(ctx)
153 }
154 if c.db == nil {
155 return
156 }
157 if err := c.db.Close(); err != nil {
158 c.Errorf("cleanup: error on closing the ProxySQL instance [%s]: %v", c.DSN, err)
159 }
160 c.db = nil
161 }