[Golang] winlogbeat二次开发(一)

分析运行逻辑

我们要想进行二次开发首先需要把他相关的函数和运行的逻辑摸清楚才能进行。

入口函数

beats/winlogbeat/beater/winlogbeat.go

func New(b *beat.Beat, _ *common.Config) (beat.Beater, error) {
     
	// Read configuration.
	config := config.DefaultSettings
	err := b.BeatConfig.Unpack(&config)
	if err != nil {
     
		return nil, fmt.Errorf("Error reading configuration file. %v", err)
	}

	// resolve registry file path
	config.RegistryFile = paths.Resolve(paths.Data, config.RegistryFile)
	logp.Info("State will be read from and persisted to %s",
		config.RegistryFile)

	eb := &Winlogbeat{
     
		beat:   b,
		config: config,
		done:   make(chan struct{
     }),
	}

	if err := eb.init(b); err != nil {
        //初始化配置文件 查看取的日志名称是否存在
		return nil, err
	}

	return eb, nil
}

beats/libbeat/cmd/run.go

func genRunCmd(settings instance.Settings, beatCreator beat.Creator) *cobra.Command {
     
	name := settings.Name
	runCmd := cobra.Command{
     
		Use:   "run",
		Short: "Run " + name,
		Run: func(cmd *cobra.Command, args []string) {
     
			err := instance.Run(settings, beatCreator)  // 下一个运行点调用run
			if err != nil {
     
				os.Exit(1)
			}
		},
	}

	// Run subcommand flags, only available to *beat run
	runCmd.Flags().AddGoFlag(flag.CommandLine.Lookup("N"))
	runCmd.Flags().AddGoFlag(flag.CommandLine.Lookup("httpprof"))
	runCmd.Flags().AddGoFlag(flag.CommandLine.Lookup("cpuprofile"))
	runCmd.Flags().AddGoFlag(flag.CommandLine.Lookup("memprofile"))

	if settings.RunFlags != nil {
     
		runCmd.Flags().AddFlagSet(settings.RunFlags)
	}

	return &runCmd
}

beats/libbeat/cmd/instance/beat.go

func Run(settings Settings, bt beat.Creator) error {
     
	err := setUmaskWithSettings(settings)
	if err != nil && err != errNotImplemented {
     
		return errw.Wrap(err, "could not set umask")
	}

	......

		return b.launch(settings, bt)  // 下一个点
	}())
}

beats/libbeat/cmd/instance/beat.go

func (b *Beat) launch(settings Settings, bt beat.Creator) error {
     
	defer logp.Sync()
	......
	return beater.Run(&b.Beat) // 运行入口点
}

beats/winlogbeat/beater/winlogbeat.go 根据采集的日志类型会创建相应的协程。

// Run is used within the beats interface to execute the Winlogbeat workers.
func (eb *Winlogbeat) Run(b *beat.Beat) error {
     
	if err := eb.setup(b); err != nil {
     
		return err
	}

	acker := newEventACKer(eb.checkpoint)
	persistedState := eb.checkpoint.States()

	// Initialize metrics.
	initMetrics("total")

	// setup global event ACK handler
	err := eb.pipeline.SetACKHandler(beat.PipelineACKHandler{
     
		ACKEvents: acker.ACKEvents,
	})
	if err != nil {
     
		return err
	}

	var wg sync.WaitGroup
	for _, log := range eb.eventLogs {
     
		state, _ := persistedState[log.source.Name()]

		// Start a goroutine for each event log.
		wg.Add(1)
		go eb.processEventLog(&wg, log, state, acker)  // 主要采集函数
	}

	wg.Wait()
	defer eb.checkpoint.Shutdown()

	if eb.config.ShutdownTimeout > 0 {
     
		logp.Info("Shutdown will wait max %v for the remaining %v events to publish.",
			eb.config.ShutdownTimeout, acker.Active())
		ctx, cancel := context.WithTimeout(context.Background(), eb.config.ShutdownTimeout)
		defer cancel()
		acker.Wait(ctx)
	}

	return nil
}

