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  }