github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/metric/emit.go (about)

     1  package metric
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/lager"
     9  
    10  	"github.com/pf-qiu/concourse/v6/atc/db"
    11  	flags "github.com/jessevdk/go-flags"
    12  )
    13  
    14  type Event struct {
    15  	Name       string
    16  	Value      float64
    17  	Attributes map[string]string
    18  	Host       string
    19  	Time       time.Time
    20  }
    21  
    22  //go:generate counterfeiter . Emitter
    23  type Emitter interface {
    24  	Emit(lager.Logger, Event)
    25  }
    26  
    27  //go:generate counterfeiter . EmitterFactory
    28  type EmitterFactory interface {
    29  	Description() string
    30  	IsConfigured() bool
    31  	NewEmitter() (Emitter, error)
    32  }
    33  
    34  type Monitor struct {
    35  	emitter          Emitter
    36  	eventHost        string
    37  	eventAttributes  map[string]string
    38  	emissions        chan eventEmission
    39  	emitterFactories []EmitterFactory
    40  
    41  	Databases       []db.Conn
    42  	DatabaseQueries Counter
    43  
    44  	ContainersCreated Counter
    45  	VolumesCreated    Counter
    46  
    47  	FailedContainers Counter
    48  	FailedVolumes    Counter
    49  
    50  	ContainersDeleted Counter
    51  	VolumesDeleted    Counter
    52  	ChecksDeleted     Counter
    53  
    54  	JobsScheduled  Counter
    55  	JobsScheduling Gauge
    56  
    57  	BuildsStarted Counter
    58  	BuildsRunning Gauge
    59  
    60  	TasksWaiting map[TasksWaitingLabels]*Gauge
    61  
    62  	ChecksFinishedWithError   Counter
    63  	ChecksFinishedWithSuccess Counter
    64  	ChecksStarted             Counter
    65  	ChecksEnqueued            Counter
    66  
    67  	ConcurrentRequests         map[string]*Gauge
    68  	ConcurrentRequestsLimitHit map[string]*Counter
    69  
    70  	VolumesStreamed Counter
    71  }
    72  
    73  var Metrics = NewMonitor()
    74  
    75  func NewMonitor() *Monitor {
    76  	return &Monitor{
    77  		TasksWaiting:               map[TasksWaitingLabels]*Gauge{},
    78  		ConcurrentRequests:         map[string]*Gauge{},
    79  		ConcurrentRequestsLimitHit: map[string]*Counter{},
    80  	}
    81  }
    82  
    83  func (m *Monitor) RegisterEmitter(factory EmitterFactory) {
    84  	m.emitterFactories = append(m.emitterFactories, factory)
    85  }
    86  
    87  func (m *Monitor) WireEmitters(group *flags.Group) {
    88  	for _, factory := range m.emitterFactories {
    89  		_, err := group.AddGroup(fmt.Sprintf("Metric Emitter (%s)", factory.Description()), "", factory)
    90  		if err != nil {
    91  			panic(err)
    92  		}
    93  	}
    94  }
    95  
    96  type eventEmission struct {
    97  	event  Event
    98  	logger lager.Logger
    99  }
   100  
   101  func (m *Monitor) Initialize(logger lager.Logger, host string, attributes map[string]string, bufferSize uint32) error {
   102  	logger.Debug("metric-initialize", lager.Data{
   103  		"host":        host,
   104  		"attributes":  attributes,
   105  		"buffer-size": bufferSize,
   106  	})
   107  
   108  	var (
   109  		emitterDescriptions []string
   110  		err                 error
   111  	)
   112  
   113  	for _, factory := range m.emitterFactories {
   114  		if factory.IsConfigured() {
   115  			emitterDescriptions = append(emitterDescriptions, factory.Description())
   116  		}
   117  	}
   118  	if len(emitterDescriptions) > 1 {
   119  		return fmt.Errorf("Multiple emitters configured: %s", strings.Join(emitterDescriptions, ", "))
   120  	}
   121  
   122  	var emitter Emitter
   123  
   124  	for _, factory := range m.emitterFactories {
   125  		if factory.IsConfigured() {
   126  			emitter, err = factory.NewEmitter()
   127  			if err != nil {
   128  				return err
   129  			}
   130  		}
   131  	}
   132  
   133  	if emitter == nil {
   134  		return nil
   135  	}
   136  
   137  	m.emitter = emitter
   138  	m.eventHost = host
   139  	m.eventAttributes = attributes
   140  	m.emissions = make(chan eventEmission, int(bufferSize))
   141  
   142  	go m.emitLoop()
   143  
   144  	return nil
   145  }
   146  
   147  func (m *Monitor) emit(logger lager.Logger, event Event) {
   148  	if m.emitter == nil {
   149  		return
   150  	}
   151  
   152  	event.Host = m.eventHost
   153  	event.Time = time.Now()
   154  
   155  	mergedAttributes := map[string]string{}
   156  	for k, v := range m.eventAttributes {
   157  		mergedAttributes[k] = v
   158  	}
   159  
   160  	if event.Attributes != nil {
   161  		for k, v := range event.Attributes {
   162  			mergedAttributes[k] = v
   163  		}
   164  	}
   165  
   166  	event.Attributes = mergedAttributes
   167  
   168  	select {
   169  	case m.emissions <- eventEmission{logger: logger, event: event}:
   170  	default:
   171  		logger.Error("queue-full", nil)
   172  	}
   173  }
   174  
   175  func (m *Monitor) emitLoop() {
   176  	for emission := range m.emissions {
   177  		m.emitter.Emit(emission.logger.Session("emit"), emission.event)
   178  	}
   179  }