master
go 173 lines 4.08 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package mongo
4
5 import (
6 "context"
7 _ "embed"
8 "errors"
9 "fmt"
10 "sync"
11 "time"
12
13 "github.com/netdata/netdata/go/plugins/pkg/confopt"
14 "github.com/netdata/netdata/go/plugins/pkg/matcher"
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("mongodb", collectorapi.Creator{
23 JobConfigSchema: configSchema,
24 Create: func() collectorapi.CollectorV1 { return New() },
25 Config: func() any { return &Config{} },
26 Methods: mongoMethods,
27 MethodHandler: mongoFunctionHandler,
28 })
29 }
30
31 func New() *Collector {
32 return &Collector{
33 Config: Config{
34 URI: "mongodb://localhost:27017",
35 Timeout: confopt.Duration(time.Second),
36 Databases: matcher.SimpleExpr{
37 Includes: []string{},
38 Excludes: []string{},
39 },
40 Functions: FunctionsConfig{
41 TopQueries: TopQueriesConfig{
42 Timeout: confopt.Duration(10 * time.Second),
43 Limit: 500,
44 },
45 },
46 },
47
48 conn: &mongoClient{},
49
50 charts: chartsServerStatus.Copy(),
51 addShardingChartsOnce: &sync.Once{},
52
53 optionalCharts: make(map[string]bool),
54 replSetMembers: make(map[string]bool),
55 databases: make(map[string]bool),
56 shards: make(map[string]bool),
57 }
58 }
59
60 type Config struct {
61 Vnode string `yaml:"vnode,omitempty" json:"vnode"`
62 UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
63 AutoDetectionRetry int `yaml:"autodetection_retry,omitempty" json:"autodetection_retry"`
64 URI string `yaml:"uri" json:"uri"`
65 Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
66 Databases matcher.SimpleExpr `yaml:"databases,omitempty" json:"databases"`
67 Functions FunctionsConfig `yaml:"functions,omitempty" json:"functions"`
68 }
69
70 type FunctionsConfig struct {
71 TopQueries TopQueriesConfig `yaml:"top_queries,omitempty" json:"top_queries"`
72 }
73
74 type TopQueriesConfig struct {
75 Disabled bool `yaml:"disabled" json:"disabled"`
76 Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
77 Limit int `yaml:"limit,omitempty" json:"limit"`
78 }
79
80 func (c Config) topQueriesTimeout() time.Duration {
81 if c.Functions.TopQueries.Timeout == 0 {
82 return c.Timeout.Duration()
83 }
84 return c.Functions.TopQueries.Timeout.Duration()
85 }
86
87 func (c Config) topQueriesLimit() int {
88 if c.Functions.TopQueries.Limit <= 0 {
89 return 500
90 }
91 return c.Functions.TopQueries.Limit
92 }
93
94 type Collector struct {
95 collectorapi.Base
96 Config `yaml:",inline" json:""`
97
98 charts *collectorapi.Charts
99 addShardingChartsOnce *sync.Once
100
101 conn mongoConn
102
103 dbSelector matcher.Matcher
104 optionalCharts map[string]bool
105 databases map[string]bool
106 replSetMembers map[string]bool
107 shards map[string]bool
108
109 // Top queries column cache with double-checked locking
110 topQueriesColsMu sync.RWMutex
111 topQueriesCols map[string]bool
112
113 funcRouter *funcRouter
114 }
115
116 func (c *Collector) Configuration() any {
117 return c.Config
118 }
119
120 func (c *Collector) Init(context.Context) error {
121 if err := c.verifyConfig(); err != nil {
122 return fmt.Errorf("config validation: %v", err)
123 }
124
125 if err := c.initDatabaseSelector(); err != nil {
126 return fmt.Errorf("init database selector: %v", err)
127 }
128
129 c.funcRouter = newFuncRouter(c)
130
131 return nil
132 }
133
134 func (c *Collector) Check(context.Context) error {
135 mx, err := c.collect()
136 if err != nil {
137 return err
138 }
139 if len(mx) == 0 {
140 return errors.New("no metrics collected")
141 }
142 return nil
143 }
144
145 func (c *Collector) Charts() *collectorapi.Charts {
146 return c.charts
147 }
148
149 func (c *Collector) Collect(context.Context) map[string]int64 {
150 mx, err := c.collect()
151 if err != nil {
152 c.Error(err)
153 }
154
155 if len(mx) == 0 {
156 c.Warning("no values collected")
157 return nil
158 }
159
160 return mx
161 }
162
163 func (c *Collector) Cleanup(ctx context.Context) {
164 if c.funcRouter != nil {
165 c.funcRouter.Cleanup(ctx)
166 }
167 if c.conn == nil {
168 return
169 }
170 if err := c.conn.close(); err != nil {
171 c.Warningf("cleanup: error on closing mongo conn: %v", err)
172 }
173 }