diff --git a/agent/logs_agent.go b/agent/logs_agent.go index cfab1dfa..efdb1c6e 100644 --- a/agent/logs_agent.go +++ b/agent/logs_agent.go @@ -17,7 +17,6 @@ import ( logsconfig "flashcat.cloud/categraf/config/logs" "flashcat.cloud/categraf/logs/auditor" "flashcat.cloud/categraf/logs/client" - "flashcat.cloud/categraf/logs/client/http" "flashcat.cloud/categraf/logs/diagnostic" "flashcat.cloud/categraf/logs/input/file" "flashcat.cloud/categraf/logs/input/journald" @@ -154,11 +153,7 @@ func (a *Agent) startLogAgent() { return } - httpConnectivity := logsconfig.HTTPConnectivityFailure - if endpoints, err := BuildHTTPEndpoints(intakeTrackType, AgentJSONIntakeProtocol, logsconfig.DefaultIntakeOrigin); err == nil { - httpConnectivity = http.CheckConnectivity(endpoints.Main) - } - endpoints, err := BuildEndpoints(httpConnectivity, intakeTrackType, AgentJSONIntakeProtocol, logsconfig.DefaultIntakeOrigin) + endpoints, err := BuildEndpoints(intakeTrackType, AgentJSONIntakeProtocol, logsconfig.DefaultIntakeOrigin) processingRules, err := GlobalProcessingRules() if err != nil { message := fmt.Sprintf("Invalid processing rules: %v", err) diff --git a/agent/logs_endpoints.go b/agent/logs_endpoints.go index 6ca5822a..b31f6e2e 100644 --- a/agent/logs_endpoints.go +++ b/agent/logs_endpoints.go @@ -23,20 +23,70 @@ const ( ) // BuildEndpoints returns the endpoints to send logs. -func BuildEndpoints(httpConnectivity logsconfig.HTTPConnectivity, intakeTrackType logsconfig.IntakeTrackType, intakeProtocol logsconfig.IntakeProtocol, intakeOrigin logsconfig.IntakeOrigin) (*logsconfig.Endpoints, error) { - return BuildEndpointsWithConfig(httpEndpointPrefix, httpConnectivity, intakeTrackType, intakeProtocol, intakeOrigin) +func BuildEndpoints(intakeTrackType logsconfig.IntakeTrackType, intakeProtocol logsconfig.IntakeProtocol, intakeOrigin logsconfig.IntakeOrigin) (*logsconfig.Endpoints, error) { + return BuildEndpointsWithConfig(httpEndpointPrefix, intakeTrackType, intakeProtocol, intakeOrigin) } // BuildEndpointsWithConfig returns the endpoints to send logs. -func BuildEndpointsWithConfig(endpointPrefix string, httpConnectivity logsconfig.HTTPConnectivity, intakeTrackType logsconfig.IntakeTrackType, intakeProtocol logsconfig.IntakeProtocol, intakeOrigin logsconfig.IntakeOrigin) (*logsconfig.Endpoints, error) { +func BuildEndpointsWithConfig(endpointPrefix string, intakeTrackType logsconfig.IntakeTrackType, intakeProtocol logsconfig.IntakeProtocol, intakeOrigin logsconfig.IntakeOrigin) (*logsconfig.Endpoints, error) { logsConfig := coreconfig.Config.Logs - if logsConfig.SendType == "http" || (bool(httpConnectivity) && !(logsConfig.SendType == "tcp")) { + switch logsConfig.SendType { + case "http": return BuildHTTPEndpointsWithConfig(endpointPrefix, intakeTrackType, intakeProtocol, intakeOrigin) + case "tcp": + return buildTCPEndpoints(logsConfig) + case "kafka": + return buildKafkaEndpoints(logsConfig) + } return buildTCPEndpoints(logsConfig) } +func buildKafkaEndpoints(logsConfig coreconfig.Logs) (*logsconfig.Endpoints, error) { + // return nil, nil + // Provide default values for legacy settings when the configuration key does not exist + defaultTLS := coreconfig.Config.Logs.SendWithTLS + + main := logsconfig.Endpoint{ + APIKey: strings.TrimSpace(logsConfig.APIKey), + UseCompression: logsConfig.UseCompression, + CompressionLevel: logsConfig.CompressionLevel, + ConnectionResetInterval: 0, + BackoffBase: 1.0, + BackoffMax: 120.0, + BackoffFactor: 2.0, + RecoveryInterval: 2, + RecoveryReset: false, + Addr: logsConfig.SendTo, + Topic: logsConfig.Topic, + } + + if intakeTrackType != "" { + main.Version = logsconfig.EPIntakeVersion2 + main.TrackType = intakeTrackType + } else { + main.Version = logsconfig.EPIntakeVersion1 + } + + if len(logsConfig.SendTo) != 0 { + brokers := strings.Split(logsConfig.SendTo, ",") + if len(brokers) == 0 { + return nil, fmt.Errorf("wrong send_to content %s", logsConfig.SendTo) + } + host, port, err := parseAddress(brokers[0]) + if err != nil { + return nil, fmt.Errorf("could not parse %s: %v", logsConfig.SendTo, err) + } + main.Host = host + main.Port = port + main.UseSSL = defaultTLS + } else { + return nil, fmt.Errorf("empty send_to is not allowed when send_type is kafka") + } + return NewEndpoints(main, false, "kafka"), nil +} + func buildTCPEndpoints(logsConfig coreconfig.Logs) (*logsconfig.Endpoints, error) { main := logsconfig.Endpoint{ APIKey: logsConfig.APIKey, @@ -58,7 +108,7 @@ func buildTCPEndpoints(logsConfig coreconfig.Logs) (*logsconfig.Endpoints, error main.UseSSL = logsConfig.SendWithTLS } - return NewEndpoints(main, false, false), nil + return NewEndpoints(main, false, "tcp"), nil } // BuildHTTPEndpoints returns the HTTP endpoints to send logs to. @@ -112,7 +162,7 @@ func BuildHTTPEndpointsWithConfig(endpointPrefix string, intakeTrackType logscon batchMaxSize := 100 batchMaxContentSize := 1000000 - return NewEndpointsWithBatchSettings(main, false, true, batchWait, batchMaxConcurrentSend, batchMaxSize, batchMaxContentSize), nil + return NewEndpointsWithBatchSettings(main, false, "http", batchWait, batchMaxConcurrentSend, batchMaxSize, batchMaxContentSize), nil } // parseAddress returns the host and the port of the address. @@ -129,13 +179,13 @@ func parseAddress(address string) (string, int, error) { } // NewEndpoints returns a new endpoints composite with default batching settings -func NewEndpoints(main logsconfig.Endpoint, useProto bool, useHTTP bool) *logsconfig.Endpoints { +func NewEndpoints(main logsconfig.Endpoint, useProto bool, typ string) *logsconfig.Endpoints { logsConfig := coreconfig.Config.Logs return &logsconfig.Endpoints{ Main: main, Additionals: nil, UseProto: useProto, - UseHTTP: useHTTP, + Type: typ, BatchWait: time.Duration(logsConfig.BatchWait) * time.Second, // TODO support custom param BatchMaxConcurrentSend: 0, @@ -145,12 +195,12 @@ func NewEndpoints(main logsconfig.Endpoint, useProto bool, useHTTP bool) *logsco } // NewEndpointsWithBatchSettings returns a new endpoints composite with non-default batching settings specified -func NewEndpointsWithBatchSettings(main logsconfig.Endpoint, useProto bool, useHTTP bool, batchWait time.Duration, batchMaxConcurrentSend int, batchMaxSize int, batchMaxContentSize int) *logsconfig.Endpoints { +func NewEndpointsWithBatchSettings(main logsconfig.Endpoint, useProto bool, typ string, batchWait time.Duration, batchMaxConcurrentSend int, batchMaxSize int, batchMaxContentSize int) *logsconfig.Endpoints { return &logsconfig.Endpoints{ Main: main, Additionals: nil, UseProto: useProto, - UseHTTP: useHTTP, + Type: typ, BatchWait: batchWait, BatchMaxConcurrentSend: batchMaxConcurrentSend, BatchMaxSize: batchMaxSize, diff --git a/conf/logs.toml b/conf/logs.toml index 606fd938..f60f2072 100644 --- a/conf/logs.toml +++ b/conf/logs.toml @@ -3,10 +3,11 @@ api_key = "ef4ahfbwzwwtlwfpbertgq1i6mq0ab1q" ## 是否开启日志采集 enable = false -## 接受日志的server地址 +## 接受日志的server地址, http/tcp/kafka, 只有kafka支持多个地址(broker)用逗号分割 send_to = "127.0.0.1:17878" -## 发送日志的协议 http/tcp +## 发送日志的协议 http/tcp/kafka send_type = "http" +topic = "flashcatcloud" ## 是否压缩发送 use_compress = false ## 是否采用ssl @@ -32,4 +33,4 @@ collect_container_all = true ## type=file时 path必填,type=journald/tcp/udp时 port必填 path = "/opt/tomcat/logs/*.txt" source = "tomcat" - service = "my_service" + service = "my_service" \ No newline at end of file diff --git a/config/logs.go b/config/logs.go index a4efc8d3..a4926255 100644 --- a/config/logs.go +++ b/config/logs.go @@ -1,6 +1,8 @@ package config import ( + "github.com/Shopify/sarama" + logsconfig "flashcat.cloud/categraf/config/logs" ) @@ -26,6 +28,12 @@ type ( CollectContainerAll bool `json:"collect_container_all" toml:"collect_container_all"` GlobalProcessingRules []*logsconfig.ProcessingRule `json:"processing_rules" toml:"processing_rules"` Items []*logsconfig.LogsConfig `json:"items" toml:"items"` + KafkaConfig + } + KafkaConfig struct { + Topic string `json:"topic" toml:"topic"` + Brokers []string `json:"brokers" toml:"brokers"` + *sarama.Config } ) diff --git a/config/logs/endpoints.go b/config/logs/endpoints.go index 2d8489a0..6e49a0ca 100644 --- a/config/logs/endpoints.go +++ b/config/logs/endpoints.go @@ -29,9 +29,11 @@ const ( EPIntakeVersion2 ) -// Endpoint holds all the organization and network parameters to send logs to Datadog. +// Endpoint holds all the organization and network parameters to send logs type Endpoint struct { APIKey string `mapstructure:"api_key" json:"api_key"` + Addr string + Topic string Host string Port int UseSSL bool @@ -57,7 +59,7 @@ type Endpoints struct { Main Endpoint Additionals []Endpoint UseProto bool - UseHTTP bool + Type string BatchWait time.Duration BatchMaxConcurrentSend int BatchMaxSize int diff --git a/config/logs/integration_config.go b/config/logs/integration_config.go index 2b1b2fec..1341101e 100644 --- a/config/logs/integration_config.go +++ b/config/logs/integration_config.go @@ -29,45 +29,47 @@ const ( // LogsConfig represents a log source config, which can be for instance // a file to tail or a port to listen to. -type LogsConfig struct { - Type string - - Port int // Network - IdleTimeout string `mapstructure:"idle_timeout" json:"idle_timeout"` // Network - Path string // File, Journald - - Encoding string `mapstructure:"encoding" json:"encoding"` // File - ExcludePaths []string `mapstructure:"exclude_paths" json:"exclude_paths"` // File - TailingMode string `mapstructure:"start_position" json:"start_position"` // File - - IncludeUnits []string `mapstructure:"include_units" json:"include_units"` // Journald - ExcludeUnits []string `mapstructure:"exclude_units" json:"exclude_units"` // Journald - ContainerMode bool `mapstructure:"container_mode" json:"container_mode"` // Journald - - Image string // Docker - Label string // Docker - // Name contains the container name - Name string // Docker - // Identifier contains the container ID - Identifier string // Docker - - ChannelPath string `mapstructure:"channel_path" json:"channel_path"` // Windows Event - Query string // Windows Event - - // used as input only by the Channel tailer. - // could have been unidirectional but the tailer could not close it in this case. - Channel chan *ChannelMessage `json:"-"` - - Service string - Source string - SourceCategory string - Tags []string - ProcessingRules []*ProcessingRule `mapstructure:"log_processing_rules" json:"log_processing_rules"` - - AutoMultiLine bool `mapstructure:"auto_multi_line_detection" json:"auto_multi_line_detection"` - AutoMultiLineSampleSize int `mapstructure:"auto_multi_line_sample_size" json:"auto_multi_line_sample_size"` - AutoMultiLineMatchThreshold float64 `mapstructure:"auto_multi_line_match_threshold" json:"auto_multi_line_match_threshold"` -} +type ( + LogsConfig struct { + Type string + + Port int // Network + IdleTimeout string `mapstructure:"idle_timeout" json:"idle_timeout"` // Network + Path string // File, Journald + + Encoding string `mapstructure:"encoding" json:"encoding"` // File + ExcludePaths []string `mapstructure:"exclude_paths" json:"exclude_paths"` // File + TailingMode string `mapstructure:"start_position" json:"start_position"` // File + + IncludeUnits []string `mapstructure:"include_units" json:"include_units"` // Journald + ExcludeUnits []string `mapstructure:"exclude_units" json:"exclude_units"` // Journald + ContainerMode bool `mapstructure:"container_mode" json:"container_mode"` // Journald + + Image string // Docker + Label string // Docker + // Name contains the container name + Name string // Docker + // Identifier contains the container ID + Identifier string // Docker + + ChannelPath string `mapstructure:"channel_path" json:"channel_path"` // Windows Event + Query string // Windows Event + + // used as input only by the Channel tailer. + // could have been unidirectional but the tailer could not close it in this case. + Channel chan *ChannelMessage `json:"-"` + + Service string + Source string + SourceCategory string + Tags []string + ProcessingRules []*ProcessingRule `mapstructure:"log_processing_rules" json:"log_processing_rules"` + + AutoMultiLine bool `mapstructure:"auto_multi_line_detection" json:"auto_multi_line_detection"` + AutoMultiLineSampleSize int `mapstructure:"auto_multi_line_sample_size" json:"auto_multi_line_sample_size"` + AutoMultiLineMatchThreshold float64 `mapstructure:"auto_multi_line_match_threshold" json:"auto_multi_line_match_threshold"` + } +) // TailingMode type type TailingMode uint8 diff --git a/go.mod b/go.mod index a5fe2b6a..8dba7a7d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/ClickHouse/clickhouse-go/v2 v2.0.15 + github.com/Shopify/sarama v1.34.0 github.com/chai2010/winsvc v0.0.0-20200705094454-db7ec320025c github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/docker/docker v20.10.16+incompatible @@ -31,7 +32,7 @@ require ( github.com/stretchr/testify v1.7.2 github.com/toolkits/pkg v1.3.0 github.com/ulricqin/gosnmp v0.0.1 - golang.org/x/net v0.0.0-20210525063256-abc453219eb5 + golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 golang.org/x/text v0.3.7 ) @@ -47,6 +48,9 @@ require ( github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect + github.com/eapache/go-resiliency v1.2.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect + github.com/eapache/queue v1.1.0 // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/color v1.9.0 // indirect github.com/fatih/structs v1.1.0 // indirect @@ -57,12 +61,21 @@ require ( github.com/godror/knownpb v0.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-hclog v0.12.0 // indirect github.com/hashicorp/go-immutable-radix v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.1 // indirect github.com/hashicorp/serf v0.9.6 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.0.0 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect + github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/klauspost/compress v1.15.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-isatty v0.0.12 // indirect @@ -77,8 +90,9 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/sirupsen/logrus v1.7.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/stretchr/objx v0.1.1 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect @@ -86,6 +100,7 @@ require ( go.opentelemetry.io/otel v1.7.0 // indirect go.opentelemetry.io/otel/trace v1.7.0 // indirect go.uber.org/automaxprocs v1.4.0 // indirect + golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 // indirect google.golang.org/grpc v1.33.1 // indirect diff --git a/go.sum b/go.sum index 331f3335..50a6ea58 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,10 @@ github.com/ClickHouse/clickhouse-go/v2 v2.0.15 h1:lLAZliqrZEygkxosLaW1qHyeTb4Ho7 github.com/ClickHouse/clickhouse-go/v2 v2.0.15/go.mod h1:Z21o82zD8FFqefOQDg93c0XITlxGbTsWQuRm588Azkk= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Shopify/sarama v1.34.0 h1:j4zTaFHFnfvuV2fdLZyXqIg0Tu4Mzl9f064Z5/H+o4o= +github.com/Shopify/sarama v1.34.0/go.mod h1:V2ceE9UupUf4/oP1Z38SI49fAnD0/MtkqDDHvolIeeQ= +github.com/Shopify/toxiproxy/v2 v2.3.0 h1:62YkpiP4bzdhKMH+6uC5E95y608k3zDwdzuBMsnn3uQ= +github.com/Shopify/toxiproxy/v2 v2.3.0/go.mod h1:KvQTtB6RjCJY4zqNJn7C7JDFgsG5uoHYDirfUfpIm0c= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -75,6 +79,7 @@ github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -90,6 +95,12 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -101,6 +112,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.11.0/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= github.com/frankban/quicktest v1.11.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= @@ -217,6 +230,9 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -235,16 +251,18 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -262,6 +280,18 @@ github.com/influxdata/line-protocol/v2 v2.0.0-20210312151457-c52fdecb625a/go.mod github.com/influxdata/line-protocol/v2 v2.1.0/go.mod h1:QKw43hdUBg3GTk2iC3iyCxksNj7PX9aUSeYOYE/ceHY= github.com/influxdata/line-protocol/v2 v2.2.1 h1:EAPkqJ9Km4uAxtMRgUubJyqAr6zgWM0dznKMLRauQRE= github.com/influxdata/line-protocol/v2 v2.2.1/go.mod h1:DmB3Cnh+3oxmG6LOBIxce4oaL4CPj3OmMPgvauXh+tM= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= @@ -279,6 +309,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7 h1:SWlt7BoQNASbhTUD0Oy5yysI2seJ7vWuGUp///OM4TM= github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7/go.mod h1:Y2SaZf2Rzd0pXkLVhLlCiAXFCLSXAIbTKDivVgff/AM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -286,8 +318,9 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -336,7 +369,6 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc= @@ -391,9 +423,14 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/prometheus v2.5.0+incompatible h1:7QPitgO2kOFG8ecuRn9O/4L9+10He72rVRJvMXrE9Hg= github.com/prometheus/prometheus v2.5.0+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62/go.mod h1:65XQgovT59RWatovFwnwocoUxiI/eENTnOY5GK3STuY= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -404,11 +441,13 @@ github.com/shirou/gopsutil/v3 v3.22.3/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -417,6 +456,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= @@ -430,6 +471,10 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ulricqin/gosnmp v0.0.1 h1:LmJ4y0tmnIe+qBeBAX9UjQvRLezso7VnN0bgslYnfzI= github.com/ulricqin/gosnmp v0.0.1/go.mod h1:9OasJbP94MjBGOLNghlVwgG3UN05ATurou1Gw+6rdzU= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -454,6 +499,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -518,8 +566,10 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -589,12 +639,15 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 h1:Js08h5hqB5xyWR789+QqueR6sDE8mk+YvpETZ+F6X9Y= golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -742,10 +795,12 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -757,6 +812,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= diff --git a/logs/README.md b/logs/README.md index 5b4d899a..1caec9a5 100644 --- a/logs/README.md +++ b/logs/README.md @@ -1,30 +1,3 @@ -# logs-agent +# logs -logs-agent collects logs and submits them to datadog's infrastructure. - -## Structure - -`logs` reads the config files, and instantiates what's needed. -Each log line comes from a source (e.g. file, network, docker), and then enters one of the available _pipeline - tailer|listener|container -> decoder -> processor -> sender -> auditor_ - -`Tailer` tails a file and submits data to the processors - -`Listener` listens on local network (TCP, UDP, Unix) and submits data to the processors - -`Container` scans docker logs from stdout/stderr and submits data to the processors - -`Decoder` converts bytes arrays into messages - -`Processor` updates the messages, filtering, redacting or adding metadata, and submits to the forwarder - -`Sender` submits the messages to the intake, and notifies the auditor - -`Auditor` notes that messages were properly submitted, stores offsets for agent restarts - -## Tests - -``` -# Run the unit tests -inv test --targets=./pkg/logs --timeout=10 - -``` +forked from datadog logs-agent diff --git a/logs/client/kafka/content_encoding.go b/logs/client/kafka/content_encoding.go new file mode 100644 index 00000000..9e87fd2c --- /dev/null +++ b/logs/client/kafka/content_encoding.go @@ -0,0 +1,73 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +package kafka + +import ( + "bytes" + "compress/gzip" +) + +// ContentEncoding encodes the payload +type ContentEncoding interface { + name() string + encode(payload []byte) ([]byte, error) +} + +// IdentityContentType encodes the payload using the identity function +var IdentityContentType ContentEncoding = &identityContentType{} + +type identityContentType struct{} + +func (c *identityContentType) name() string { + return "identity" +} + +func (c *identityContentType) encode(payload []byte) ([]byte, error) { + return payload, nil +} + +// GzipContentEncoding encodes the payload using gzip algorithm +type GzipContentEncoding struct { + level int +} + +// NewGzipContentEncoding creates a new Gzip content type +func NewGzipContentEncoding(level int) *GzipContentEncoding { + if level < gzip.NoCompression { + level = gzip.NoCompression + } else if level > gzip.BestCompression { + level = gzip.BestCompression + } + + return &GzipContentEncoding{ + level, + } +} + +func (c *GzipContentEncoding) name() string { + return "gzip" +} + +func (c *GzipContentEncoding) encode(payload []byte) ([]byte, error) { + var compressedPayload bytes.Buffer + gzipWriter, err := gzip.NewWriterLevel(&compressedPayload, c.level) + if err != nil { + return nil, err + } + _, err = gzipWriter.Write(payload) + if err != nil { + return nil, err + } + err = gzipWriter.Flush() + if err != nil { + return nil, err + } + err = gzipWriter.Close() + if err != nil { + return nil, err + } + return compressedPayload.Bytes(), nil +} diff --git a/logs/client/kafka/destination.go b/logs/client/kafka/destination.go new file mode 100644 index 00000000..3ac85c69 --- /dev/null +++ b/logs/client/kafka/destination.go @@ -0,0 +1,188 @@ +package kafka + +import ( + "context" + "errors" + "strings" + "sync" + "time" + + "github.com/Shopify/sarama" + + coreconfig "flashcat.cloud/categraf/config" + logsconfig "flashcat.cloud/categraf/config/logs" + "flashcat.cloud/categraf/logs/client" + "flashcat.cloud/categraf/pkg/backoff" +) + +// ContentType options, +const ( + TextContentType = "text/plain" + JSONContentType = "application/json" +) + +// HTTP errors. +var ( + errClient = errors.New("client error") + errServer = errors.New("server error") +) + +// emptyPayload is an empty payload used to check HTTP connectivity without sending logs. +var emptyPayload []byte + +// Destination sends a payload over HTTP. +type Destination struct { + topic string + brokers []string + + apiKey string + contentType string + contentEncoding ContentEncoding + client sarama.SyncProducer + destinationsContext *client.DestinationsContext + once sync.Once + payloadChan chan []byte + climit chan struct{} // semaphore for limiting concurrent background sends + backoff backoff.Policy + nbErrors int + blockedUntil time.Time + protocol logsconfig.IntakeProtocol + origin logsconfig.IntakeOrigin +} + +// NewDestination returns a new Destination. +// If `maxConcurrentBackgroundSends` > 0, then at most that many background payloads will be sent concurrently, else +// there is no concurrency and the background sending pipeline will block while sending each payload. +// TODO: add support for SOCKS5 +func NewDestination(endpoint logsconfig.Endpoint, contentType string, destinationsContext *client.DestinationsContext, maxConcurrentBackgroundSends int) *Destination { + return newDestination(endpoint, contentType, destinationsContext, time.Second*10, maxConcurrentBackgroundSends) +} + +func newDestination(endpoint logsconfig.Endpoint, contentType string, destinationsContext *client.DestinationsContext, timeout time.Duration, maxConcurrentBackgroundSends int) *Destination { + if maxConcurrentBackgroundSends < 0 { + maxConcurrentBackgroundSends = 0 + } + + policy := backoff.NewPolicy( + endpoint.BackoffFactor, + endpoint.BackoffBase, + endpoint.BackoffMax, + endpoint.RecoveryInterval, + endpoint.RecoveryReset, + ) + brokers := strings.Split(endpoint.Addr, ",") + c, err := sarama.NewSyncProducer(brokers, coreconfig.Config.Logs.Config) + if err != nil { + panic(err) + } + return &Destination{ + topic: endpoint.Topic, + brokers: brokers, + apiKey: endpoint.APIKey, + contentType: contentType, + contentEncoding: buildContentEncoding(endpoint), + client: c, + destinationsContext: destinationsContext, + climit: make(chan struct{}, maxConcurrentBackgroundSends), + backoff: policy, + protocol: endpoint.Protocol, + origin: endpoint.Origin, + } +} + +func errorToTag(err error) string { + if err == nil { + return "none" + } else if _, ok := err.(*client.RetryableError); ok { + return "retryable" + } else { + return "non-retryable" + } +} + +// Send sends a payload over HTTP, +// the error returned can be retryable and it is the responsibility of the callee to retry. +func (d *Destination) Send(payload []byte) error { + if d.blockedUntil.After(time.Now()) { + // log.Printf("%s: sleeping until %v before retrying\n", d.url, d.blockedUntil) + d.waitForBackoff() + } + + err := d.unconditionalSend(payload) + + if _, ok := err.(*client.RetryableError); ok { + d.nbErrors = d.backoff.IncError(d.nbErrors) + } else { + d.nbErrors = d.backoff.DecError(d.nbErrors) + } + + d.blockedUntil = time.Now().Add(d.backoff.GetBackoffDuration(d.nbErrors)) + + return err +} + +func (d *Destination) unconditionalSend(payload []byte) (err error) { + ctx := d.destinationsContext.Context() + + encodedPayload, err := d.contentEncoding.encode(payload) + if err != nil { + return err + } + + err = NewBuilder().WithMessage(d.apiKey, encodedPayload).WithTopic(d.topic).Send(d.client) + if err != nil { + if ctx.Err() == context.Canceled { + return ctx.Err() + } + // most likely a network or a connect error, the callee should retry. + return client.NewRetryableError(err) + } + return nil +} + +// SendAsync sends a payload in background. +func (d *Destination) SendAsync(payload []byte) { + d.once.Do(func() { + payloadChan := make(chan []byte, logsconfig.ChanSize) + d.sendInBackground(payloadChan) + d.payloadChan = payloadChan + }) + d.payloadChan <- payload +} + +// sendInBackground sends all payloads from payloadChan in background. +func (d *Destination) sendInBackground(payloadChan chan []byte) { + ctx := d.destinationsContext.Context() + go func() { + for { + select { + case payload := <-payloadChan: + // if the channel is non-buffered then there is no concurrency and we block on sending each payload + if cap(d.climit) == 0 { + d.unconditionalSend(payload) //nolint:errcheck + break + } + d.climit <- struct{}{} + go func() { + d.unconditionalSend(payload) //nolint:errcheck + <-d.climit + }() + case <-ctx.Done(): + return + } + } + }() +} + +func buildContentEncoding(endpoint logsconfig.Endpoint) ContentEncoding { + if endpoint.UseCompression { + return NewGzipContentEncoding(endpoint.CompressionLevel) + } + return IdentityContentType +} + +func (d *Destination) waitForBackoff() { + ctx, cancel := context.WithDeadline(d.destinationsContext.Context(), d.blockedUntil) + defer cancel() + <-ctx.Done() +} diff --git a/logs/client/kafka/kafka.go b/logs/client/kafka/kafka.go new file mode 100644 index 00000000..07e50622 --- /dev/null +++ b/logs/client/kafka/kafka.go @@ -0,0 +1,52 @@ +package kafka + +import ( + "fmt" + + "github.com/Shopify/sarama" +) + +type MessageBuilder struct { + sarama.ProducerMessage +} + +func NewBuilder() *MessageBuilder { + return &MessageBuilder{} +} + +func (m *MessageBuilder) WithMessage(key string, value []byte) *MessageBuilder { + m.Key = sarama.StringEncoder(key) + m.Value = sarama.ByteEncoder(value) + return m +} + +func (m *MessageBuilder) WithTopic(topic string) *MessageBuilder { + m.Topic = topic + return m +} + +func (s *MessageBuilder) build() (*sarama.ProducerMessage, error) { + switch { + case len(s.Topic) == 0: + return nil, fmt.Errorf("Message (%s) must not be nil", "topic") + case s.Key.Length() == 0: + return nil, fmt.Errorf("Message (%s) must not be nil", "key") + case s.Value.Length() == 0: + return nil, fmt.Errorf("Message (%s) must not be nil", "value") + } + return &s.ProducerMessage, nil +} + +func (m *MessageBuilder) Send(producer sarama.SyncProducer) error { + if producer == nil { + return fmt.Errorf("empty producer") + } + + msg, err := m.build() + if err != nil { + return err + } + + _, _, err = producer.SendMessage(msg) + return err +} diff --git a/logs/pipeline/pipeline.go b/logs/pipeline/pipeline.go index 176a8f3e..eb13399b 100644 --- a/logs/pipeline/pipeline.go +++ b/logs/pipeline/pipeline.go @@ -11,6 +11,7 @@ import ( logsconfig "flashcat.cloud/categraf/config/logs" "flashcat.cloud/categraf/logs/client" "flashcat.cloud/categraf/logs/client/http" + "flashcat.cloud/categraf/logs/client/kafka" "flashcat.cloud/categraf/logs/client/tcp" "flashcat.cloud/categraf/logs/diagnostic" "flashcat.cloud/categraf/logs/message" @@ -27,42 +28,46 @@ type Pipeline struct { // NewPipeline returns a new Pipeline func NewPipeline(outputChan chan *message.Message, processingRules []*logsconfig.ProcessingRule, endpoints *logsconfig.Endpoints, destinationsContext *client.DestinationsContext, diagnosticMessageReceiver diagnostic.MessageReceiver, serverless bool) *Pipeline { - var destinations *client.Destinations - if endpoints.UseHTTP { + var ( + destinations *client.Destinations + strategy sender.Strategy + encoder processor.Encoder + ) + switch endpoints.Type { + case "http": main := http.NewDestination(endpoints.Main, http.JSONContentType, destinationsContext, endpoints.BatchMaxConcurrentSend) additionals := []client.Destination{} for _, endpoint := range endpoints.Additionals { additionals = append(additionals, http.NewDestination(endpoint, http.JSONContentType, destinationsContext, endpoints.BatchMaxConcurrentSend)) } destinations = client.NewDestinations(main, additionals) - } else { + strategy = sender.NewBatchStrategy(sender.ArraySerializer, endpoints.BatchWait, endpoints.BatchMaxConcurrentSend, endpoints.BatchMaxSize, endpoints.BatchMaxContentSize, "logs") + encoder = processor.JSONEncoder + case "kafka": + main := kafka.NewDestination(endpoints.Main, http.JSONContentType, destinationsContext, endpoints.BatchMaxConcurrentSend) + additionals := []client.Destination{} + for _, endpoint := range endpoints.Additionals { + additionals = append(additionals, kafka.NewDestination(endpoint, http.JSONContentType, destinationsContext, endpoints.BatchMaxConcurrentSend)) + } + destinations = client.NewDestinations(main, additionals) + strategy = sender.StreamStrategy + encoder = processor.JSONEncoder + case "tcp": main := tcp.NewDestination(endpoints.Main, endpoints.UseProto, destinationsContext) additionals := []client.Destination{} for _, endpoint := range endpoints.Additionals { additionals = append(additionals, tcp.NewDestination(endpoint, endpoints.UseProto, destinationsContext)) } destinations = client.NewDestinations(main, additionals) + strategy = sender.StreamStrategy + encoder = processor.RawEncoder } senderChan := make(chan *message.Message, logsconfig.ChanSize) - - var strategy sender.Strategy - if endpoints.UseHTTP || serverless { - strategy = sender.NewBatchStrategy(sender.ArraySerializer, endpoints.BatchWait, endpoints.BatchMaxConcurrentSend, endpoints.BatchMaxSize, endpoints.BatchMaxContentSize, "logs") - } else { - strategy = sender.StreamStrategy - } sender := sender.NewSender(senderChan, outputChan, destinations, strategy) - var encoder processor.Encoder - if serverless { - encoder = processor.JSONServerlessEncoder - } else if endpoints.UseHTTP { - encoder = processor.JSONEncoder - } else if endpoints.UseProto { + if endpoints.UseProto { encoder = processor.ProtoEncoder - } else { - encoder = processor.RawEncoder } inputChan := make(chan *message.Message, logsconfig.ChanSize) diff --git a/logs/status/builder.go b/logs/status/builder.go index 9eeca824..f661432e 100644 --- a/logs/status/builder.go +++ b/logs/status/builder.go @@ -46,7 +46,7 @@ func (b *Builder) BuildStatus() Status { StatusMetrics: b.getMetricsStatus(), Warnings: b.getWarnings(), Errors: b.getErrors(), - UseHTTP: b.getUseHTTP(), + Type: b.getType(), } } @@ -57,8 +57,8 @@ func (b *Builder) getIsRunning() bool { return atomic.LoadInt32(b.isRunning) != 0 } -func (b *Builder) getUseHTTP() bool { - return b.endpoints.UseHTTP +func (b *Builder) getType() string { + return b.endpoints.Type } func (b *Builder) getEndpoints() []string { @@ -80,7 +80,8 @@ func (b *Builder) formatEndpoint(endpoint logsconfig.Endpoint, prefix string) st port := endpoint.Port var protocol string - if b.endpoints.UseHTTP { + switch b.endpoints.Type { + case "http": if endpoint.UseSSL { protocol = "HTTPS" if port == 0 { @@ -95,7 +96,13 @@ func (b *Builder) formatEndpoint(endpoint logsconfig.Endpoint, prefix string) st port = 80 // use default port } } - } else { + case "kafka": + if endpoint.UseSSL { + protocol = " SSL Encrypted TCP (to Kafka)" + } else { + protocol = "TCP (to Kafka)" + } + case "tcp": if endpoint.UseSSL { protocol = "SSL encrypted TCP" } else { diff --git a/logs/status/status.go b/logs/status/status.go index 13e0035f..7d4e71c6 100644 --- a/logs/status/status.go +++ b/logs/status/status.go @@ -58,7 +58,7 @@ type Status struct { Integrations []Integration `json:"integrations"` Errors []string `json:"errors"` Warnings []string `json:"warnings"` - UseHTTP bool `json:"use_http"` + Type string `json:"use_http"` } // Init instantiates the builder that builds the status on the fly.