master
go 165 lines 3.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package clickhouse
4
5 import (
6 "context"
7 _ "embed"
8 "errors"
9 "fmt"
10 "net/http"
11 "time"
12
13 "github.com/netdata/netdata/go/plugins/pkg/confopt"
14 "github.com/netdata/netdata/go/plugins/pkg/web"
15 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
16 )
17
18 //go:embed "config_schema.json"
19 var configSchema string
20
21 func init() {
22 collectorapi.Register("clickhouse", collectorapi.Creator{
23 Create: func() collectorapi.CollectorV1 { return New() },
24 Config: func() any { return &Config{} },
25 JobConfigSchema: configSchema,
26 Methods: clickhouseMethods,
27 MethodHandler: clickhouseFunctionHandler,
28 })
29 }
30
31 func New() *Collector {
32 return &Collector{
33 Config: Config{
34 HTTPConfig: web.HTTPConfig{
35 RequestConfig: web.RequestConfig{
36 URL: "http://127.0.0.1:8123",
37 },
38 ClientConfig: web.ClientConfig{
39 Timeout: confopt.Duration(time.Second),
40 },
41 },
42 Functions: FunctionsConfig{
43 TopQueries: TopQueriesConfig{
44 Limit: 500,
45 },
46 },
47 },
48 charts: chCharts.Copy(),
49 seenDisks: make(map[string]*seenDisk),
50 seenDbTables: make(map[string]*seenTable),
51 }
52 }
53
54 type Config struct {
55 Vnode string `yaml:"vnode,omitempty" json:"vnode"`
56 UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
57 AutoDetectionRetry int `yaml:"autodetection_retry,omitempty" json:"autodetection_retry"`
58 web.HTTPConfig `yaml:",inline" json:""`
59 Functions FunctionsConfig `yaml:"functions,omitempty" json:"functions"`
60 }
61
62 type FunctionsConfig struct {
63 TopQueries TopQueriesConfig `yaml:"top_queries,omitempty" json:"top_queries"`
64 }
65
66 type TopQueriesConfig struct {
67 Disabled bool `yaml:"disabled" json:"disabled"`
68 Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
69 Limit int `yaml:"limit,omitempty" json:"limit"`
70 }
71
72 func (c Config) topQueriesTimeout() time.Duration {
73 if c.Functions.TopQueries.Timeout == 0 {
74 return c.Timeout.Duration()
75 }
76 return c.Functions.TopQueries.Timeout.Duration()
77 }
78
79 func (c Config) topQueriesLimit() int {
80 if c.Functions.TopQueries.Limit <= 0 {
81 return 500
82 }
83 return c.Functions.TopQueries.Limit
84 }
85
86 type (
87 Collector struct {
88 collectorapi.Base
89 Config `yaml:",inline" json:""`
90
91 charts *collectorapi.Charts
92
93 httpClient *http.Client
94
95 seenDisks map[string]*seenDisk
96 seenDbTables map[string]*seenTable
97
98 // Function handler (singleton, initialized in Init)
99 funcRouter *funcRouter
100 }
101 seenDisk struct{ disk string }
102 seenTable struct{ db, table string }
103 )
104
105 func (c *Collector) Configuration() any {
106 return c.Config
107 }
108
109 func (c *Collector) Init(context.Context) error {
110 if err := c.validateConfig(); err != nil {
111 return fmt.Errorf("config validation: %v", err)
112 }
113
114 httpClient, err := c.initHTTPClient()
115 if err != nil {
116 return fmt.Errorf("init HTTP client: %v", err)
117 }
118 c.httpClient = httpClient
119
120 c.funcRouter = newFuncRouter(c)
121
122 c.Debugf("using URL %s", c.URL)
123 c.Debugf("using timeout: %s", c.Timeout)
124
125 return nil
126 }
127
128 func (c *Collector) Check(context.Context) error {
129 mx, err := c.collect()
130 if err != nil {
131 return err
132 }
133
134 if len(mx) == 0 {
135 return errors.New("no metrics collected")
136 }
137
138 return nil
139 }
140
141 func (c *Collector) Charts() *collectorapi.Charts {
142 return c.charts
143 }
144
145 func (c *Collector) Collect(context.Context) map[string]int64 {
146 mx, err := c.collect()
147 if err != nil {
148 c.Error(err)
149 }
150
151 if len(mx) == 0 {
152 return nil
153 }
154
155 return mx
156 }
157
158 func (c *Collector) Cleanup(ctx context.Context) {
159 if c.funcRouter != nil {
160 c.funcRouter.Cleanup(ctx)
161 }
162 if c.httpClient != nil {
163 c.httpClient.CloseIdleConnections()
164 }
165 }