beats/winlogbeat/beater/winlogbeat.go

func (eb *Winlogbeat) processEventLog(
	wg *sync.WaitGroup,
	logger *eventLogger,
	state checkpoint.EventLogState,
	acker *eventACKer,
) {
     
	defer wg.Done()
	logger.run(eb.done, eb.pipeline, state, acker)
}

连接获取日志并Publish
winlogbeat/beater/eventlogger.go

func (e *eventLogger) run(
	done <-chan struct{
     },
	pipeline beat.Pipeline,
	state checkpoint.EventLogState,
	acker *eventACKer,
) {
     
	api := e.source

	// Initialize per event log metrics.
	initMetrics(api.Name())

	client, err := e.connect(pipeline)
	if err != nil {
     
		logp.Warn("EventLog[%s] Pipeline error. Failed to connect to publisher pipeline",
			api.Name())
		return
	}

	// close client on function return or when `done` is triggered (unblock client)
	defer client.Close()
	go func() {
     
		<-done
		client.Close()
	}()

	err = api.Open(state)
	if err != nil {
     
		logp.Warn("EventLog[%s] Open() error. No events will be read from "+
			"this source. %v", api.Name(), err)
		return
	}
	defer func() {
     
		logp.Info("EventLog[%s] Stop processing.", api.Name())

		if err := api.Close(); err != nil {
     
			logp.Warn("EventLog[%s] Close() error. %v", api.Name(), err)
			return
		}
	}()

	debugf("EventLog[%s] opened successfully", api.Name())

	for stop := false; !stop; {
     
		select {
     
		case <-done:
			return
		default:
		}

		// Read from the event.
		records, err := api.Read()  //读取事件日志 beats/winlogbeat/eventlog/eventlog.go 
		switch err {
     
		case nil:
		case io.EOF:
			// Graceful stop.
			stop = true
		default:
			logp.Warn("EventLog[%s] Read() error: %v", api.Name(), err)
			return
		}

		debugf("EventLog[%s] Read() returned %d records", api.Name(), len(records))
		if len(records) == 0 {
     
			time.Sleep(time.Second)
			continue
		}

		acker.Add(len(records))
		for _, lr := range records {
     
			client.Publish(lr.ToEvent())  //push数据
		}
	}
}

beats/libbeat/publisher/pipeline/client.go

func (c *client) Publish(e beat.Event) {
     
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.publish(e)
}

func (c *client) publish(e beat.Event) {
     
	var (
		event   = &e
		publish = true
		log     = c.pipeline.monitors.Logger
	)

	c.onNewEvent()

	if !c.isOpen.Load() {
     
		// client is closing down -> report event as dropped and return
		c.onDroppedOnPublish(e)
		return
	}

	if c.processors != nil {
     
		var err error

		event, err = c.processors.Run(event)
		publish = event != nil
		if err != nil {
     
			// TODO: introduce dead-letter queue?

			log.Errorf("Failed to publish event: %v", err)
		}
	}

	if event != nil {
     
		e = *event
	}

	open := c.acker.addEvent(e, publish)
	if !open {
     
		// client is closing down -> report event as dropped and return
		c.onDroppedOnPublish(e)
		return
	}

	if !publish {
     
		c.onFilteredOut(e)
		return
	}

	e = *event
	pubEvent := publisher.Event{
     
		Content: e,
		Flags:   c.eventFlags,
	}

	if c.reportEvents {
     
		c.pipeline.waitCloser.inc()
	}

	var published bool
	if c.canDrop {
     
		published = c.producer.TryPublish(pubEvent)
	} else {
     
		published = c.producer.Publish(pubEvent)
	}

	if published {
     
		c.onPublished()
	} else {
     
		c.onDroppedOnPublish(e)
		if c.reportEvents {
     
			c.pipeline.waitCloser.dec(1)
		}
	}
}

你可能感兴趣的:(golang,go,winlogbeat,winlogbeat)