youtubebeat/vendor/github.com/elastic/beats/filebeat/fileset/factory.go

183 lines
5.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 fileset
import (
"github.com/gofrs/uuid"
"github.com/elastic/beats/filebeat/channel"
input "github.com/elastic/beats/filebeat/prospector"
"github.com/elastic/beats/filebeat/registrar"
"github.com/elastic/beats/libbeat/beat"
"github.com/elastic/beats/libbeat/cfgfile"
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/logp"
"github.com/elastic/beats/libbeat/monitoring"
"github.com/elastic/beats/libbeat/outputs/elasticsearch"
"github.com/mitchellh/hashstructure"
)
var (
moduleList = monitoring.NewUniqueList()
)
func init() {
monitoring.NewFunc(monitoring.GetNamespace("state").GetRegistry(), "module", moduleList.Report, monitoring.Report)
}
// Factory for modules
type Factory struct {
outlet channel.Factory
registrar *registrar.Registrar
beatVersion string
pipelineLoaderFactory PipelineLoaderFactory
overwritePipelines bool
pipelineCallbackID uuid.UUID
beatDone chan struct{}
}
// Wrap an array of inputs and implements cfgfile.Runner interface
type inputsRunner struct {
id uint64
moduleRegistry *ModuleRegistry
inputs []*input.Runner
pipelineLoaderFactory PipelineLoaderFactory
pipelineCallbackID uuid.UUID
overwritePipelines bool
}
// NewFactory instantiates a new Factory
func NewFactory(outlet channel.Factory, registrar *registrar.Registrar, beatVersion string,
pipelineLoaderFactory PipelineLoaderFactory, overwritePipelines bool, beatDone chan struct{}) *Factory {
return &Factory{
outlet: outlet,
registrar: registrar,
beatVersion: beatVersion,
beatDone: beatDone,
pipelineLoaderFactory: pipelineLoaderFactory,
pipelineCallbackID: uuid.Nil,
overwritePipelines: overwritePipelines,
}
}
// Create creates a module based on a config
func (f *Factory) Create(p beat.Pipeline, c *common.Config, meta *common.MapStrPointer) (cfgfile.Runner, error) {
// Start a registry of one module:
m, err := NewModuleRegistry([]*common.Config{c}, f.beatVersion, false)
if err != nil {
return nil, err
}
pConfigs, err := m.GetInputConfigs()
if err != nil {
return nil, err
}
// Hash module ID
var h map[string]interface{}
c.Unpack(&h)
id, err := hashstructure.Hash(h, nil)
if err != nil {
return nil, err
}
inputs := make([]*input.Runner, len(pConfigs))
connector := channel.ConnectTo(p, f.outlet)
for i, pConfig := range pConfigs {
inputs[i], err = input.New(pConfig, connector, f.beatDone, f.registrar.GetStates(), meta)
if err != nil {
logp.Err("Error creating input: %s", err)
return nil, err
}
}
return &inputsRunner{
id: id,
moduleRegistry: m,
inputs: inputs,
pipelineLoaderFactory: f.pipelineLoaderFactory,
pipelineCallbackID: f.pipelineCallbackID,
overwritePipelines: f.overwritePipelines,
}, nil
}
// CheckConfig checks if a config is valid or not
func (f *Factory) CheckConfig(config *common.Config) error {
// TODO: add code here once we know that spinning up a filebeat input to check for errors doesn't cause memory leaks.
return nil
}
func (p *inputsRunner) Start() {
// Load pipelines
if p.pipelineLoaderFactory != nil {
// Attempt to load pipelines instantly when starting or after reload.
// Thus, if ES was not available previously, it could be loaded this time.
// If the function below fails, it means that ES is not available
// at the moment, so the pipeline loader cannot be created.
// Registering a callback regardless of the availability of ES
// makes it possible to try to load pipeline when ES becomes reachable.
pipelineLoader, err := p.pipelineLoaderFactory()
if err != nil {
logp.Err("Error loading pipeline: %s", err)
} else {
err := p.moduleRegistry.LoadPipelines(pipelineLoader, p.overwritePipelines)
if err != nil {
// Log error and continue
logp.Err("Error loading pipeline: %s", err)
}
}
// Register callback to try to load pipelines when connecting to ES.
callback := func(esClient *elasticsearch.Client) error {
return p.moduleRegistry.LoadPipelines(esClient, p.overwritePipelines)
}
p.pipelineCallbackID, err = elasticsearch.RegisterConnectCallback(callback)
if err != nil {
logp.Err("Error registering connect callback for Elasticsearch to load pipelines: %v", err)
}
}
for _, input := range p.inputs {
input.Start()
}
// Loop through and add modules, only 1 normally
for m := range p.moduleRegistry.registry {
moduleList.Add(m)
}
}
func (p *inputsRunner) Stop() {
if p.pipelineCallbackID != uuid.Nil {
elasticsearch.DeregisterConnectCallback(p.pipelineCallbackID)
}
for _, input := range p.inputs {
input.Stop()
}
// Loop through and remove modules, only 1 normally
for m := range p.moduleRegistry.registry {
moduleList.Remove(m)
}
}
func (p *inputsRunner) String() string {
return p.moduleRegistry.InfoString()
}