Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
271
plugins/inputs/opensearch_query/opensearch_query.go
Normal file
271
plugins/inputs/opensearch_query/opensearch_query.go
Normal file
|
@ -0,0 +1,271 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package opensearch_query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/opensearch-project/opensearch-go/v2"
|
||||
"github.com/opensearch-project/opensearch-go/v2/opensearchapi"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
common_tls "github.com/influxdata/telegraf/plugins/common/tls"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
type OpensearchQuery struct {
|
||||
URLs []string `toml:"urls"`
|
||||
Username config.Secret `toml:"username"`
|
||||
Password config.Secret `toml:"password"`
|
||||
EnableSniffer bool `toml:"enable_sniffer"`
|
||||
Timeout config.Duration `toml:"timeout"`
|
||||
HealthCheckInterval config.Duration `toml:"health_check_interval"`
|
||||
Aggregations []osAggregation `toml:"aggregation"`
|
||||
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
common_tls.ClientConfig
|
||||
osClient *opensearch.Client
|
||||
}
|
||||
|
||||
type osAggregation struct {
|
||||
Index string `toml:"index"`
|
||||
MeasurementName string `toml:"measurement_name"`
|
||||
DateField string `toml:"date_field"`
|
||||
DateFieldFormat string `toml:"date_field_custom_format"`
|
||||
QueryPeriod config.Duration `toml:"query_period"`
|
||||
FilterQuery string `toml:"filter_query"`
|
||||
MetricFields []string `toml:"metric_fields"`
|
||||
MetricFunction string `toml:"metric_function"`
|
||||
Tags []string `toml:"tags"`
|
||||
IncludeMissingTag bool `toml:"include_missing_tag"`
|
||||
MissingTagValue string `toml:"missing_tag_value"`
|
||||
mapMetricFields map[string]string
|
||||
|
||||
aggregation aggregationRequest
|
||||
}
|
||||
|
||||
func (*OpensearchQuery) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (o *OpensearchQuery) Init() error {
|
||||
if o.URLs == nil {
|
||||
return errors.New("no urls defined")
|
||||
}
|
||||
|
||||
err := o.newClient()
|
||||
if err != nil {
|
||||
o.Log.Errorf("Error creating OpenSearch client: %v", err)
|
||||
}
|
||||
|
||||
for i, agg := range o.Aggregations {
|
||||
if agg.MeasurementName == "" {
|
||||
return errors.New("field 'measurement_name' is not set")
|
||||
}
|
||||
if agg.DateField == "" {
|
||||
return errors.New("field 'date_field' is not set")
|
||||
}
|
||||
err = o.initAggregation(agg, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpensearchQuery) Gather(acc telegraf.Accumulator) error {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, agg := range o.Aggregations {
|
||||
wg.Add(1)
|
||||
go func(agg osAggregation) {
|
||||
defer wg.Done()
|
||||
err := o.osAggregationQuery(acc, agg)
|
||||
if err != nil {
|
||||
acc.AddError(fmt.Errorf("opensearch query aggregation %q: %w ", agg.MeasurementName, err))
|
||||
}
|
||||
}(agg)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpensearchQuery) newClient() error {
|
||||
username, err := o.Username.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting username failed: %w", err)
|
||||
}
|
||||
defer username.Destroy()
|
||||
|
||||
password, err := o.Password.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting password failed: %w", err)
|
||||
}
|
||||
defer password.Destroy()
|
||||
|
||||
clientConfig := opensearch.Config{
|
||||
Addresses: o.URLs,
|
||||
Username: username.String(),
|
||||
Password: password.String(),
|
||||
}
|
||||
|
||||
if o.InsecureSkipVerify {
|
||||
clientConfig.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
}
|
||||
|
||||
client, err := opensearch.NewClient(clientConfig)
|
||||
o.osClient = client
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *OpensearchQuery) initAggregation(agg osAggregation, i int) (err error) {
|
||||
for _, metricField := range agg.MetricFields {
|
||||
if _, ok := agg.mapMetricFields[metricField]; !ok {
|
||||
return fmt.Errorf("metric field %q not found on index %q", metricField, agg.Index)
|
||||
}
|
||||
}
|
||||
|
||||
err = agg.buildAggregationQuery()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error building aggregation: %w", err)
|
||||
}
|
||||
|
||||
o.Aggregations[i] = agg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpensearchQuery) osAggregationQuery(acc telegraf.Accumulator, aggregation osAggregation) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(o.Timeout))
|
||||
defer cancel()
|
||||
|
||||
searchResult, err := o.runAggregationQuery(ctx, aggregation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return searchResult.getMetrics(acc, aggregation.MeasurementName)
|
||||
}
|
||||
|
||||
func (o *OpensearchQuery) runAggregationQuery(ctx context.Context, aggregation osAggregation) (*aggregationResponse, error) {
|
||||
now := time.Now().UTC()
|
||||
from := now.Add(time.Duration(-aggregation.QueryPeriod))
|
||||
filterQuery := aggregation.FilterQuery
|
||||
if filterQuery == "" {
|
||||
filterQuery = "*"
|
||||
}
|
||||
|
||||
aq := &query{
|
||||
Size: 0,
|
||||
Aggregations: aggregation.aggregation,
|
||||
Query: nil,
|
||||
}
|
||||
|
||||
boolQuery := &boolQuery{
|
||||
FilterQueryString: filterQuery,
|
||||
TimestampField: aggregation.DateField,
|
||||
TimeRangeFrom: from,
|
||||
TimeRangeTo: now,
|
||||
DateFieldFormat: aggregation.DateFieldFormat,
|
||||
}
|
||||
|
||||
aq.Query = boolQuery
|
||||
req, err := json.Marshal(aq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
|
||||
searchRequest := &opensearchapi.SearchRequest{
|
||||
Body: strings.NewReader(string(req)),
|
||||
Index: []string{aggregation.Index},
|
||||
Timeout: time.Duration(o.Timeout),
|
||||
}
|
||||
|
||||
resp, err := searchRequest.Do(ctx, o.osClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.IsError() {
|
||||
return nil, fmt.Errorf("opensearch SearchRequest failure: [%d] %s", resp.StatusCode, resp.Status())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var searchResult aggregationResponse
|
||||
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
err = decoder.Decode(&searchResult)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &searchResult, nil
|
||||
}
|
||||
|
||||
func (aggregation *osAggregation) buildAggregationQuery() error {
|
||||
var agg aggregationRequest
|
||||
agg = &metricAggregationRequest{}
|
||||
|
||||
// create one aggregation per metric field found & function defined for numeric fields
|
||||
for k, v := range aggregation.mapMetricFields {
|
||||
switch v {
|
||||
case "long", "float", "integer", "short", "double", "scaled_float":
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
err := agg.addAggregation(strings.ReplaceAll(k, ".", "_")+"_"+aggregation.MetricFunction, aggregation.MetricFunction, k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// create a terms aggregation per tag
|
||||
for _, term := range aggregation.Tags {
|
||||
bucket := &bucketAggregationRequest{}
|
||||
name := strings.ReplaceAll(term, ".", "_")
|
||||
err := bucket.addAggregation(name, "terms", term)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = bucket.bucketSize(name, 1000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if aggregation.IncludeMissingTag && aggregation.MissingTagValue != "" {
|
||||
bucket.missing(name, aggregation.MissingTagValue)
|
||||
}
|
||||
|
||||
bucket.addNestedAggregation(name, agg)
|
||||
|
||||
agg = bucket
|
||||
}
|
||||
|
||||
aggregation.aggregation = agg
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("opensearch_query", func() telegraf.Input {
|
||||
return &OpensearchQuery{
|
||||
Timeout: config.Duration(time.Second * 5),
|
||||
HealthCheckInterval: config.Duration(time.Second * 10),
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue