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

     1  package client
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/go-kit/log"
    10  
    11  	"github.com/grafana/loki/clients/pkg/promtail/api"
    12  )
    13  
    14  // MultiClient is client pushing to one or more loki instances.
    15  type MultiClient struct {
    16  	clients []Client
    17  	entries chan api.Entry
    18  	wg      sync.WaitGroup
    19  
    20  	once sync.Once
    21  }
    22  
    23  // NewMulti creates a new client
    24  func NewMulti(metrics *Metrics, streamLagLabels []string, logger log.Logger, cfgs ...Config) (Client, error) {
    25  	var fake struct{}
    26  
    27  	if len(cfgs) == 0 {
    28  		return nil, errors.New("at least one client config should be provided")
    29  	}
    30  	clientsCheck := make(map[string]struct{})
    31  	clients := make([]Client, 0, len(cfgs))
    32  	for _, cfg := range cfgs {
    33  		client, err := New(metrics, cfg, streamLagLabels, logger)
    34  		if err != nil {
    35  			return nil, err
    36  		}
    37  
    38  		// Don't allow duplicate clients, we have client specific metrics that need at least one unique label value (name).
    39  		if _, ok := clientsCheck[client.Name()]; ok {
    40  			return nil, fmt.Errorf("duplicate client configs are not allowed, found duplicate for URL: %s", cfg.URL)
    41  		}
    42  
    43  		clientsCheck[client.Name()] = fake
    44  		clients = append(clients, client)
    45  	}
    46  	multi := &MultiClient{
    47  		clients: clients,
    48  		entries: make(chan api.Entry),
    49  	}
    50  	multi.start()
    51  	return multi, nil
    52  }
    53  
    54  func (m *MultiClient) start() {
    55  	m.wg.Add(1)
    56  	go func() {
    57  		defer m.wg.Done()
    58  		for e := range m.entries {
    59  			for _, c := range m.clients {
    60  				c.Chan() <- e
    61  			}
    62  		}
    63  	}()
    64  }
    65  
    66  func (m *MultiClient) Chan() chan<- api.Entry {
    67  	return m.entries
    68  }
    69  
    70  // Stop implements Client
    71  func (m *MultiClient) Stop() {
    72  	m.once.Do(func() { close(m.entries) })
    73  	m.wg.Wait()
    74  	for _, c := range m.clients {
    75  		c.Stop()
    76  	}
    77  }
    78  
    79  // StopNow implements Client
    80  func (m *MultiClient) StopNow() {
    81  	for _, c := range m.clients {
    82  		c.StopNow()
    83  	}
    84  }
    85  
    86  func (m *MultiClient) Name() string {
    87  	var sb strings.Builder
    88  	sb.WriteString("multi:")
    89  	for i, c := range m.clients {
    90  		sb.WriteString(c.Name())
    91  		if i != len(m.clients)-1 {
    92  			sb.WriteString(",")
    93  		}
    94  	}
    95  	return sb.String()
    96  }