145 lines
3.6 KiB
Go
145 lines
3.6 KiB
Go
// Licensed to Elasticsearch B.V. under one or more contributor
|
|
// license agreements. See the NOTICE file distributed with
|
|
// this work for additional information regarding copyright
|
|
// ownership. Elasticsearch B.V. licenses this file to you under
|
|
// the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package redis
|
|
|
|
import (
|
|
"time"
|
|
|
|
rd "github.com/garyburd/redigo/redis"
|
|
|
|
"github.com/elastic/beats/filebeat/channel"
|
|
"github.com/elastic/beats/filebeat/harvester"
|
|
"github.com/elastic/beats/filebeat/input"
|
|
"github.com/elastic/beats/filebeat/input/file"
|
|
"github.com/elastic/beats/libbeat/common"
|
|
"github.com/elastic/beats/libbeat/common/cfgwarn"
|
|
"github.com/elastic/beats/libbeat/logp"
|
|
)
|
|
|
|
func init() {
|
|
err := input.Register("redis", NewInput)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// Input is a input for redis
|
|
type Input struct {
|
|
started bool
|
|
outlet channel.Outleter
|
|
config config
|
|
cfg *common.Config
|
|
registry *harvester.Registry
|
|
}
|
|
|
|
// NewInput creates a new redis input
|
|
func NewInput(cfg *common.Config, outletFactory channel.Connector, context input.Context) (input.Input, error) {
|
|
cfgwarn.Experimental("Redis slowlog input is enabled.")
|
|
|
|
config := defaultConfig
|
|
|
|
err := cfg.Unpack(&config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
outlet, err := outletFactory(cfg, context.DynamicFields)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p := &Input{
|
|
started: false,
|
|
outlet: outlet,
|
|
config: config,
|
|
cfg: cfg,
|
|
registry: harvester.NewRegistry(),
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
// LoadStates loads the states
|
|
func (p *Input) LoadStates(states []file.State) error {
|
|
return nil
|
|
}
|
|
|
|
// Run runs the input
|
|
func (p *Input) Run() {
|
|
logp.Debug("redis", "Run redis input with hosts: %+v", p.config.Hosts)
|
|
|
|
if len(p.config.Hosts) == 0 {
|
|
logp.Err("No redis hosts configured")
|
|
return
|
|
}
|
|
|
|
forwarder := harvester.NewForwarder(p.outlet)
|
|
for _, host := range p.config.Hosts {
|
|
pool := CreatePool(host, p.config.Password, p.config.Network,
|
|
p.config.MaxConn, p.config.IdleTimeout, p.config.IdleTimeout)
|
|
|
|
h, err := NewHarvester(pool.Get())
|
|
if err != nil {
|
|
logp.Err("Failed to create harvester: %v", err)
|
|
continue
|
|
}
|
|
h.forwarder = forwarder
|
|
|
|
if err := p.registry.Start(h); err != nil {
|
|
logp.Err("Harvester start failed: %s", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stop stops the input and all its harvesters
|
|
func (p *Input) Stop() {
|
|
p.registry.Stop()
|
|
p.outlet.Close()
|
|
}
|
|
|
|
// Wait waits for the input to be completed. Not implemented.
|
|
func (p *Input) Wait() {}
|
|
|
|
// CreatePool creates a redis connection pool
|
|
// NOTE: This code is copied from the redis pool handling in metricbeat
|
|
func CreatePool(
|
|
host, password, network string,
|
|
maxConn int,
|
|
idleTimeout, connTimeout time.Duration,
|
|
) *rd.Pool {
|
|
return &rd.Pool{
|
|
MaxIdle: maxConn,
|
|
IdleTimeout: idleTimeout,
|
|
Dial: func() (rd.Conn, error) {
|
|
c, err := rd.Dial(network, host,
|
|
rd.DialConnectTimeout(connTimeout),
|
|
rd.DialReadTimeout(connTimeout),
|
|
rd.DialWriteTimeout(connTimeout))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if password != "" {
|
|
if _, err := c.Do("AUTH", password); err != nil {
|
|
c.Close()
|
|
return nil, err
|
|
}
|
|
}
|
|
return c, err
|
|
},
|
|
}
|
|
}
|