github.com/netdata/go.d.plugin@v0.58.1/modules/fluentd/fluentd.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package fluentd 4 5 import ( 6 _ "embed" 7 "fmt" 8 "time" 9 10 "github.com/netdata/go.d.plugin/pkg/matcher" 11 "github.com/netdata/go.d.plugin/pkg/web" 12 13 "github.com/netdata/go.d.plugin/agent/module" 14 ) 15 16 //go:embed "config_schema.json" 17 var configSchema string 18 19 func init() { 20 module.Register("fluentd", module.Creator{ 21 JobConfigSchema: configSchema, 22 Create: func() module.Module { return New() }, 23 }) 24 } 25 26 const ( 27 defaultURL = "http://127.0.0.1:24220" 28 defaultHTTPTimeout = time.Second * 2 29 ) 30 31 // New creates Fluentd with default values. 32 func New() *Fluentd { 33 config := Config{ 34 HTTP: web.HTTP{ 35 Request: web.Request{ 36 URL: defaultURL, 37 }, 38 Client: web.Client{ 39 Timeout: web.Duration{Duration: defaultHTTPTimeout}, 40 }, 41 }} 42 43 return &Fluentd{ 44 Config: config, 45 activePlugins: make(map[string]bool), 46 charts: charts.Copy(), 47 } 48 } 49 50 type Config struct { 51 web.HTTP `yaml:",inline"` 52 PermitPlugin string `yaml:"permit_plugin_id"` 53 } 54 55 // Fluentd Fluentd module. 56 type Fluentd struct { 57 module.Base 58 Config `yaml:",inline"` 59 60 permitPlugin matcher.Matcher 61 apiClient *apiClient 62 activePlugins map[string]bool 63 charts *Charts 64 } 65 66 // Cleanup makes cleanup. 67 func (Fluentd) Cleanup() {} 68 69 // Init makes initialization. 70 func (f *Fluentd) Init() bool { 71 if f.URL == "" { 72 f.Error("URL not set") 73 return false 74 } 75 76 if f.PermitPlugin != "" { 77 m, err := matcher.NewSimplePatternsMatcher(f.PermitPlugin) 78 if err != nil { 79 f.Errorf("error on creating permit_plugin matcher : %v", err) 80 return false 81 } 82 f.permitPlugin = matcher.WithCache(m) 83 } 84 85 client, err := web.NewHTTPClient(f.Client) 86 if err != nil { 87 f.Errorf("error on creating client : %v", err) 88 return false 89 } 90 91 f.apiClient = newAPIClient(client, f.Request) 92 93 f.Debugf("using URL %s", f.URL) 94 f.Debugf("using timeout: %s", f.Timeout.Duration) 95 96 return true 97 } 98 99 // Check makes check. 100 func (f Fluentd) Check() bool { return len(f.Collect()) > 0 } 101 102 // Charts creates Charts. 103 func (f Fluentd) Charts() *Charts { return f.charts } 104 105 // Collect collects metrics. 106 func (f *Fluentd) Collect() map[string]int64 { 107 info, err := f.apiClient.getPluginsInfo() 108 109 if err != nil { 110 f.Error(err) 111 return nil 112 } 113 114 metrics := make(map[string]int64) 115 116 for _, p := range info.Payload { 117 // TODO: if p.Category == "input" ? 118 if !p.hasCategory() && !p.hasBufferQueueLength() && !p.hasBufferTotalQueuedSize() { 119 continue 120 } 121 122 if f.permitPlugin != nil && !f.permitPlugin.MatchString(p.ID) { 123 f.Debugf("plugin id: '%s', type: '%s', category: '%s' denied", p.ID, p.Type, p.Category) 124 continue 125 } 126 127 id := fmt.Sprintf("%s_%s_%s", p.ID, p.Type, p.Category) 128 129 if p.hasCategory() { 130 metrics[id+"_retry_count"] = *p.RetryCount 131 } 132 if p.hasBufferQueueLength() { 133 metrics[id+"_buffer_queue_length"] = *p.BufferQueueLength 134 } 135 if p.hasBufferTotalQueuedSize() { 136 metrics[id+"_buffer_total_queued_size"] = *p.BufferTotalQueuedSize 137 } 138 139 if !f.activePlugins[id] { 140 f.activePlugins[id] = true 141 f.addPluginToCharts(p) 142 } 143 144 } 145 146 return metrics 147 } 148 149 func (f *Fluentd) addPluginToCharts(p pluginData) { 150 id := fmt.Sprintf("%s_%s_%s", p.ID, p.Type, p.Category) 151 152 if p.hasCategory() { 153 chart := f.charts.Get("retry_count") 154 _ = chart.AddDim(&Dim{ID: id + "_retry_count", Name: p.ID}) 155 chart.MarkNotCreated() 156 } 157 if p.hasBufferQueueLength() { 158 chart := f.charts.Get("buffer_queue_length") 159 _ = chart.AddDim(&Dim{ID: id + "_buffer_queue_length", Name: p.ID}) 160 chart.MarkNotCreated() 161 } 162 if p.hasBufferTotalQueuedSize() { 163 chart := f.charts.Get("buffer_total_queued_size") 164 _ = chart.AddDim(&Dim{ID: id + "_buffer_total_queued_size", Name: p.ID}) 165 chart.MarkNotCreated() 166 } 167 }