func (s *Scanner) Run(ctx context.Context, events chan<- *model.Event) error {
	s.logger.Info("Running, config=", s.cfg)
	if err := s.init(ctx, events); err != nil {
		return err
	}
	s.runSyncWorkers(ctx, events)
	s.runPersistState(ctx)
	return nil
}
Run starts internal go routines which will scan folders and send the obtained data asynchronously
package scanner
import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/logrange/logrange/pkg/scanner/model"
	"github.com/logrange/logrange/pkg/scanner/parser"
	"github.com/logrange/logrange/pkg/storage"
	"github.com/logrange/logrange/pkg/utils"
	"github.com/pkg/errors"
	"os"
	"regexp"
	"sync"
	"sync/atomic"
	"time"
	"github.com/jrivets/log4g"
	"github.com/mohae/deepcopy"
)
type (
	desc struct {
		Id           string
		File         string
		Offset       int64
		LastSeenSize int64
	}
	descs map[string]*desc
	workers map[string]*worker
	Scanner struct {
		cfg *Config
		schemas  []*schema
		excludes []*regexp.Regexp
		descs       atomic.Value
		workers     atomic.Value
		workerIdCnt int32
		waitWg  sync.WaitGroup
		storage storage.Storage
		logger  log4g.Logger
	}
	Stats struct {
		Workers []*stats
	}
)
const (
	storageKeyName = "scanner.json"
)
func NewScanner(cfg *Config, storage storage.Storage) (*Scanner, error) {
	if err := cfg.Check(); err != nil {
		return nil, fmt.Errorf("invalid config; %v", err)
	}
	s := new(Scanner)
	s.cfg = deepcopy.Copy(cfg).(*Config)
	s.workers.Store(make(workers))
	s.descs.Store(make(descs))
	s.schemas = make([]*schema, 0, len(cfg.Schemas))
	for _, sh := range s.cfg.Schemas {
		s.schemas = append(s.schemas, newSchema(sh))
	}
	s.excludes = make([]*regexp.Regexp, 0, len(cfg.ExcludeMatchers))
	for _, ex := range s.cfg.ExcludeMatchers {
		re, _ := regexp.Compile(ex)
		s.excludes = append(s.excludes, re)
	}
	s.storage = storage
	s.logger = log4g.GetLogger("scanner")
	return s, nil
}