github.com/netdata/go.d.plugin@v0.58.1/modules/springboot2/springboot2.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package springboot2
     4  
     5  import (
     6  	_ "embed"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/netdata/go.d.plugin/pkg/matcher"
    11  
    12  	mtx "github.com/netdata/go.d.plugin/pkg/metrics"
    13  	"github.com/netdata/go.d.plugin/pkg/prometheus"
    14  	"github.com/netdata/go.d.plugin/pkg/stm"
    15  	"github.com/netdata/go.d.plugin/pkg/web"
    16  
    17  	"github.com/netdata/go.d.plugin/agent/module"
    18  )
    19  
    20  //go:embed "config_schema.json"
    21  var configSchema string
    22  
    23  func init() {
    24  	module.Register("springboot2", module.Creator{
    25  		JobConfigSchema: configSchema,
    26  		Create:          func() module.Module { return New() },
    27  	})
    28  }
    29  
    30  const (
    31  	defaultHTTPTimeout = time.Second
    32  )
    33  
    34  // New returns SpringBoot2 instance with default values
    35  func New() *SpringBoot2 {
    36  	return &SpringBoot2{
    37  		HTTP: web.HTTP{
    38  			Client: web.Client{
    39  				Timeout: web.Duration{Duration: defaultHTTPTimeout},
    40  			},
    41  		},
    42  	}
    43  }
    44  
    45  // SpringBoot2 Spring boot 2 module
    46  type SpringBoot2 struct {
    47  	module.Base
    48  
    49  	web.HTTP  `yaml:",inline"`
    50  	URIFilter matcher.SimpleExpr `yaml:"uri_filter"`
    51  
    52  	uriFilter matcher.Matcher
    53  
    54  	prom prometheus.Prometheus
    55  }
    56  
    57  type metrics struct {
    58  	Uptime mtx.Gauge `stm:"uptime,1000"`
    59  
    60  	ThreadsDaemon mtx.Gauge `stm:"threads_daemon"`
    61  	Threads       mtx.Gauge `stm:"threads"`
    62  
    63  	Resp1xx mtx.Counter `stm:"resp_1xx"`
    64  	Resp2xx mtx.Counter `stm:"resp_2xx"`
    65  	Resp3xx mtx.Counter `stm:"resp_3xx"`
    66  	Resp4xx mtx.Counter `stm:"resp_4xx"`
    67  	Resp5xx mtx.Counter `stm:"resp_5xx"`
    68  
    69  	HeapUsed      heap `stm:"heap_used"`
    70  	HeapCommitted heap `stm:"heap_committed"`
    71  
    72  	MemFree mtx.Gauge `stm:"mem_free"`
    73  }
    74  
    75  type heap struct {
    76  	Eden     mtx.Gauge `stm:"eden"`
    77  	Survivor mtx.Gauge `stm:"survivor"`
    78  	Old      mtx.Gauge `stm:"old"`
    79  }
    80  
    81  // Cleanup Cleanup
    82  func (SpringBoot2) Cleanup() {}
    83  
    84  // Init makes initialization
    85  func (s *SpringBoot2) Init() bool {
    86  	client, err := web.NewHTTPClient(s.Client)
    87  	if err != nil {
    88  		s.Error(err)
    89  		return false
    90  	}
    91  	s.uriFilter, err = s.URIFilter.Parse()
    92  	if err != nil && err != matcher.ErrEmptyExpr {
    93  		s.Error(err)
    94  		return false
    95  	}
    96  	s.prom = prometheus.New(client, s.Request)
    97  	return true
    98  }
    99  
   100  // Check makes check
   101  func (s *SpringBoot2) Check() bool {
   102  	rawMetrics, err := s.prom.ScrapeSeries()
   103  	if err != nil {
   104  		s.Warning(err)
   105  		return false
   106  	}
   107  	jvmMemory := rawMetrics.FindByName("jvm_memory_used_bytes")
   108  
   109  	return len(jvmMemory) > 0
   110  }
   111  
   112  // Charts creates Charts
   113  func (SpringBoot2) Charts() *Charts {
   114  	return charts.Copy()
   115  }
   116  
   117  // Collect collects metrics
   118  func (s *SpringBoot2) Collect() map[string]int64 {
   119  	rawMetrics, err := s.prom.ScrapeSeries()
   120  	if err != nil {
   121  		return nil
   122  	}
   123  
   124  	var m metrics
   125  
   126  	// uptime
   127  	m.Uptime.Set(rawMetrics.FindByName("process_uptime_seconds").Max())
   128  
   129  	// response
   130  	s.gatherResponse(rawMetrics, &m)
   131  
   132  	// threads
   133  	m.ThreadsDaemon.Set(rawMetrics.FindByNames("jvm_threads_daemon", "jvm_threads_daemon_threads").Max())
   134  	m.Threads.Set(rawMetrics.FindByNames("jvm_threads_live", "jvm_threads_live_threads").Max())
   135  
   136  	// heap memory
   137  	gatherHeap(rawMetrics.FindByName("jvm_memory_used_bytes"), &m.HeapUsed)
   138  	gatherHeap(rawMetrics.FindByName("jvm_memory_committed_bytes"), &m.HeapCommitted)
   139  	m.MemFree.Set(m.HeapCommitted.Sum() - m.HeapUsed.Sum())
   140  
   141  	return stm.ToMap(m)
   142  }
   143  
   144  func gatherHeap(rawMetrics prometheus.Series, m *heap) {
   145  	for _, metric := range rawMetrics {
   146  		id := metric.Labels.Get("id")
   147  		value := metric.Value
   148  		switch {
   149  		case strings.Contains(id, "Eden"):
   150  			m.Eden.Set(value)
   151  		case strings.Contains(id, "Survivor"):
   152  			m.Survivor.Set(value)
   153  		case strings.Contains(id, "Old") || strings.Contains(id, "Tenured"):
   154  			m.Old.Set(value)
   155  		}
   156  	}
   157  }
   158  
   159  func (s *SpringBoot2) gatherResponse(rawMetrics prometheus.Series, m *metrics) {
   160  	for _, metric := range rawMetrics.FindByName("http_server_requests_seconds_count") {
   161  		if s.uriFilter != nil {
   162  			uri := metric.Labels.Get("uri")
   163  			if !s.uriFilter.MatchString(uri) {
   164  				continue
   165  			}
   166  		}
   167  
   168  		status := metric.Labels.Get("status")
   169  		if status == "" {
   170  			continue
   171  		}
   172  		value := metric.Value
   173  		switch status[0] {
   174  		case '1':
   175  			m.Resp1xx.Add(value)
   176  		case '2':
   177  			m.Resp2xx.Add(value)
   178  		case '3':
   179  			m.Resp3xx.Add(value)
   180  		case '4':
   181  			m.Resp4xx.Add(value)
   182  		case '5':
   183  			m.Resp5xx.Add(value)
   184  		}
   185  	}
   186  }
   187  
   188  func (h heap) Sum() float64 {
   189  	return h.Eden.Value() + h.Survivor.Value() + h.Old.Value()
   190  }