github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/cmd/fluent-bit/config_test.go (about)

     1  package main
     2  
     3  import (
     4  	"io/ioutil"
     5  	"net/url"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/grafana/dskit/backoff"
    12  	"github.com/grafana/dskit/flagext"
    13  	"github.com/prometheus/common/model"
    14  	"github.com/weaveworks/common/logging"
    15  
    16  	"github.com/grafana/loki/clients/pkg/promtail/client"
    17  
    18  	lokiflag "github.com/grafana/loki/pkg/util/flagext"
    19  )
    20  
    21  type fakeConfig map[string]string
    22  
    23  func (f fakeConfig) Get(key string) string {
    24  	return f[key]
    25  }
    26  
    27  func Test_parseConfig(t *testing.T) {
    28  	fileName := createTempLabelMap(t)
    29  	defer os.Remove(fileName)
    30  
    31  	tests := []struct {
    32  		name    string
    33  		conf    map[string]string
    34  		want    *config
    35  		wantErr bool
    36  	}{
    37  		{"defaults",
    38  			map[string]string{},
    39  			&config{
    40  				lineFormat: jsonFormat,
    41  				clientConfig: client.Config{
    42  					URL:            mustParseURL("http://localhost:3100/loki/api/v1/push"),
    43  					BatchSize:      defaultClientCfg.BatchSize,
    44  					BatchWait:      defaultClientCfg.BatchWait,
    45  					Timeout:        defaultClientCfg.Timeout,
    46  					ExternalLabels: lokiflag.LabelSet{LabelSet: model.LabelSet{"job": "fluent-bit"}},
    47  					BackoffConfig:  defaultClientCfg.BackoffConfig,
    48  				},
    49  				logLevel:      mustParseLogLevel("info"),
    50  				dropSingleKey: true,
    51  			},
    52  			false},
    53  		{"setting values",
    54  			map[string]string{
    55  				"URL":           "http://somewhere.com:3100/loki/api/v1/push",
    56  				"TenantID":      "my-tenant-id",
    57  				"LineFormat":    "key_value",
    58  				"LogLevel":      "warn",
    59  				"Labels":        `{app="foo"}`,
    60  				"BatchSize":     "100",
    61  				"BatchWait":     "30",
    62  				"Timeout":       "1s",
    63  				"RemoveKeys":    "buzz,fuzz",
    64  				"LabelKeys":     "foo,bar",
    65  				"DropSingleKey": "false",
    66  				"MinBackoff":    "1ms",
    67  				"MaxBackoff":    "5m",
    68  				"MaxRetries":    "10",
    69  			},
    70  			&config{
    71  				lineFormat: kvPairFormat,
    72  				clientConfig: client.Config{
    73  					URL:            mustParseURL("http://somewhere.com:3100/loki/api/v1/push"),
    74  					TenantID:       "my-tenant-id",
    75  					BatchSize:      100,
    76  					BatchWait:      mustParseDuration("30s"),
    77  					Timeout:        mustParseDuration("1s"),
    78  					ExternalLabels: lokiflag.LabelSet{LabelSet: model.LabelSet{"app": "foo"}},
    79  					BackoffConfig:  backoff.Config{MinBackoff: mustParseDuration("1ms"), MaxBackoff: mustParseDuration("5m"), MaxRetries: 10},
    80  				},
    81  				logLevel:      mustParseLogLevel("warn"),
    82  				labelKeys:     []string{"foo", "bar"},
    83  				removeKeys:    []string{"buzz", "fuzz"},
    84  				dropSingleKey: false,
    85  			},
    86  			false},
    87  		{"with label map",
    88  			map[string]string{
    89  				"URL":           "http://somewhere.com:3100/loki/api/v1/push",
    90  				"LineFormat":    "key_value",
    91  				"LogLevel":      "warn",
    92  				"Labels":        `{app="foo"}`,
    93  				"BatchSize":     "100",
    94  				"BatchWait":     "30s",
    95  				"Timeout":       "1s",
    96  				"RemoveKeys":    "buzz,fuzz",
    97  				"LabelKeys":     "foo,bar",
    98  				"DropSingleKey": "false",
    99  				"MinBackoff":    "1ms",
   100  				"MaxBackoff":    "5m",
   101  				"MaxRetries":    "10",
   102  				"LabelMapPath":  fileName,
   103  			},
   104  			&config{
   105  				lineFormat: kvPairFormat,
   106  				clientConfig: client.Config{
   107  					URL:            mustParseURL("http://somewhere.com:3100/loki/api/v1/push"),
   108  					TenantID:       "", // empty as not set in fluent-bit plugin config map
   109  					BatchSize:      100,
   110  					BatchWait:      mustParseDuration("30s"),
   111  					Timeout:        mustParseDuration("1s"),
   112  					ExternalLabels: lokiflag.LabelSet{LabelSet: model.LabelSet{"app": "foo"}},
   113  					BackoffConfig:  backoff.Config{MinBackoff: mustParseDuration("1ms"), MaxBackoff: mustParseDuration("5m"), MaxRetries: 10},
   114  				},
   115  				logLevel:      mustParseLogLevel("warn"),
   116  				labelKeys:     nil,
   117  				removeKeys:    []string{"buzz", "fuzz"},
   118  				dropSingleKey: false,
   119  				labelMap: map[string]interface{}{
   120  					"kubernetes": map[string]interface{}{
   121  						"container_name": "container",
   122  						"host":           "host",
   123  						"namespace_name": "namespace",
   124  						"pod_name":       "instance",
   125  						"labels": map[string]interface{}{
   126  							"component": "component",
   127  							"tier":      "tier",
   128  						},
   129  					},
   130  					"stream": "stream",
   131  				},
   132  			},
   133  			false},
   134  		{"bad url", map[string]string{"URL": "::doh.com"}, nil, true},
   135  		{"bad BatchWait", map[string]string{"BatchWait": "30sa"}, nil, true},
   136  		{"bad BatchSize", map[string]string{"BatchSize": "a"}, nil, true},
   137  		{"bad Timeout", map[string]string{"Timeout": "1a"}, nil, true},
   138  		{"bad labels", map[string]string{"Labels": "a"}, nil, true},
   139  		{"bad format", map[string]string{"LineFormat": "a"}, nil, true},
   140  		{"bad log level", map[string]string{"LogLevel": "a"}, nil, true},
   141  		{"bad drop single key", map[string]string{"DropSingleKey": "a"}, nil, true},
   142  		{"bad MinBackoff", map[string]string{"MinBackoff": "1msa"}, nil, true},
   143  		{"bad MaxBackoff", map[string]string{"MaxBackoff": "5ma"}, nil, true},
   144  		{"bad MaxRetries", map[string]string{"MaxRetries": "a"}, nil, true},
   145  		{"bad labelmap file", map[string]string{"LabelMapPath": "a"}, nil, true},
   146  	}
   147  	for _, tt := range tests {
   148  		t.Run(tt.name, func(t *testing.T) {
   149  			got, err := parseConfig(fakeConfig(tt.conf))
   150  			if (err != nil) != tt.wantErr {
   151  				t.Errorf("parseConfig() error = %v, wantErr %v", err, tt.wantErr)
   152  				return
   153  			}
   154  			if !tt.wantErr {
   155  				assertConfig(t, got, tt.want)
   156  			}
   157  		})
   158  	}
   159  }
   160  
   161  func assertConfig(t *testing.T, expected, actual *config) {
   162  	if expected.clientConfig.BatchSize != actual.clientConfig.BatchSize {
   163  		t.Errorf("incorrect batch size want:%v got:%v", expected.clientConfig.BatchSize, actual.clientConfig.BatchSize)
   164  	}
   165  	if !reflect.DeepEqual(expected.clientConfig.ExternalLabels, actual.clientConfig.ExternalLabels) {
   166  		t.Errorf("incorrect labels want:%v got:%v", expected.clientConfig.ExternalLabels, actual.clientConfig.ExternalLabels)
   167  	}
   168  	if expected.clientConfig.BatchWait != actual.clientConfig.BatchWait {
   169  		t.Errorf("incorrect batch wait want:%v got:%v", expected.clientConfig.BatchWait, actual.clientConfig.BatchWait)
   170  	}
   171  	if expected.clientConfig.Timeout != actual.clientConfig.Timeout {
   172  		t.Errorf("incorrect Timeout want:%v got:%v", expected.clientConfig.Timeout, actual.clientConfig.Timeout)
   173  	}
   174  	if expected.clientConfig.BackoffConfig.MinBackoff != actual.clientConfig.BackoffConfig.MinBackoff {
   175  		t.Errorf("incorrect MinBackoff want:%v got:%v", expected.clientConfig.BackoffConfig.MinBackoff, actual.clientConfig.BackoffConfig.MinBackoff)
   176  	}
   177  	if expected.clientConfig.BackoffConfig.MaxBackoff != actual.clientConfig.BackoffConfig.MaxBackoff {
   178  		t.Errorf("incorrect MaxBackoff want:%v got:%v", expected.clientConfig.BackoffConfig.MaxBackoff, actual.clientConfig.BackoffConfig.MaxBackoff)
   179  	}
   180  	if expected.clientConfig.BackoffConfig.MaxRetries != actual.clientConfig.BackoffConfig.MaxRetries {
   181  		t.Errorf("incorrect MaxRetries want:%v got:%v", expected.clientConfig.BackoffConfig.MaxRetries, actual.clientConfig.BackoffConfig.MaxRetries)
   182  	}
   183  	if !reflect.DeepEqual(expected.clientConfig.URL, actual.clientConfig.URL) {
   184  		t.Errorf("incorrect URL want:%v got:%v", expected.clientConfig.URL, actual.clientConfig.URL)
   185  	}
   186  	if !reflect.DeepEqual(expected.clientConfig.TenantID, actual.clientConfig.TenantID) {
   187  		t.Errorf("incorrect TenantID want:%v got:%v", expected.clientConfig.TenantID, actual.clientConfig.TenantID)
   188  	}
   189  	if !reflect.DeepEqual(expected.lineFormat, actual.lineFormat) {
   190  		t.Errorf("incorrect lineFormat want:%v got:%v", expected.lineFormat, actual.lineFormat)
   191  	}
   192  	if !reflect.DeepEqual(expected.removeKeys, actual.removeKeys) {
   193  		t.Errorf("incorrect removeKeys want:%v got:%v", expected.removeKeys, actual.removeKeys)
   194  	}
   195  	if !reflect.DeepEqual(expected.labelKeys, actual.labelKeys) {
   196  		t.Errorf("incorrect labelKeys want:%v got:%v", expected.labelKeys, actual.labelKeys)
   197  	}
   198  	if expected.logLevel.String() != actual.logLevel.String() {
   199  		t.Errorf("incorrect logLevel want:%v got:%v", expected.logLevel.String(), actual.logLevel.String())
   200  	}
   201  	if !reflect.DeepEqual(expected.labelMap, actual.labelMap) {
   202  		t.Errorf("incorrect labelMap want:%v got:%v", expected.labelMap, actual.labelMap)
   203  	}
   204  }
   205  
   206  func mustParseURL(u string) flagext.URLValue {
   207  	parsed, err := url.Parse(u)
   208  	if err != nil {
   209  		panic(err)
   210  	}
   211  	return flagext.URLValue{URL: parsed}
   212  }
   213  
   214  func mustParseLogLevel(l string) logging.Level {
   215  	level := logging.Level{}
   216  	err := level.Set(l)
   217  	if err != nil {
   218  		panic(err)
   219  	}
   220  	return level
   221  }
   222  
   223  func mustParseDuration(u string) time.Duration {
   224  	parsed, err := time.ParseDuration(u)
   225  	if err != nil {
   226  		panic(err)
   227  	}
   228  	return parsed
   229  }
   230  
   231  func createTempLabelMap(t *testing.T) string {
   232  	file, err := ioutil.TempFile("", "labelmap")
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  	_, err = file.WriteString(`{
   237          "kubernetes": {
   238              "namespace_name": "namespace",
   239              "labels": {
   240                  "component": "component",
   241                  "tier": "tier"
   242              },
   243              "host": "host",
   244              "container_name": "container",
   245              "pod_name": "instance"
   246          },
   247          "stream": "stream"
   248      }`)
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  	return file.Name()
   253  }