github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/promtail/targets/docker/targetmanager.go (about)

     1  package docker
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/go-kit/log"
     8  	"github.com/go-kit/log/level"
     9  	"github.com/prometheus/common/model"
    10  	"github.com/prometheus/prometheus/discovery"
    11  
    12  	"github.com/grafana/loki/clients/pkg/logentry/stages"
    13  	"github.com/grafana/loki/clients/pkg/promtail/api"
    14  	"github.com/grafana/loki/clients/pkg/promtail/positions"
    15  	"github.com/grafana/loki/clients/pkg/promtail/scrapeconfig"
    16  	"github.com/grafana/loki/clients/pkg/promtail/targets/target"
    17  
    18  	"github.com/grafana/loki/pkg/util"
    19  )
    20  
    21  const (
    22  	// See github.com/prometheus/prometheus/discovery/moby
    23  	dockerLabel                = model.MetaLabelPrefix + "docker_"
    24  	dockerLabelContainerPrefix = dockerLabel + "container_"
    25  	dockerLabelContainerID     = dockerLabelContainerPrefix + "id"
    26  	dockerLabelLogStream       = dockerLabelContainerPrefix + "log_stream"
    27  )
    28  
    29  type TargetManager struct {
    30  	metrics    *Metrics
    31  	logger     log.Logger
    32  	positions  positions.Positions
    33  	cancel     context.CancelFunc
    34  	done       chan struct{}
    35  	manager    *discovery.Manager
    36  	pushClient api.EntryHandler
    37  	groups     map[string]*targetGroup
    38  }
    39  
    40  func NewTargetManager(
    41  	metrics *Metrics,
    42  	logger log.Logger,
    43  	positions positions.Positions,
    44  	pushClient api.EntryHandler,
    45  	scrapeConfigs []scrapeconfig.Config,
    46  ) (*TargetManager, error) {
    47  	ctx, cancel := context.WithCancel(context.Background())
    48  	tm := &TargetManager{
    49  		metrics:    metrics,
    50  		logger:     logger,
    51  		cancel:     cancel,
    52  		done:       make(chan struct{}),
    53  		positions:  positions,
    54  		manager:    discovery.NewManager(ctx, log.With(logger, "component", "docker_discovery")),
    55  		pushClient: pushClient,
    56  		groups:     make(map[string]*targetGroup),
    57  	}
    58  	configs := map[string]discovery.Configs{}
    59  	for _, cfg := range scrapeConfigs {
    60  		if cfg.DockerSDConfigs != nil {
    61  			pipeline, err := stages.NewPipeline(
    62  				log.With(logger, "component", "docker_pipeline"),
    63  				cfg.PipelineStages,
    64  				&cfg.JobName,
    65  				metrics.reg,
    66  			)
    67  			if err != nil {
    68  				return nil, err
    69  			}
    70  
    71  			for _, sdConfig := range cfg.DockerSDConfigs {
    72  				syncerKey := fmt.Sprintf("%s/%s:%d", cfg.JobName, sdConfig.Host, sdConfig.Port)
    73  				_, ok := tm.groups[syncerKey]
    74  				if !ok {
    75  					tm.groups[syncerKey] = &targetGroup{
    76  						metrics:       metrics,
    77  						logger:        logger,
    78  						positions:     positions,
    79  						targets:       make(map[string]*Target),
    80  						entryHandler:  pipeline.Wrap(pushClient),
    81  						defaultLabels: model.LabelSet{},
    82  						relabelConfig: cfg.RelabelConfigs,
    83  						host:          sdConfig.Host,
    84  					}
    85  				}
    86  				configs[syncerKey] = append(configs[syncerKey], sdConfig)
    87  			}
    88  		} else {
    89  			level.Debug(tm.logger).Log("msg", "Docker service discovery configs are empty")
    90  		}
    91  	}
    92  
    93  	go tm.run(ctx)
    94  	go util.LogError("running target manager", tm.manager.Run)
    95  
    96  	return tm, tm.manager.ApplyConfig(configs)
    97  }
    98  
    99  // run listens on the service discovery and adds new targets.
   100  func (tm *TargetManager) run(ctx context.Context) {
   101  	defer close(tm.done)
   102  	for {
   103  		select {
   104  		case targetGroups := <-tm.manager.SyncCh():
   105  			for jobName, groups := range targetGroups {
   106  				tg, ok := tm.groups[jobName]
   107  				if !ok {
   108  					level.Debug(tm.logger).Log("msg", "unknown target for job", "job", jobName)
   109  					continue
   110  				}
   111  				tg.sync(groups)
   112  			}
   113  		case <-ctx.Done():
   114  			return
   115  		}
   116  	}
   117  }
   118  
   119  // Ready returns true if at least one Docker target is active.
   120  func (tm *TargetManager) Ready() bool {
   121  	for _, s := range tm.groups {
   122  		if s.Ready() {
   123  			return true
   124  		}
   125  	}
   126  	return false
   127  }
   128  
   129  func (tm *TargetManager) Stop() {
   130  	tm.cancel()
   131  	<-tm.done
   132  	for _, s := range tm.groups {
   133  		s.Stop()
   134  	}
   135  }
   136  
   137  func (tm *TargetManager) ActiveTargets() map[string][]target.Target {
   138  	result := make(map[string][]target.Target, len(tm.groups))
   139  	for k, s := range tm.groups {
   140  		result[k] = s.ActiveTargets()
   141  	}
   142  	return result
   143  }
   144  
   145  func (tm *TargetManager) AllTargets() map[string][]target.Target {
   146  	result := make(map[string][]target.Target, len(tm.groups))
   147  	for k, s := range tm.groups {
   148  		result[k] = s.AllTargets()
   149  	}
   150  	return result
   151  }