func NewServersetDiscovery(conf *ServersetSDConfig, logger log.Logger) (*Discovery, error) {
	return NewDiscovery(conf.Servers, time.Duration(conf.Timeout), conf.Paths, logger, parseServersetMember)
}

func NewServersetDiscovery ( conf * ServersetSDConfig , logger log . Logger ) ( * Discovery , error ) { return NewDiscovery ( conf . Servers , time . Duration ( conf . Timeout ) , conf . Paths , logger , parseServersetMember ) }

// NewServersetDiscovery returns a new Discovery for the given serverset config.

NewServersetDiscovery returns a new Discovery for the given serverset config .


func NewDiscovery(
	srvs []string,
	timeout time.Duration,
	paths []string,
	logger log.Logger,
	pf func(data []byte, path string) (model.LabelSet, error),
) (*Discovery, error) {
	if logger == nil {
		logger = log.NewNopLogger()
	}

	conn, _, err := zk.Connect(
		srvs, timeout,
		func(c *zk.Conn) {
			c.SetLogger(treecache.NewZookeeperLogger(logger))
		})
	if err != nil {
		return nil, err
	}
	updates := make(chan treecache.ZookeeperTreeCacheEvent)
	sd := &Discovery{
		conn:    conn,
		updates: updates,
		sources: map[string]*targetgroup.Group{},
		parse:   pf,
		logger:  logger,
	}
	for _, path := range paths {
		sd.treeCaches = append(sd.treeCaches, treecache.NewZookeeperTreeCache(conn, path, updates, logger))
	}
	return sd, nil
}

func NewDiscovery ( srvs [ ] string , timeout time . Duration , paths [ ] string , logger log . Logger , pf func ( data [ ] byte , path string ) ( model . LabelSet , error ) , ) ( * Discovery , error ) { if logger == nil { logger = log . NewNopLogger ( ) } conn , _ , err := zk . Connect ( srvs , timeout , func ( c * zk . Conn ) { c . SetLogger ( treecache . NewZookeeperLogger ( logger ) ) } ) if err != nil { return nil , err } updates := make ( chan treecache . ZookeeperTreeCacheEvent ) sd := & Discovery { conn : conn , updates : updates , sources : map [ string ] * targetgroup . Group { } , parse : pf , logger : logger , } for _ , path := range paths { sd . treeCaches = append ( sd . treeCaches , treecache . NewZookeeperTreeCache ( conn , path , updates , logger ) ) } return sd , nil }

// NewDiscovery returns a new discovery along Zookeeper parses with
// the given parse function.

NewDiscovery returns a new discovery along Zookeeper parses with the given parse function .


func FuzzParseMetricSelector(in []byte) int {
	_, err := ParseMetricSelector(string(in))
	if err == nil {
		return fuzzInteresting
	}

	return fuzzMeh
}

func FuzzParseMetricSelector ( in [ ] byte ) int { _ , err := ParseMetricSelector ( string ( in ) ) if err == nil { return fuzzInteresting } return fuzzMeh }


func FuzzParseExpr(in []byte) int {
	_, err := ParseExpr(string(in))
	if err == nil {
		return fuzzInteresting
	}

	return fuzzMeh
}

func FuzzParseExpr ( in [ ] byte ) int { _ , err := ParseExpr ( string ( in ) ) if err == nil { return fuzzInteresting } return fuzzMeh }


func FuzzParseStmts(in []byte) int {
	_, err := ParseStmts(string(in))
	if err == nil {
		return fuzzInteresting
	}

	return fuzzMeh
}

func FuzzParseStmts ( in [ ] byte ) int { _ , err := ParseStmts ( string ( in ) ) if err == nil { return fuzzInteresting } return fuzzMeh }


func NewManager(logger log.Logger, app Appendable) *Manager {
	if logger == nil {
		logger = log.NewNopLogger()
	}
	return &Manager{
		append:        app,
		logger:        logger,
		scrapeConfigs: make(map[string]*config.ScrapeConfig),
		scrapePools:   make(map[string]*scrapePool),
		graceShut:     make(chan struct{}),
		triggerReload: make(chan struct{}, 1),
	}
}

func NewManager ( logger log . Logger , app Appendable ) * Manager { if logger == nil { logger = log . NewNopLogger ( ) } return & Manager { append : app , logger : logger , scrapeConfigs : make ( map [ string ] * config . ScrapeConfig ) , scrapePools : make ( map [ string ] * scrapePool ) , graceShut : make ( chan struct { } ) , triggerReload : make ( chan struct { } , 1 ) , } }

// NewManager is the Manager constructor


func (m *Manager) Run(tsets <-chan map[string][]*targetgroup.Group) error {
	go m.reloader()
	for {
		select {
		case ts := <-tsets:
			m.updateTsets(ts)

			select {
			case m.triggerReload <- struct{}{}:
			default:
			}

		case <-m.graceShut:
			return nil
		}
	}
}

func ( m * Manager ) Run ( tsets <- chan map [ string ] [ ] * targetgroup . Group ) error { go m . reloader ( ) for { select { case ts := <- tsets : m . updateTsets ( ts ) select { case m . triggerReload <- struct { } { } : default : } case <- m . graceShut : return nil } } }

// Run receives and saves target set updates and triggers the scraping loops reloading.
// Reloading happens in the background so that it doesn't block receiving targets updates.

Run receives and saves target set updates and triggers the scraping loops reloading . Reloading happens in the background so that it doesn t block receiving targets updates .


func (m *Manager) setJitterSeed(labels labels.Labels) error {
	h := fnv.New64a()
	hostname, err := getFqdn()
	if err != nil {
		return err
	}
	if _, err := fmt.Fprintf(h, "%s%s", hostname, labels.String()); err != nil {
		return err
	}
	m.jitterSeed = h.Sum64()
	return nil
}

func ( m * Manager ) setJitterSeed ( labels labels . Labels ) error { h := fnv . New64a ( ) hostname , err := getFqdn ( ) if err != nil { return err } if _ , err := fmt . Fprintf ( h , " " , hostname , labels . String ( ) ) ; err != nil { return err } m . jitterSeed = h . Sum64 ( ) return nil }

// setJitterSeed calculates a global jitterSeed per server relying on extra label set.

setJitterSeed calculates a global jitterSeed per server relying on extra label set .


func (m *Manager) Stop() {
	m.mtxScrape.Lock()
	defer m.mtxScrape.Unlock()

	for _, sp := range m.scrapePools {
		sp.stop()
	}
	close(m.graceShut)
}

func ( m * Manager ) Stop ( ) { m . mtxScrape . Lock ( ) defer m . mtxScrape . Unlock ( ) for _ , sp := range m . scrapePools { sp . stop ( ) } close ( m . graceShut ) }

// Stop cancels all running scrape pools and blocks until all have exited.

Stop cancels all running scrape pools and blocks until all have exited .


func (m *Manager) ApplyConfig(cfg *config.Config) error {
	m.mtxScrape.Lock()
	defer m.mtxScrape.Unlock()

	c := make(map[string]*config.ScrapeConfig)
	for _, scfg := range cfg.ScrapeConfigs {
		c[scfg.JobName] = scfg
	}
	m.scrapeConfigs = c

	if err := m.setJitterSeed(cfg.GlobalConfig.ExternalLabels); err != nil {
		return err
	}

	// Cleanup and reload pool if the configuration has changed.
	var failed bool
	for name, sp := range m.scrapePools {
		if cfg, ok := m.scrapeConfigs[name]; !ok {
			sp.stop()
			delete(m.scrapePools, name)
		} else if !reflect.DeepEqual(sp.config, cfg) {
			err := sp.reload(cfg)
			if err != nil {
				level.Error(m.logger).Log("msg", "error reloading scrape pool", "err", err, "scrape_pool", name)
				failed = true
			}
		}
	}

	if failed {
		return errors.New("failed to apply the new configuration")
	}
	return nil
}

// ApplyConfig resets the manager's target providers and job configurations as defined by the new cfg.

ApplyConfig resets the manager s target providers and job configurations as defined by the new cfg .


func (m *Manager) TargetsAll() map[string][]*Target {
	m.mtxScrape.Lock()
	defer m.mtxScrape.Unlock()

	targets := make(map[string][]*Target, len(m.scrapePools))
	for tset, sp := range m.scrapePools {
		targets[tset] = append(sp.ActiveTargets(), sp.DroppedTargets()...)

	}
	return targets
}

func ( m * Manager ) TargetsAll ( ) map [ string ] [ ] * Target { m . mtxScrape . Lock ( ) defer m . mtxScrape . Unlock ( ) targets := make ( map [ string ] [ ] * Target , len ( m . scrapePools ) ) for tset , sp := range m . scrapePools { targets [ tset ] = append ( sp . ActiveTargets ( ) , sp . DroppedTargets ( ) ... ) } return targets }

// TargetsAll returns active and dropped targets grouped by job_name.

TargetsAll returns active and dropped targets grouped by job_name .


func (m *Manager) TargetsActive() map[string][]*Target {
	m.mtxScrape.Lock()
	defer m.mtxScrape.Unlock()

	targets := make(map[string][]*Target, len(m.scrapePools))
	for tset, sp := range m.scrapePools {
		targets[tset] = sp.ActiveTargets()
	}
	return targets
}

func ( m * Manager ) TargetsActive ( ) map [ string ] [ ] * Target { m . mtxScrape . Lock ( ) defer m . mtxScrape . Unlock ( ) targets := make ( map [ string ] [ ] * Target , len ( m . scrapePools ) ) for tset , sp := range m . scrapePools { targets [ tset ] = sp . ActiveTargets ( ) } return targets }

// TargetsActive returns the active targets currently being scraped.

TargetsActive returns the active targets currently being scraped .


func (m *Manager) TargetsDropped() map[string][]*Target {
	m.mtxScrape.Lock()
	defer m.mtxScrape.Unlock()

	targets := make(map[string][]*Target, len(m.scrapePools))
	for tset, sp := range m.scrapePools {
		targets[tset] = sp.DroppedTargets()
	}
	return targets
}

func ( m * Manager ) TargetsDropped ( ) map [ string ] [ ] * Target { m . mtxScrape . Lock ( ) defer m . mtxScrape . Unlock ( ) targets := make ( map [ string ] [ ] * Target , len ( m . scrapePools ) ) for tset , sp := range m . scrapePools { targets [ tset ] = sp . DroppedTargets ( ) } return targets }

// TargetsDropped returns the dropped targets during relabelling.

TargetsDropped returns the dropped targets during relabelling .


func getFqdn() (string, error) {
	hostname, err := os.Hostname()
	if err != nil {
		return "", err
	}

	ips, err := net.LookupIP(hostname)
	if err != nil {
		// Return the system hostname if we can't look up the IP address.
		return hostname, nil
	}

	lookup := func(ipStr encoding.TextMarshaler) (string, error) {
		ip, err := ipStr.MarshalText()
		if err != nil {
			return "", err
		}
		hosts, err := net.LookupAddr(string(ip))
		if err != nil || len(hosts) == 0 {
			return "", err
		}
		return hosts[0], nil
	}

	for _, addr := range ips {
		if ip := addr.To4(); ip != nil {
			if fqdn, err := lookup(ip); err == nil {
				return fqdn, nil
			}

		}

		if ip := addr.To16(); ip != nil {
			if fqdn, err := lookup(ip); err == nil {
				return fqdn, nil
			}

		}
	}
	return hostname, nil
}

// getFqdn returns a FQDN if it's possible, otherwise falls back to hostname.

getFqdn returns a FQDN if it s possible otherwise falls back to hostname .


func tagsFromMetric(m model.Metric) map[string]TagValue {
	tags := make(map[string]TagValue, len(m)-1)
	for l, v := range m {
		if l == model.MetricNameLabel {
			continue
		}
		tags[string(l)] = TagValue(v)
	}
	return tags
}

func tagsFromMetric ( m model . Metric ) map [ string ] TagValue { tags := make ( map [ string ] TagValue , len ( m ) - 1 ) for l , v := range m { if l == model . MetricNameLabel { continue } tags [ string ( l ) ] = TagValue ( v ) } return tags }

// tagsFromMetric translates Prometheus metric into OpenTSDB tags.

tagsFromMetric translates Prometheus metric into OpenTSDB tags .


func (c *Client) Write(samples model.Samples) error {
	reqs := make([]StoreSamplesRequest, 0, len(samples))
	for _, s := range samples {
		v := float64(s.Value)
		if math.IsNaN(v) || math.IsInf(v, 0) {
			level.Debug(c.logger).Log("msg", "cannot send value to OpenTSDB, skipping sample", "value", v, "sample", s)
			continue
		}
		metric := TagValue(s.Metric[model.MetricNameLabel])
		reqs = append(reqs, StoreSamplesRequest{
			Metric:    metric,
			Timestamp: s.Timestamp.Unix(),
			Value:     v,
			Tags:      tagsFromMetric(s.Metric),
		})
	}

	u, err := url.Parse(c.url)
	if err != nil {
		return err
	}

	u.Path = putEndpoint

	buf, err := json.Marshal(reqs)
	if err != nil {
		return err
	}

	ctx, cancel := context.WithTimeout(context.Background(), c.timeout)
	defer cancel()

	req, err := http.NewRequest("POST", u.String(), bytes.NewBuffer(buf))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", contentTypeJSON)
	resp, err := http.DefaultClient.Do(req.WithContext(ctx))
	if err != nil {
		return err
	}
	defer func() {
		io.Copy(ioutil.Discard, resp.Body)
		resp.Body.Close()
	}()

	// API returns status code 204 for successful writes.
	// http://opentsdb.net/docs/build/html/api_http/put.html
	if resp.StatusCode == http.StatusNoContent {
		return nil
	}

	// API returns status code 400 on error, encoding error details in the
	// response content in JSON.
	buf, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	var r map[string]int
	if err := json.Unmarshal(buf, &r); err != nil {
		return err
	}
	return errors.Errorf("failed to write %d samples to OpenTSDB, %d succeeded", r["failed"], r["success"])
}

// Write sends a batch of samples to OpenTSDB via its HTTP API.

Write sends a batch of samples to OpenTSDB via its HTTP API .


func QueryableClient(c *Client) storage.Queryable {
	remoteReadQueries.WithLabelValues(c.Name())
	return storage.QueryableFunc(func(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
		return &querier{
			ctx:    ctx,
			mint:   mint,
			maxt:   maxt,
			client: c,
		}, nil
	})
}

func QueryableClient ( c * Client ) storage . Queryable { remoteReadQueries . WithLabelValues ( c . Name ( ) ) return storage . QueryableFunc ( func ( ctx context . Context , mint , maxt int64 ) ( storage . Querier , error ) { return & querier { ctx : ctx , mint : mint , maxt : maxt , client : c , } , nil } ) }

// QueryableClient returns a storage.Queryable which queries the given
// Client to select series sets.

QueryableClient returns a storage . Queryable which queries the given Client to select series sets .


func (q *querier) Select(p *storage.SelectParams, matchers ...*labels.Matcher) (storage.SeriesSet, storage.Warnings, error) {
	query, err := ToQuery(q.mint, q.maxt, matchers, p)
	if err != nil {
		return nil, nil, err
	}

	remoteReadGauge := remoteReadQueries.WithLabelValues(q.client.Name())
	remoteReadGauge.Inc()
	defer remoteReadGauge.Dec()

	res, err := q.client.Read(q.ctx, query)
	if err != nil {
		return nil, nil, err
	}

	return FromQueryResult(res), nil, nil
}

func ( q * querier ) Select ( p * storage . SelectParams , matchers ... * labels . Matcher ) ( storage . SeriesSet , storage . Warnings , error ) { query , err := ToQuery ( q . mint , q . maxt , matchers , p ) if err != nil { return nil , nil , err } remoteReadGauge := remoteReadQueries . WithLabelValues ( q . client . Name ( ) ) remoteReadGauge . Inc ( ) defer remoteReadGauge . Dec ( ) res , err := q . client . Read ( q . ctx , query ) if err != nil { return nil , nil , err } return FromQueryResult ( res ) , nil , nil }

// Select implements storage.Querier and uses the given matchers to read series
// sets from the Client.

Select implements storage . Querier and uses the given matchers to read series sets from the Client .


func ExternalLabelsHandler(next storage.Queryable, externalLabels labels.Labels) storage.Queryable {
	return storage.QueryableFunc(func(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
		q, err := next.Querier(ctx, mint, maxt)
		if err != nil {
			return nil, err
		}
		return &externalLabelsQuerier{Querier: q, externalLabels: externalLabels}, nil
	})
}

func ExternalLabelsHandler ( next storage . Queryable , externalLabels labels . Labels ) storage . Queryable { return storage . QueryableFunc ( func ( ctx context . Context , mint , maxt int64 ) ( storage . Querier , error ) { q , err := next . Querier ( ctx , mint , maxt ) if err != nil { return nil , err } return & externalLabelsQuerier { Querier : q , externalLabels : externalLabels } , nil } ) }

// ExternalLabelsHandler returns a storage.Queryable which creates a
// externalLabelsQuerier.

ExternalLabelsHandler returns a storage . Queryable which creates a externalLabelsQuerier .


func (q externalLabelsQuerier) Select(p *storage.SelectParams, matchers ...*labels.Matcher) (storage.SeriesSet, storage.Warnings, error) {
	m, added := q.addExternalLabels(matchers)
	s, warnings, err := q.Querier.Select(p, m...)
	if err != nil {
		return nil, warnings, err
	}
	return newSeriesSetFilter(s, added), warnings, nil
}

func ( q externalLabelsQuerier ) Select ( p * storage . SelectParams , matchers ... * labels . Matcher ) ( storage . SeriesSet , storage . Warnings , error ) { m , added := q . addExternalLabels ( matchers ) s , warnings , err := q . Querier . Select ( p , m ... ) if err != nil { return nil , warnings , err } return newSeriesSetFilter ( s , added ) , warnings , nil }

// Select adds equality matchers for all external labels to the list of matchers
// before calling the wrapped storage.Queryable. The added external labels are
// removed from the returned series sets.

Select adds equality matchers for all external labels to the list of matchers before calling the wrapped storage . Queryable . The added external labels are removed from the returned series sets .


func PreferLocalStorageFilter(next storage.Queryable, cb startTimeCallback) storage.Queryable {
	return storage.QueryableFunc(func(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
		localStartTime, err := cb()
		if err != nil {
			return nil, err
		}
		cmaxt := maxt
		// Avoid queries whose timerange is later than the first timestamp in local DB.
		if mint > localStartTime {
			return storage.NoopQuerier(), nil
		}
		// Query only samples older than the first timestamp in local DB.
		if maxt > localStartTime {
			cmaxt = localStartTime
		}
		return next.Querier(ctx, mint, cmaxt)
	})
}

// PreferLocalStorageFilter returns a QueryableFunc which creates a NoopQuerier
// if requested timeframe can be answered completely by the local TSDB, and
// reduces maxt if the timeframe can be partially answered by TSDB.

PreferLocalStorageFilter returns a QueryableFunc which creates a NoopQuerier if requested timeframe can be answered completely by the local TSDB and reduces maxt if the timeframe can be partially answered by TSDB .


func RequiredMatchersFilter(next storage.Queryable, required []*labels.Matcher) storage.Queryable {
	return storage.QueryableFunc(func(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
		q, err := next.Querier(ctx, mint, maxt)
		if err != nil {
			return nil, err
		}
		return &requiredMatchersQuerier{Querier: q, requiredMatchers: required}, nil
	})
}

func RequiredMatchersFilter ( next storage . Queryable , required [ ] * labels . Matcher ) storage . Queryable { return storage . QueryableFunc ( func ( ctx context . Context , mint , maxt int64 ) ( storage . Querier , error ) { q , err := next . Querier ( ctx , mint , maxt ) if err != nil { return nil , err } return & requiredMatchersQuerier { Querier : q , requiredMatchers : required } , nil } ) }

// RequiredMatchersFilter returns a storage.Queryable which creates a
// requiredMatchersQuerier.

RequiredMatchersFilter returns a storage . Queryable which creates a requiredMatchersQuerier .


func (q requiredMatchersQuerier) Select(p *storage.SelectParams, matchers ...*labels.Matcher) (storage.SeriesSet, storage.Warnings, error) {
	ms := q.requiredMatchers
	for _, m := range matchers {
		for i, r := range ms {
			if m.Type == labels.MatchEqual && m.Name == r.Name && m.Value == r.Value {
				ms = append(ms[:i], ms[i+1:]...)
				break
			}
		}
		if len(ms) == 0 {
			break
		}
	}
	if len(ms) > 0 {
		return storage.NoopSeriesSet(), nil, nil
	}
	return q.Querier.Select(p, matchers...)
}

func ( q requiredMatchersQuerier ) Select ( p * storage . SelectParams , matchers ... * labels . Matcher ) ( storage . SeriesSet , storage . Warnings , error ) { ms := q . requiredMatchers for _ , m := range matchers { for i , r := range ms { if m . Type == labels . MatchEqual && m . Name == r . Name && m . Value == r . Value { ms = append ( ms [ : i ] , ms [ i + 1 : ] ... ) break } } if len ( ms ) == 0 { break } } if len ( ms ) > 0 { return storage . NoopSeriesSet ( ) , nil , nil } return q . Querier . Select ( p , matchers ... ) }

// Select returns a NoopSeriesSet if the given matchers don't match the label
// set of the requiredMatchersQuerier. Otherwise it'll call the wrapped querier.

Select returns a NoopSeriesSet if the given matchers don t match the label set of the requiredMatchersQuerier . Otherwise it ll call the wrapped querier .


func (q externalLabelsQuerier) addExternalLabels(ms []*labels.Matcher) ([]*labels.Matcher, labels.Labels) {
	el := make(labels.Labels, len(q.externalLabels))
	copy(el, q.externalLabels)

	// ms won't be sorted, so have to O(n^2) the search.
	for _, m := range ms {
		for i := 0; i < len(el); {
			if el[i].Name == m.Name {
				el = el[:i+copy(el[i:], el[i+1:])]
				continue
			}
			i++
		}
	}

	for _, l := range el {
		m, err := labels.NewMatcher(labels.MatchEqual, l.Name, l.Value)
		if err != nil {
			panic(err)
		}
		ms = append(ms, m)
	}
	return ms, el
}

// addExternalLabels adds matchers for each external label. External labels
// that already have a corresponding user-supplied matcher are skipped, as we
// assume that the user explicitly wants to select a different value for them.
// We return the new set of matchers, along with a map of labels for which
// matchers were added, so that these can later be removed from the result
// time series again.

addExternalLabels adds matchers for each external label . External labels that already have a corresponding user - supplied matcher are skipped as we assume that the user explicitly wants to select a different value for them . We return the new set of matchers along with a map of labels for which matchers were added so that these can later be removed from the result time series again .


func newInstanceDiscovery(provider *gophercloud.ProviderClient, opts *gophercloud.AuthOptions,
	port int, region string, allTenants bool, l log.Logger) *InstanceDiscovery {
	if l == nil {
		l = log.NewNopLogger()
	}
	return &InstanceDiscovery{provider: provider, authOpts: opts,
		region: region, port: port, allTenants: allTenants, logger: l}
}

func newInstanceDiscovery ( provider * gophercloud . ProviderClient , opts * gophercloud . AuthOptions , port int , region string , allTenants bool , l log . Logger ) * InstanceDiscovery { if l == nil { l = log . NewNopLogger ( ) } return & InstanceDiscovery { provider : provider , authOpts : opts , region : region , port : port , allTenants : allTenants , logger : l } }

// NewInstanceDiscovery returns a new instance discovery.

NewInstanceDiscovery returns a new instance discovery .


func (a *Alert) ResolvedAt(ts time.Time) bool {
	if a.EndsAt.IsZero() {
		return false
	}
	return !a.EndsAt.After(ts)
}

func ( a * Alert ) ResolvedAt ( ts time . Time ) bool { if a . EndsAt . IsZero ( ) { return false } return ! a . EndsAt . After ( ts ) }

// ResolvedAt returns true iff the activity interval ended before
// the given timestamp.

ResolvedAt returns true iff the activity interval ended before the given timestamp .


func NewManager(o *Options, logger log.Logger) *Manager {
	ctx, cancel := context.WithCancel(context.Background())

	if o.Do == nil {
		o.Do = do
	}
	if logger == nil {
		logger = log.NewNopLogger()
	}

	n := &Manager{
		queue:  make([]*Alert, 0, o.QueueCapacity),
		ctx:    ctx,
		cancel: cancel,
		more:   make(chan struct{}, 1),
		opts:   o,
		logger: logger,
	}

	queueLenFunc := func() float64 { return float64(n.queueLen()) }
	alertmanagersDiscoveredFunc := func() float64 { return float64(len(n.Alertmanagers())) }

	n.metrics = newAlertMetrics(
		o.Registerer,
		o.QueueCapacity,
		queueLenFunc,
		alertmanagersDiscoveredFunc,
	)

	return n
}

func NewManager ( o * Options , logger log . Logger ) * Manager { ctx , cancel := context . WithCancel ( context . Background ( ) ) if o . Do == nil { o . Do = do } if logger == nil { logger = log . NewNopLogger ( ) } n := & Manager { queue : make ( [ ] * Alert , 0 , o . QueueCapacity ) , ctx : ctx , cancel : cancel , more : make ( chan struct { } , 1 ) , opts : o , logger : logger , } queueLenFunc := func ( ) float64 { return float64 ( n . queueLen ( ) ) } alertmanagersDiscoveredFunc := func ( ) float64 { return float64 ( len ( n . Alertmanagers ( ) ) ) } n . metrics = newAlertMetrics ( o . Registerer , o . QueueCapacity , queueLenFunc , alertmanagersDiscoveredFunc , ) return n }

// NewManager is the manager constructor.


func (n *Manager) ApplyConfig(conf *config.Config) error {
	n.mtx.Lock()
	defer n.mtx.Unlock()

	n.opts.ExternalLabels = conf.GlobalConfig.ExternalLabels
	n.opts.RelabelConfigs = conf.AlertingConfig.AlertRelabelConfigs

	amSets := make(map[string]*alertmanagerSet)

	for _, cfg := range conf.AlertingConfig.AlertmanagerConfigs {
		ams, err := newAlertmanagerSet(cfg, n.logger)
		if err != nil {
			return err
		}

		ams.metrics = n.metrics

		// The config hash is used for the map lookup identifier.
		b, err := json.Marshal(cfg)
		if err != nil {
			return err
		}
		amSets[fmt.Sprintf("%x", md5.Sum(b))] = ams
	}

	n.alertmanagers = amSets

	return nil
}

// ApplyConfig updates the status state as the new config requires.

ApplyConfig updates the status state as the new config requires .


func (n *Manager) Run(tsets <-chan map[string][]*targetgroup.Group) {

	for {
		select {
		case <-n.ctx.Done():
			return
		case ts := <-tsets:
			n.reload(ts)
		case <-n.more:
		}
		alerts := n.nextBatch()

		if !n.sendAll(alerts...) {
			n.metrics.dropped.Add(float64(len(alerts)))
		}
		// If the queue still has items left, kick off the next iteration.
		if n.queueLen() > 0 {
			n.setMore()
		}
	}
}

// Run dispatches notifications continuously.

Run dispatches notifications continuously .


func (n *Manager) Send(alerts ...*Alert) {
	n.mtx.Lock()
	defer n.mtx.Unlock()

	// Attach external labels before relabelling and sending.
	for _, a := range alerts {
		lb := labels.NewBuilder(a.Labels)

		for _, l := range n.opts.ExternalLabels {
			if a.Labels.Get(l.Name) == "" {
				lb.Set(l.Name, l.Value)
			}
		}

		a.Labels = lb.Labels()
	}

	alerts = n.relabelAlerts(alerts)

	// Queue capacity should be significantly larger than a single alert
	// batch could be.
	if d := len(alerts) - n.opts.QueueCapacity; d > 0 {
		alerts = alerts[d:]

		level.Warn(n.logger).Log("msg", "Alert batch larger than queue capacity, dropping alerts", "num_dropped", d)
		n.metrics.dropped.Add(float64(d))
	}

	// If the queue is full, remove the oldest alerts in favor
	// of newer ones.
	if d := (len(n.queue) + len(alerts)) - n.opts.QueueCapacity; d > 0 {
		n.queue = n.queue[d:]

		level.Warn(n.logger).Log("msg", "Alert notification queue full, dropping alerts", "num_dropped", d)
		n.metrics.dropped.Add(float64(d))
	}
	n.queue = append(n.queue, alerts...)

	// Notify sending goroutine that there are alerts to be processed.
	n.setMore()
}

// Send queues the given notification requests for processing.
// Panics if called on a handler that is not running.

Send queues the given notification requests for processing . Panics if called on a handler that is not running .


func (n *Manager) Alertmanagers() []*url.URL {
	n.mtx.RLock()
	amSets := n.alertmanagers
	n.mtx.RUnlock()

	var res []*url.URL

	for _, ams := range amSets {
		ams.mtx.RLock()
		for _, am := range ams.ams {
			res = append(res, am.url())
		}
		ams.mtx.RUnlock()
	}

	return res
}

func ( n * Manager ) Alertmanagers ( ) [ ] * url . URL { n . mtx . RLock ( ) amSets := n . alertmanagers n . mtx . RUnlock ( ) var res [ ] * url . URL for _ , ams := range amSets { ams . mtx . RLock ( ) for _ , am := range ams . ams { res = append ( res , am . url ( ) ) } ams . mtx . RUnlock ( ) } return res }

// Alertmanagers returns a slice of Alertmanager URLs.

Alertmanagers returns a slice of Alertmanager URLs .


func (n *Manager) DroppedAlertmanagers() []*url.URL {
	n.mtx.RLock()
	amSets := n.alertmanagers
	n.mtx.RUnlock()

	var res []*url.URL

	for _, ams := range amSets {
		ams.mtx.RLock()
		for _, dam := range ams.droppedAms {
			res = append(res, dam.url())
		}
		ams.mtx.RUnlock()
	}

	return res
}

func ( n * Manager ) DroppedAlertmanagers ( ) [ ] * url . URL { n . mtx . RLock ( ) amSets := n . alertmanagers n . mtx . RUnlock ( ) var res [ ] * url . URL for _ , ams := range amSets { ams . mtx . RLock ( ) for _ , dam := range ams . droppedAms { res = append ( res , dam . url ( ) ) } ams . mtx . RUnlock ( ) } return res }

// DroppedAlertmanagers returns a slice of Alertmanager URLs.

DroppedAlertmanagers returns a slice of Alertmanager URLs .


func (n *Manager) sendAll(alerts ...*Alert) bool {
	begin := time.Now()

	b, err := json.Marshal(alerts)
	if err != nil {
		level.Error(n.logger).Log("msg", "Encoding alerts failed", "err", err)
		return false
	}

	n.mtx.RLock()
	amSets := n.alertmanagers
	n.mtx.RUnlock()

	var (
		wg         sync.WaitGroup
		numSuccess uint64
	)
	for _, ams := range amSets {
		ams.mtx.RLock()

		for _, am := range ams.ams {
			wg.Add(1)

			ctx, cancel := context.WithTimeout(n.ctx, time.Duration(ams.cfg.Timeout))
			defer cancel()

			go func(ams *alertmanagerSet, am alertmanager) {
				u := am.url().String()

				if err := n.sendOne(ctx, ams.client, u, b); err != nil {
					level.Error(n.logger).Log("alertmanager", u, "count", len(alerts), "msg", "Error sending alert", "err", err)
					n.metrics.errors.WithLabelValues(u).Inc()
				} else {
					atomic.AddUint64(&numSuccess, 1)
				}
				n.metrics.latency.WithLabelValues(u).Observe(time.Since(begin).Seconds())
				n.metrics.sent.WithLabelValues(u).Add(float64(len(alerts)))

				wg.Done()
			}(ams, am)
		}
		ams.mtx.RUnlock()
	}
	wg.Wait()

	return numSuccess > 0
}

func ( n * Manager ) sendAll ( alerts ... * Alert ) bool { begin := time . Now ( ) b , err := json . Marshal ( alerts ) if err != nil { level . Error ( n . logger ) . Log ( " " , " " , " " , err ) return false } n . mtx . RLock ( ) amSets := n . alertmanagers n . mtx . RUnlock ( ) var ( wg sync . WaitGroup numSuccess uint64 ) for _ , ams := range amSets { ams . mtx . RLock ( ) for _ , am := range ams . ams { wg . Add ( 1 ) ctx , cancel := context . WithTimeout ( n . ctx , time . Duration ( ams . cfg . Timeout ) ) defer cancel ( ) go func ( ams * alertmanagerSet , am alertmanager ) { u := am . url ( ) . String ( ) if err := n . sendOne ( ctx , ams . client , u , b ) ; err != nil { level . Error ( n . logger ) . Log ( " " , u , " " , len ( alerts ) , " " , " " , " " , err ) n . metrics . errors . WithLabelValues ( u ) . Inc ( ) } else { atomic . AddUint64 ( & numSuccess , 1 ) } n . metrics . latency . WithLabelValues ( u ) . Observe ( time . Since ( begin ) . Seconds ( ) ) n . metrics . sent . WithLabelValues ( u ) . Add ( float64 ( len ( alerts ) ) ) wg . Done ( ) } ( ams , am ) } ams . mtx . RUnlock ( ) } wg . Wait ( ) return numSuccess > 0 }

// sendAll sends the alerts to all configured Alertmanagers concurrently.
// It returns true if the alerts could be sent successfully to at least one Alertmanager.

sendAll sends the alerts to all configured Alertmanagers concurrently . It returns true if the alerts could be sent successfully to at least one Alertmanager .


func (n *Manager) Stop() {
	level.Info(n.logger).Log("msg", "Stopping notification manager...")
	n.cancel()
}

func ( n * Manager ) Stop ( ) { level . Info ( n . logger ) . Log ( " " , " " ) n . cancel ( ) }

// Stop shuts down the notification handler.

Stop shuts down the notification handler .


func (s *alertmanagerSet) sync(tgs []*targetgroup.Group) {
	allAms := []alertmanager{}
	allDroppedAms := []alertmanager{}

	for _, tg := range tgs {
		ams, droppedAms, err := alertmanagerFromGroup(tg, s.cfg)
		if err != nil {
			level.Error(s.logger).Log("msg", "Creating discovered Alertmanagers failed", "err", err)
			continue
		}
		allAms = append(allAms, ams...)
		allDroppedAms = append(allDroppedAms, droppedAms...)
	}

	s.mtx.Lock()
	defer s.mtx.Unlock()
	// Set new Alertmanagers and deduplicate them along their unique URL.
	s.ams = []alertmanager{}
	s.droppedAms = []alertmanager{}
	s.droppedAms = append(s.droppedAms, allDroppedAms...)
	seen := map[string]struct{}{}

	for _, am := range allAms {
		us := am.url().String()
		if _, ok := seen[us]; ok {
			continue
		}

		// This will initialize the Counters for the AM to 0.
		s.metrics.sent.WithLabelValues(us)
		s.metrics.errors.WithLabelValues(us)

		seen[us] = struct{}{}
		s.ams = append(s.ams, am)
	}
}

// sync extracts a deduplicated set of Alertmanager endpoints from a list
// of target groups definitions.

sync extracts a deduplicated set of Alertmanager endpoints from a list of target groups definitions .


func alertmanagerFromGroup(tg *targetgroup.Group, cfg *config.AlertmanagerConfig) ([]alertmanager, []alertmanager, error) {
	var res []alertmanager
	var droppedAlertManagers []alertmanager

	for _, tlset := range tg.Targets {
		lbls := make([]labels.Label, 0, len(tlset)+2+len(tg.Labels))

		for ln, lv := range tlset {
			lbls = append(lbls, labels.Label{Name: string(ln), Value: string(lv)})
		}
		// Set configured scheme as the initial scheme label for overwrite.
		lbls = append(lbls, labels.Label{Name: model.SchemeLabel, Value: cfg.Scheme})
		lbls = append(lbls, labels.Label{Name: pathLabel, Value: postPath(cfg.PathPrefix)})

		// Combine target labels with target group labels.
		for ln, lv := range tg.Labels {
			if _, ok := tlset[ln]; !ok {
				lbls = append(lbls, labels.Label{Name: string(ln), Value: string(lv)})
			}
		}

		lset := relabel.Process(labels.New(lbls...), cfg.RelabelConfigs...)
		if lset == nil {
			droppedAlertManagers = append(droppedAlertManagers, alertmanagerLabels{lbls})
			continue
		}

		lb := labels.NewBuilder(lset)

		// addPort checks whether we should add a default port to the address.
		// If the address is not valid, we don't append a port either.
		addPort := func(s string) bool {
			// If we can split, a port exists and we don't have to add one.
			if _, _, err := net.SplitHostPort(s); err == nil {
				return false
			}
			// If adding a port makes it valid, the previous error
			// was not due to an invalid address and we can append a port.
			_, _, err := net.SplitHostPort(s + ":1234")
			return err == nil
		}
		addr := lset.Get(model.AddressLabel)
		// If it's an address with no trailing port, infer it based on the used scheme.
		if addPort(addr) {
			// Addresses reaching this point are already wrapped in [] if necessary.
			switch lset.Get(model.SchemeLabel) {
			case "http", "":
				addr = addr + ":80"
			case "https":
				addr = addr + ":443"
			default:
				return nil, nil, errors.Errorf("invalid scheme: %q", cfg.Scheme)
			}
			lb.Set(model.AddressLabel, addr)
		}

		if err := config.CheckTargetAddress(model.LabelValue(addr)); err != nil {
			return nil, nil, err
		}

		// Meta labels are deleted after relabelling. Other internal labels propagate to
		// the target which decides whether they will be part of their label set.
		for _, l := range lset {
			if strings.HasPrefix(l.Name, model.MetaLabelPrefix) {
				lb.Del(l.Name)
			}
		}

		res = append(res, alertmanagerLabels{lset})
	}
	return res, droppedAlertManagers, nil
}

// alertmanagersFromGroup extracts a list of alertmanagers from a target group
// and an associated AlertmanagerConfig.

alertmanagersFromGroup extracts a list of alertmanagers from a target group and an associated AlertmanagerConfig .


func (i item) String() string {
	switch {
	case i.typ == ItemEOF:
		return "EOF"
	case i.typ == ItemError:
		return i.val
	case i.typ == ItemIdentifier || i.typ == ItemMetricIdentifier:
		return fmt.Sprintf("%q", i.val)
	case i.typ.isKeyword():
		return fmt.Sprintf("<%s>", i.val)
	case i.typ.isOperator():
		return fmt.Sprintf("<op:%s>", i.val)
	case i.typ.isAggregator():
		return fmt.Sprintf("<aggr:%s>", i.val)
	case len(i.val) > 10:
		return fmt.Sprintf("%.10q...", i.val)
	}
	return fmt.Sprintf("%q", i.val)
}

func ( i item ) String ( ) string { switch { case i . typ == ItemEOF : return " " case i . typ == ItemError : return i . val case i . typ == ItemIdentifier || i . typ == ItemMetricIdentifier : return fmt . Sprintf ( " " , i . val ) case i . typ . isKeyword ( ) : return fmt . Sprintf ( " " , i . val ) case i . typ . isOperator ( ) : return fmt . Sprintf ( " " , i . val ) case i . typ . isAggregator ( ) : return fmt . Sprintf ( " " , i . val ) case len ( i . val ) > 10 : return fmt . Sprintf ( " " , i . val ) } return fmt . Sprintf ( " " , i . val ) }

// String returns a descriptive string for the item.

String returns a descriptive string for the item .


func (i ItemType) isAggregatorWithParam() bool {
	return i == ItemTopK || i == ItemBottomK || i == ItemCountValues || i == ItemQuantile
}

func ( i ItemType ) isAggregatorWithParam ( ) bool { return i == ItemTopK || i == ItemBottomK || i == ItemCountValues || i == ItemQuantile }

// isAggregator returns true if the item is an aggregator that takes a parameter.
// Returns false otherwise

isAggregator returns true if the item is an aggregator that takes a parameter . Returns false otherwise


func (i ItemType) isComparisonOperator() bool {
	switch i {
	case ItemEQL, ItemNEQ, ItemLTE, ItemLSS, ItemGTE, ItemGTR:
		return true
	default:
		return false
	}
}

func ( i ItemType ) isComparisonOperator ( ) bool { switch i { case ItemEQL , ItemNEQ , ItemLTE , ItemLSS , ItemGTE , ItemGTR : return true default : return false } }

// isCompairsonOperator returns true if the item corresponds to a comparison operator.
// Returns false otherwise.

isCompairsonOperator returns true if the item corresponds to a comparison operator . Returns false otherwise .


func (i ItemType) isSetOperator() bool {
	switch i {
	case ItemLAND, ItemLOR, ItemLUnless:
		return true
	}
	return false
}

func ( i ItemType ) isSetOperator ( ) bool { switch i { case ItemLAND , ItemLOR , ItemLUnless : return true } return false }

// isSetOperator returns whether the item corresponds to a set operator.

isSetOperator returns whether the item corresponds to a set operator .


func (i ItemType) precedence() int {
	switch i {
	case ItemLOR:
		return 1
	case ItemLAND, ItemLUnless:
		return 2
	case ItemEQL, ItemNEQ, ItemLTE, ItemLSS, ItemGTE, ItemGTR:
		return 3
	case ItemADD, ItemSUB:
		return 4
	case ItemMUL, ItemDIV, ItemMOD:
		return 5
	case ItemPOW:
		return 6
	default:
		return LowestPrec
	}
}

func ( i ItemType ) precedence ( ) int { switch i { case ItemLOR : return 1 case ItemLAND , ItemLUnless : return 2 case ItemEQL , ItemNEQ , ItemLTE , ItemLSS , ItemGTE , ItemGTR : return 3 case ItemADD , ItemSUB : return 4 case ItemMUL , ItemDIV , ItemMOD : return 5 case ItemPOW : return 6 default : return LowestPrec } }

// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrec.

Precedence returns the operator precedence of the binary operator op . If op is not a binary operator the result is LowestPrec .


func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = Pos(w)
	l.pos += l.width
	return r
}

func ( l * lexer ) next ( ) rune { if int ( l . pos ) >= len ( l . input ) { l . width = 0 return eof } r , w := utf8 . DecodeRuneInString ( l . input [ l . pos : ] ) l . width = Pos ( w ) l . pos += l . width return r }

// next returns the next rune in the input.

next returns the next rune in the input .


func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

func ( l * lexer ) peek ( ) rune { r := l . next ( ) l . backup ( ) return r }

// peek returns but does not consume the next rune in the input.

peek returns but does not consume the next rune in the input .


func (l *lexer) emit(t ItemType) {
	l.items <- item{t, l.start, l.input[l.start:l.pos]}
	l.start = l.pos
}

func ( l * lexer ) emit ( t ItemType ) { l . items <- item { t , l . start , l . input [ l . start : l . pos ] } l . start = l . pos }

// emit passes an item back to the client.

emit passes an item back to the client .


func (l *lexer) linePosition() int {
	lb := strings.LastIndex(l.input[:l.lastPos], "\n")
	if lb == -1 {
		return 1 + int(l.lastPos)
	}
	return 1 + int(l.lastPos) - lb
}

func ( l * lexer ) linePosition ( ) int { lb := strings . LastIndex ( l . input [ : l . lastPos ] , " \n " ) if lb == - 1 { return 1 + int ( l . lastPos ) } return 1 + int ( l . lastPos ) - lb }

// linePosition reports at which character in the current line
// we are on.

linePosition reports at which character in the current line we are on .


func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = item.pos
	return item
}

func ( l * lexer ) nextItem ( ) item { item := <- l . items l . lastPos = item . pos return item }

// nextItem returns the next item from the input.

nextItem returns the next item from the input .


func lex(input string) *lexer {
	l := &lexer{
		input: input,
		items: make(chan item),
	}
	go l.run()
	return l
}

func lex ( input string ) * lexer { l := & lexer { input : input , items : make ( chan item ) , } go l . run ( ) return l }

// lex creates a new scanner for the input string.

lex creates a new scanner for the input string .


func lexInsideBraces(l *lexer) stateFn {
	if strings.HasPrefix(l.input[l.pos:], lineComment) {
		return lexLineComment
	}

	switch r := l.next(); {
	case r == eof:
		return l.errorf("unexpected end of input inside braces")
	case isSpace(r):
		return lexSpace
	case isAlpha(r):
		l.backup()
		return lexIdentifier
	case r == ',':
		l.emit(ItemComma)
	case r == '"' || r == '\'':
		l.stringOpen = r
		return lexString
	case r == '`':
		l.stringOpen = r
		return lexRawString
	case r == '=':
		if l.next() == '~' {
			l.emit(ItemEQLRegex)
			break
		}
		l.backup()
		l.emit(ItemEQL)
	case r == '!':
		switch nr := l.next(); {
		case nr == '~':
			l.emit(ItemNEQRegex)
		case nr == '=':
			l.emit(ItemNEQ)
		default:
			return l.errorf("unexpected character after '!' inside braces: %q", nr)
		}
	case r == '{':
		return l.errorf("unexpected left brace %q", r)
	case r == '}':
		l.emit(ItemRightBrace)
		l.braceOpen = false

		if l.seriesDesc {
			return lexValueSequence
		}
		return lexStatements
	default:
		return l.errorf("unexpected character inside braces: %q", r)
	}
	return lexInsideBraces
}

func lexInsideBraces ( l * lexer ) stateFn { if strings . HasPrefix ( l . input [ l . pos : ] , lineComment ) { return lexLineComment } switch r := l . next ( ) ; { case r == eof : return l . errorf ( " " ) case isSpace ( r ) : return lexSpace case isAlpha ( r ) : l . backup ( ) return lexIdentifier case r == ',' : l . emit ( ItemComma ) case r == '"' || r == '\'' : l . stringOpen = r return lexString case r == '`' : l . stringOpen = r return lexRawString case r == '=' : if l . next ( ) == '~' { l . emit ( ItemEQLRegex ) break } l . backup ( ) l . emit ( ItemEQL ) case r == '!' : switch nr := l . next ( ) ; { case nr == '~' : l . emit ( ItemNEQRegex ) case nr == '=' : l . emit ( ItemNEQ ) default : return l . errorf ( " " , nr ) } case r == '{' : return l . errorf ( " " , r ) case r == '}' : l . emit ( ItemRightBrace ) l . braceOpen = false if l . seriesDesc { return lexValueSequence } return lexStatements default : return l . errorf ( " " , r ) } return lexInsideBraces }

// lexInsideBraces scans the inside of a vector selector. Keywords are ignored and
// scanned as identifiers.

lexInsideBraces scans the inside of a vector selector . Keywords are ignored and scanned as identifiers .


func lexValueSequence(l *lexer) stateFn {
	switch r := l.next(); {
	case r == eof:
		return lexStatements
	case isSpace(r):
		l.emit(ItemSpace)
		lexSpace(l)
	case r == '+':
		l.emit(ItemADD)
	case r == '-':
		l.emit(ItemSUB)
	case r == 'x':
		l.emit(ItemTimes)
	case r == '_':
		l.emit(ItemBlank)
	case isDigit(r) || (r == '.' && isDigit(l.peek())):
		l.backup()
		lexNumber(l)
	case isAlpha(r):
		l.backup()
		// We might lex invalid items here but this will be caught by the parser.
		return lexKeywordOrIdentifier
	default:
		return l.errorf("unexpected character in series sequence: %q", r)
	}
	return lexValueSequence
}

// lexValueSequence scans a value sequence of a series description.

lexValueSequence scans a value sequence of a series description .


func digitVal(ch rune) int {
	switch {
	case '0' <= ch && ch <= '9':
		return int(ch - '0')
	case 'a' <= ch && ch <= 'f':
		return int(ch - 'a' + 10)
	case 'A' <= ch && ch <= 'F':
		return int(ch - 'A' + 10)
	}
	return 16 // Larger than any legal digit val.
}

func
digitVal
(
ch
rune
)
int
{
switch
{
case
'0'
<=
ch
&&
ch
<=
'9'
:
return
int
(
ch
'0'
)
case
'a'
<=
ch
&&
ch
<=
'f'
:
return
int
(
ch
'a'
+
10
)
case
'A'
<=
ch
&&
ch
<=
'F'
:
return
int
(
ch
'A'
+
10
)
}
return
16
// Larger than any legal digit val.
}

// digitVal returns the digit value of a rune or 16 in case the rune does not
// represent a valid digit.

digitVal returns the digit value of a rune or 16 in case the rune does not represent a valid digit .


func lexString(l *lexer) stateFn {
Loop:
	for {
		switch l.next() {
		case '\\':
			lexEscape(l)
		case utf8.RuneError:
			return l.errorf("invalid UTF-8 rune")
		case eof, '\n':
			return l.errorf("unterminated quoted string")
		case l.stringOpen:
			break Loop
		}
	}
	l.emit(ItemString)
	return lexStatements
}

func lexString ( l * lexer ) stateFn { Loop : for { switch l . next ( ) { case '\\' : lexEscape ( l ) case utf8 . RuneError : return l . errorf ( " " ) case eof , '\n' : return l . errorf ( " " ) case l . stringOpen : break Loop } } l . emit ( ItemString ) return lexStatements }

// lexString scans a quoted string. The initial quote has already been seen.

lexString scans a quoted string . The initial quote has already been seen .


func lexSpace(l *lexer) stateFn {
	for isSpace(l.peek()) {
		l.next()
	}
	l.ignore()
	return lexStatements
}

func lexSpace ( l * lexer ) stateFn { for isSpace ( l . peek ( ) ) { l . next ( ) } l . ignore ( ) return lexStatements }

// lexSpace scans a run of space characters. One space has already been seen.

lexSpace scans a run of space characters . One space has already been seen .


func lexLineComment(l *lexer) stateFn {
	l.pos += Pos(len(lineComment))
	for r := l.next(); !isEndOfLine(r) && r != eof; {
		r = l.next()
	}
	l.backup()
	l.emit(ItemComment)
	return lexStatements
}

func lexLineComment ( l * lexer ) stateFn { l . pos += Pos ( len ( lineComment ) ) for r := l . next ( ) ; ! isEndOfLine ( r ) && r != eof ; { r = l . next ( ) } l . backup ( ) l . emit ( ItemComment ) return lexStatements }

// lexLineComment scans a line comment. Left comment marker is known to be present.

lexLineComment scans a line comment . Left comment marker is known to be present .


func lexNumberOrDuration(l *lexer) stateFn {
	if l.scanNumber() {
		l.emit(ItemNumber)
		return lexStatements
	}
	// Next two chars must be a valid unit and a non-alphanumeric.
	if l.accept("smhdwy") {
		if isAlphaNumeric(l.next()) {
			return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos])
		}
		l.backup()
		l.emit(ItemDuration)
		return lexStatements
	}
	return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos])
}

// lexNumberOrDuration scans a number or a duration item.

lexNumberOrDuration scans a number or a duration item .


func (l *lexer) scanNumber() bool {
	digits := "0123456789"
	// Disallow hexadecimal in series descriptions as the syntax is ambiguous.
	if !l.seriesDesc && l.accept("0") && l.accept("xX") {
		digits = "0123456789abcdefABCDEF"
	}
	l.acceptRun(digits)
	if l.accept(".") {
		l.acceptRun(digits)
	}
	if l.accept("eE") {
		l.accept("+-")
		l.acceptRun("0123456789")
	}
	// Next thing must not be alphanumeric unless it's the times token
	// for series repetitions.
	if r := l.peek(); (l.seriesDesc && r == 'x') || !isAlphaNumeric(r) {
		return true
	}
	return false
}

// scanNumber scans numbers of different formats. The scanned item is
// not necessarily a valid number. This case is caught by the parser.

scanNumber scans numbers of different formats . The scanned item is not necessarily a valid number . This case is caught by the parser .


func lexIdentifier(l *lexer) stateFn {
	for isAlphaNumeric(l.next()) {
		// absorb
	}
	l.backup()
	l.emit(ItemIdentifier)
	return lexStatements
}

func
lexIdentifier
(
l
*
lexer
)
stateFn
{
for
isAlphaNumeric
(
l
.
next
(
)
)
{
// absorb
}
l
.
backup
(
)
l
.
emit
(
ItemIdentifier
)
return
lexStatements
}

// lexIdentifier scans an alphanumeric identifier. The next character
// is known to be a letter.

lexIdentifier scans an alphanumeric identifier . The next character is known to be a letter .


func lexKeywordOrIdentifier(l *lexer) stateFn {
Loop:
	for {
		switch r := l.next(); {
		case isAlphaNumeric(r) || r == ':':
			// absorb.
		default:
			l.backup()
			word := l.input[l.start:l.pos]
			if kw, ok := key[strings.ToLower(word)]; ok {
				l.emit(kw)
			} else if !strings.Contains(word, ":") {
				l.emit(ItemIdentifier)
			} else {
				l.emit(ItemMetricIdentifier)
			}
			break Loop
		}
	}
	if l.seriesDesc && l.peek() != '{' {
		return lexValueSequence
	}
	return lexStatements
}

func
lexKeywordOrIdentifier
(
l
*
lexer
)
stateFn
{
Loop
:
for
{
switch
r
:=
l
.
next
(
)
;
{
case
isAlphaNumeric
(
r
)
||
r
==
':'
:
// absorb.
default
:
l
.
backup
(
)
word
:=
l
.
input
[
l
.
start
:
l
.
pos
]
if
kw
,
ok
:=
key
[
strings
.
ToLower
(
word
)
]
;
ok
{
l
.
emit
(
kw
)
}
else
if
!
strings
.
Contains
(
word
,
"
"
)
{
l
.
emit
(
ItemIdentifier
)
}
else
{
l
.
emit
(
ItemMetricIdentifier
)
}
break
Loop
}
}
if
l
.
seriesDesc
&&
l
.
peek
(
)
!=
'{'
{
return
lexValueSequence
}
return
lexStatements
}

// lexKeywordOrIdentifier scans an alphanumeric identifier which may contain
// a colon rune. If the identifier is a keyword the respective keyword item
// is scanned.

lexKeywordOrIdentifier scans an alphanumeric identifier which may contain a colon rune . If the identifier is a keyword the respective keyword item is scanned .


func isLabel(s string) bool {
	if len(s) == 0 || !isAlpha(rune(s[0])) {
		return false
	}
	for _, c := range s[1:] {
		if !isAlphaNumeric(c) {
			return false
		}
	}
	return true
}

func isLabel ( s string ) bool { if len ( s ) == 0 || ! isAlpha ( rune ( s [ 0 ] ) ) { return false } for _ , c := range s [ 1 : ] { if ! isAlphaNumeric ( c ) { return false } } return true }

// isLabel reports whether the string can be used as label.

isLabel reports whether the string can be used as label .


func (p *PromParser) Series() ([]byte, *int64, float64) {
	if p.hasTS {
		return p.series, &p.ts, p.val
	}
	return p.series, nil, p.val
}

func ( p * PromParser ) Series ( ) ( [ ] byte , * int64 , float64 ) { if p . hasTS { return p . series , & p . ts , p . val } return p . series , nil , p . val }

// Series returns the bytes of the series, the timestamp if set, and the value
// of the current sample.

Series returns the bytes of the series the timestamp if set and the value of the current sample .


func (p *PromParser) Type() ([]byte, MetricType) {
	return p.l.b[p.offsets[0]:p.offsets[1]], p.mtype
}

func ( p * PromParser ) Type ( ) ( [ ] byte , MetricType ) { return p . l . b [ p . offsets [ 0 ] : p . offsets [ 1 ] ] , p . mtype }

// Type returns the metric name and type in the current entry.
// Must only be called after Next returned a type entry.
// The returned byte slices become invalid after the next call to Next.

Type returns the metric name and type in the current entry . Must only be called after Next returned a type entry . The returned byte slices become invalid after the next call to Next .


func (p *PromParser) nextToken() token {
	for {
		if tok := p.l.Lex(); tok != tWhitespace {
			return tok
		}
	}
}

func ( p * PromParser ) nextToken ( ) token { for { if tok := p . l . Lex ( ) ; tok != tWhitespace { return tok } } }

// nextToken returns the next token from the promlexer. It skips over tabs
// and spaces.

nextToken returns the next token from the promlexer . It skips over tabs and spaces .


func NewAPI(
	qe *promql.Engine,
	q storage.Queryable,
	tr targetRetriever,
	ar alertmanagerRetriever,
	configFunc func() config.Config,
	flagsMap map[string]string,
	readyFunc func(http.HandlerFunc) http.HandlerFunc,
	db func() TSDBAdmin,
	enableAdmin bool,
	logger log.Logger,
	rr rulesRetriever,
	remoteReadSampleLimit int,
	remoteReadConcurrencyLimit int,
	CORSOrigin *regexp.Regexp,
) *API {
	return &API{
		QueryEngine:           qe,
		Queryable:             q,
		targetRetriever:       tr,
		alertmanagerRetriever: ar,

		now:                   time.Now,
		config:                configFunc,
		flagsMap:              flagsMap,
		ready:                 readyFunc,
		db:                    db,
		enableAdmin:           enableAdmin,
		rulesRetriever:        rr,
		remoteReadSampleLimit: remoteReadSampleLimit,
		remoteReadGate:        gate.New(remoteReadConcurrencyLimit),
		logger:                logger,
		CORSOrigin:            CORSOrigin,
	}
}

func NewAPI ( qe * promql . Engine , q storage . Queryable , tr targetRetriever , ar alertmanagerRetriever , configFunc func ( ) config . Config , flagsMap map [ string ] string , readyFunc func ( http . HandlerFunc ) http . HandlerFunc , db func ( ) TSDBAdmin , enableAdmin bool , logger log . Logger , rr rulesRetriever , remoteReadSampleLimit int , remoteReadConcurrencyLimit int , CORSOrigin * regexp . Regexp , ) * API { return & API { QueryEngine : qe , Queryable : q , targetRetriever : tr , alertmanagerRetriever : ar , now : time . Now , config : configFunc , flagsMap : flagsMap , ready : readyFunc , db : db , enableAdmin : enableAdmin , rulesRetriever : rr , remoteReadSampleLimit : remoteReadSampleLimit , remoteReadGate : gate . New ( remoteReadConcurrencyLimit ) , logger : logger , CORSOrigin : CORSOrigin , } }

// NewAPI returns an initialized API type.

NewAPI returns an initialized API type .


func mergeLabels(primary, secondary []prompb.Label) []prompb.Label {
	result := make([]prompb.Label, 0, len(primary)+len(secondary))
	i, j := 0, 0
	for i < len(primary) && j < len(secondary) {
		if primary[i].Name < secondary[j].Name {
			result = append(result, primary[i])
			i++
		} else if primary[i].Name > secondary[j].Name {
			result = append(result, secondary[j])
			j++
		} else {
			result = append(result, primary[i])
			i++
			j++
		}
	}
	for ; i < len(primary); i++ {
		result = append(result, primary[i])
	}
	for ; j < len(secondary); j++ {
		result = append(result, secondary[j])
	}
	return result
}

func mergeLabels ( primary , secondary [ ] prompb . Label ) [ ] prompb . Label { result := make ( [ ] prompb . Label , 0 , len ( primary ) + len ( secondary ) ) i , j := 0 , 0 for i < len ( primary ) && j < len ( secondary ) { if primary [ i ] . Name < secondary [ j ] . Name { result = append ( result , primary [ i ] ) i ++ } else if primary [ i ] . Name > secondary [ j ] . Name { result = append ( result , secondary [ j ] ) j ++ } else { result = append ( result , primary [ i ] ) i ++ j ++ } } for ; i < len ( primary ) ; i ++ { result = append ( result , primary [ i ] ) } for ; j < len ( secondary ) ; j ++ { result = append ( result , secondary [ j ] ) } return result }

// mergeLabels merges two sets of sorted proto labels, preferring those in
// primary to those in secondary when there is an overlap.

mergeLabels merges two sets of sorted proto labels preferring those in primary to those in secondary when there is an overlap .


func (s *ReadyStorage) Set(db *tsdb.DB, startTimeMargin int64) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	s.a = &adapter{db: db, startTimeMargin: startTimeMargin}
}

func ( s * ReadyStorage ) Set ( db * tsdb . DB , startTimeMargin int64 ) { s . mtx . Lock ( ) defer s . mtx . Unlock ( ) s . a = & adapter { db : db , startTimeMargin : startTimeMargin } }


func (s *ReadyStorage) Get() *tsdb.DB {
	if x := s.get(); x != nil {
		return x.db
	}
	return nil
}

func ( s * ReadyStorage ) Get ( ) * tsdb . DB { if x := s . get ( ) ; x != nil { return x . db } return nil }


func (s *ReadyStorage) Querier(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
	if x := s.get(); x != nil {
		return x.Querier(ctx, mint, maxt)
	}
	return nil, ErrNotReady
}

func ( s * ReadyStorage ) Querier ( ctx context . Context , mint , maxt int64 ) ( storage . Querier , error ) { if x := s . get ( ) ; x != nil { return x . Querier ( ctx , mint , maxt ) } return nil , ErrNotReady }

// Querier implements the Storage interface.

Querier implements the Storage interface .


func (s *ReadyStorage) Appender() (storage.Appender, error) {
	if x := s.get(); x != nil {
		return x.Appender()
	}
	return nil, ErrNotReady
}

func ( s * ReadyStorage ) Appender ( ) ( storage . Appender , error ) { if x := s . get ( ) ; x != nil { return x . Appender ( ) } return nil , ErrNotReady }

// Appender implements the Storage interface.

Appender implements the Storage interface .


func (s *ReadyStorage) Close() error {
	if x := s.Get(); x != nil {
		return x.Close()
	}
	return nil
}

func ( s * ReadyStorage ) Close ( ) error { if x := s . Get ( ) ; x != nil { return x . Close ( ) } return nil }

// Close implements the Storage interface.

Close implements the Storage interface .


func Adapter(db *tsdb.DB, startTimeMargin int64) storage.Storage {
	return &adapter{db: db, startTimeMargin: startTimeMargin}
}

func Adapter ( db * tsdb . DB , startTimeMargin int64 ) storage . Storage { return & adapter { db : db , startTimeMargin : startTimeMargin } }

// Adapter return an adapter as storage.Storage.

Adapter return an adapter as storage . Storage .


func Open(path string, l log.Logger, r prometheus.Registerer, opts *Options) (*tsdb.DB, error) {
	if opts.MinBlockDuration > opts.MaxBlockDuration {
		opts.MaxBlockDuration = opts.MinBlockDuration
	}
	// Start with smallest block duration and create exponential buckets until the exceed the
	// configured maximum block duration.
	rngs := tsdb.ExponentialBlockRanges(int64(time.Duration(opts.MinBlockDuration).Seconds()*1000), 10, 3)

	for i, v := range rngs {
		if v > int64(time.Duration(opts.MaxBlockDuration).Seconds()*1000) {
			rngs = rngs[:i]
			break
		}
	}

	db, err := tsdb.Open(path, l, r, &tsdb.Options{
		WALSegmentSize:         int(opts.WALSegmentSize),
		RetentionDuration:      uint64(time.Duration(opts.RetentionDuration).Seconds() * 1000),
		MaxBytes:               int64(opts.MaxBytes),
		BlockRanges:            rngs,
		NoLockfile:             opts.NoLockfile,
		AllowOverlappingBlocks: opts.AllowOverlappingBlocks,
	})
	if err != nil {
		return nil, err
	}
	registerMetrics(db, r)

	return db, nil
}

// Open returns a new storage backed by a TSDB database that is configured for Prometheus.

Open returns a new storage backed by a TSDB database that is configured for Prometheus .


func (a adapter) Appender() (storage.Appender, error) {
	return appender{a: a.db.Appender()}, nil
}

func ( a adapter ) Appender ( ) ( storage . Appender , error ) { return appender { a : a . db . Appender ( ) } , nil }

// Appender returns a new appender against the storage.

Appender returns a new appender against the storage .


func NewRegexp(s string) (Regexp, error) {
	regex, err := regexp.Compile("^(?:" + s + ")$")
	return Regexp{
		Regexp:   regex,
		original: s,
	}, err
}

func NewRegexp ( s string ) ( Regexp , error ) { regex , err := regexp . Compile ( " " + s + " " ) return Regexp { Regexp : regex , original : s , } , err }

// NewRegexp creates a new anchored Regexp and returns an error if the
// passed-in regular expression does not compile.

NewRegexp creates a new anchored Regexp and returns an error if the passed - in regular expression does not compile .


func MustNewRegexp(s string) Regexp {
	re, err := NewRegexp(s)
	if err != nil {
		panic(err)
	}
	return re
}

func MustNewRegexp ( s string ) Regexp { re , err := NewRegexp ( s ) if err != nil { panic ( err ) } return re }

// MustNewRegexp works like NewRegexp, but panics if the regular expression does not compile.

MustNewRegexp works like NewRegexp but panics if the regular expression does not compile .


func Process(labels labels.Labels, cfgs ...*Config) labels.Labels {
	for _, cfg := range cfgs {
		labels = relabel(labels, cfg)
		if labels == nil {
			return nil
		}
	}
	return labels
}

func Process ( labels labels . Labels , cfgs ... * Config ) labels . Labels { for _ , cfg := range cfgs { labels = relabel ( labels , cfg ) if labels == nil { return nil } } return labels }

// Process returns a relabeled copy of the given label set. The relabel configurations
// are applied in order of input.
// If a label set is dropped, nil is returned.
// May return the input labelSet modified.

Process returns a relabeled copy of the given label set . The relabel configurations are applied in order of input . If a label set is dropped nil is returned . May return the input labelSet modified .


func sum64(hash [md5.Size]byte) uint64 {
	var s uint64

	for i, b := range hash {
		shift := uint64((md5.Size - i - 1) * 8)

		s |= uint64(b) << shift
	}
	return s
}

func sum64 ( hash [ md5 . Size ] byte ) uint64 { var s uint64 for i , b := range hash { shift := uint64 ( ( md5 . Size - i - 1 ) * 8 ) s |= uint64 ( b ) << shift } return s }

// sum64 sums the md5 hash to an uint64.


func (sp *scrapePool) stop() {
	sp.cancel()
	var wg sync.WaitGroup

	sp.mtx.Lock()
	defer sp.mtx.Unlock()

	for fp, l := range sp.loops {
		wg.Add(1)

		go func(l loop) {
			l.stop()
			wg.Done()
		}(l)

		delete(sp.loops, fp)
		delete(sp.activeTargets, fp)
	}
	wg.Wait()
	sp.client.CloseIdleConnections()
}

func ( sp * scrapePool ) stop ( ) { sp . cancel ( ) var wg sync . WaitGroup sp . mtx . Lock ( ) defer sp . mtx . Unlock ( ) for fp , l := range sp . loops { wg . Add ( 1 ) go func ( l loop ) { l . stop ( ) wg . Done ( ) } ( l ) delete ( sp . loops , fp ) delete ( sp . activeTargets , fp ) } wg . Wait ( ) sp . client . CloseIdleConnections ( ) }

// stop terminates all scrape loops and returns after they all terminated.

stop terminates all scrape loops and returns after they all terminated .


func (sp *scrapePool) reload(cfg *config.ScrapeConfig) error {
	targetScrapePoolReloads.Inc()
	start := time.Now()

	sp.mtx.Lock()
	defer sp.mtx.Unlock()

	client, err := config_util.NewClientFromConfig(cfg.HTTPClientConfig, cfg.JobName)
	if err != nil {
		targetScrapePoolReloadsFailed.Inc()
		return errors.Wrap(err, "error creating HTTP client")
	}
	sp.config = cfg
	oldClient := sp.client
	sp.client = client

	var (
		wg              sync.WaitGroup
		interval        = time.Duration(sp.config.ScrapeInterval)
		timeout         = time.Duration(sp.config.ScrapeTimeout)
		limit           = int(sp.config.SampleLimit)
		honorLabels     = sp.config.HonorLabels
		honorTimestamps = sp.config.HonorTimestamps
		mrc             = sp.config.MetricRelabelConfigs
	)

	for fp, oldLoop := range sp.loops {
		var (
			t       = sp.activeTargets[fp]
			s       = &targetScraper{Target: t, client: sp.client, timeout: timeout}
			newLoop = sp.newLoop(scrapeLoopOptions{
				target:          t,
				scraper:         s,
				limit:           limit,
				honorLabels:     honorLabels,
				honorTimestamps: honorTimestamps,
				mrc:             mrc,
			})
		)
		wg.Add(1)

		go func(oldLoop, newLoop loop) {
			oldLoop.stop()
			wg.Done()

			go newLoop.run(interval, timeout, nil)
		}(oldLoop, newLoop)

		sp.loops[fp] = newLoop
	}

	wg.Wait()
	oldClient.CloseIdleConnections()
	targetReloadIntervalLength.WithLabelValues(interval.String()).Observe(
		time.Since(start).Seconds(),
	)
	return nil
}

func ( sp * scrapePool ) reload ( cfg * config . ScrapeConfig ) error { targetScrapePoolReloads . Inc ( ) start := time . Now ( ) sp . mtx . Lock ( ) defer sp . mtx . Unlock ( ) client , err := config_util . NewClientFromConfig ( cfg . HTTPClientConfig , cfg . JobName ) if err != nil { targetScrapePoolReloadsFailed . Inc ( ) return errors . Wrap ( err , " " ) } sp . config = cfg oldClient := sp . client sp . client = client var ( wg sync . WaitGroup interval = time . Duration ( sp . config . ScrapeInterval ) timeout = time . Duration ( sp . config . ScrapeTimeout ) limit = int ( sp . config . SampleLimit ) honorLabels = sp . config . HonorLabels honorTimestamps = sp . config . HonorTimestamps mrc = sp . config . MetricRelabelConfigs ) for fp , oldLoop := range sp . loops { var ( t = sp . activeTargets [ fp ] s = & targetScraper { Target : t , client : sp . client , timeout : timeout } newLoop = sp . newLoop ( scrapeLoopOptions { target : t , scraper : s , limit : limit , honorLabels : honorLabels , honorTimestamps : honorTimestamps , mrc : mrc , } ) ) wg . Add ( 1 ) go func ( oldLoop , newLoop loop ) { oldLoop . stop ( ) wg . Done ( ) go newLoop . run ( interval , timeout , nil ) } ( oldLoop , newLoop ) sp . loops [ fp ] = newLoop } wg . Wait ( ) oldClient . CloseIdleConnections ( ) targetReloadIntervalLength . WithLabelValues ( interval . String ( ) ) . Observe ( time . Since ( start ) . Seconds ( ) , ) return nil }

// reload the scrape pool with the given scrape configuration. The target state is preserved
// but all scrape loops are restarted with the new scrape configuration.
// This method returns after all scrape loops that were stopped have stopped scraping.

reload the scrape pool with the given scrape configuration . The target state is preserved but all scrape loops are restarted with the new scrape configuration . This method returns after all scrape loops that were stopped have stopped scraping .


func (sp *scrapePool) Sync(tgs []*targetgroup.Group) {
	start := time.Now()

	var all []*Target
	sp.mtx.Lock()
	sp.droppedTargets = []*Target{}
	for _, tg := range tgs {
		targets, err := targetsFromGroup(tg, sp.config)
		if err != nil {
			level.Error(sp.logger).Log("msg", "creating targets failed", "err", err)
			continue
		}
		for _, t := range targets {
			if t.Labels().Len() > 0 {
				all = append(all, t)
			} else if t.DiscoveredLabels().Len() > 0 {
				sp.droppedTargets = append(sp.droppedTargets, t)
			}
		}
	}
	sp.mtx.Unlock()
	sp.sync(all)

	targetSyncIntervalLength.WithLabelValues(sp.config.JobName).Observe(
		time.Since(start).Seconds(),
	)
	targetScrapePoolSyncsCounter.WithLabelValues(sp.config.JobName).Inc()
}

func ( sp * scrapePool ) Sync ( tgs [ ] * targetgroup . Group ) { start := time . Now ( ) var all [ ] * Target sp . mtx . Lock ( ) sp . droppedTargets = [ ] * Target { } for _ , tg := range tgs { targets , err := targetsFromGroup ( tg , sp . config ) if err != nil { level . Error ( sp . logger ) . Log ( " " , " " , " " , err ) continue } for _ , t := range targets { if t . Labels ( ) . Len ( ) > 0 { all = append ( all , t ) } else if t . DiscoveredLabels ( ) . Len ( ) > 0 { sp . droppedTargets = append ( sp . droppedTargets , t ) } } } sp . mtx . Unlock ( ) sp . sync ( all ) targetSyncIntervalLength . WithLabelValues ( sp . config . JobName ) . Observe ( time . Since ( start ) . Seconds ( ) , ) targetScrapePoolSyncsCounter . WithLabelValues ( sp . config . JobName ) . Inc ( ) }

// Sync converts target groups into actual scrape targets and synchronizes
// the currently running scraper with the resulting set and returns all scraped and dropped targets.

Sync converts target groups into actual scrape targets and synchronizes the currently running scraper with the resulting set and returns all scraped and dropped targets .


func (sp *scrapePool) sync(targets []*Target) {
	sp.mtx.Lock()
	defer sp.mtx.Unlock()

	var (
		uniqueTargets   = map[uint64]struct{}{}
		interval        = time.Duration(sp.config.ScrapeInterval)
		timeout         = time.Duration(sp.config.ScrapeTimeout)
		limit           = int(sp.config.SampleLimit)
		honorLabels     = sp.config.HonorLabels
		honorTimestamps = sp.config.HonorTimestamps
		mrc             = sp.config.MetricRelabelConfigs
	)

	for _, t := range targets {
		t := t
		hash := t.hash()
		uniqueTargets[hash] = struct{}{}

		if _, ok := sp.activeTargets[hash]; !ok {
			s := &targetScraper{Target: t, client: sp.client, timeout: timeout}
			l := sp.newLoop(scrapeLoopOptions{
				target:          t,
				scraper:         s,
				limit:           limit,
				honorLabels:     honorLabels,
				honorTimestamps: honorTimestamps,
				mrc:             mrc,
			})

			sp.activeTargets[hash] = t
			sp.loops[hash] = l

			go l.run(interval, timeout, nil)
		} else {
			// Need to keep the most updated labels information
			// for displaying it in the Service Discovery web page.
			sp.activeTargets[hash].SetDiscoveredLabels(t.DiscoveredLabels())
		}
	}

	var wg sync.WaitGroup

	// Stop and remove old targets and scraper loops.
	for hash := range sp.activeTargets {
		if _, ok := uniqueTargets[hash]; !ok {
			wg.Add(1)
			go func(l loop) {

				l.stop()

				wg.Done()
			}(sp.loops[hash])

			delete(sp.loops, hash)
			delete(sp.activeTargets, hash)
		}
	}

	// Wait for all potentially stopped scrapers to terminate.
	// This covers the case of flapping targets. If the server is under high load, a new scraper
	// may be active and tries to insert. The old scraper that didn't terminate yet could still
	// be inserting a previous sample set.
	wg.Wait()
}

// sync takes a list of potentially duplicated targets, deduplicates them, starts
// scrape loops for new targets, and stops scrape loops for disappeared targets.
// It returns after all stopped scrape loops terminated.

sync takes a list of potentially duplicated targets deduplicates them starts scrape loops for new targets and stops scrape loops for disappeared targets . It returns after all stopped scrape loops terminated .


func appender(app storage.Appender, limit int) storage.Appender {
	app = &timeLimitAppender{
		Appender: app,
		maxTime:  timestamp.FromTime(time.Now().Add(maxAheadTime)),
	}

	// The limit is applied after metrics are potentially dropped via relabeling.
	if limit > 0 {
		app = &limitAppender{
			Appender: app,
			limit:    limit,
		}
	}
	return app
}

// appender returns an appender for ingested samples from the target.

appender returns an appender for ingested samples from the target .


func Uname() string {
	buf := syscall.Utsname{}
	err := syscall.Uname(&buf)
	if err != nil {
		panic("syscall.Uname failed: " + err.Error())
	}

	str := "(" + charsToString(buf.Sysname[:])
	str += " " + charsToString(buf.Release[:])
	str += " " + charsToString(buf.Version[:])
	str += " " + charsToString(buf.Machine[:])
	str += " " + charsToString(buf.Nodename[:])
	str += " " + charsToString(buf.Domainname[:]) + ")"
	return str
}

func Uname ( ) string { buf := syscall . Utsname { } err := syscall . Uname ( & buf ) if err != nil { panic ( " " + err . Error ( ) ) } str := " " + charsToString ( buf . Sysname [ : ] ) str += " " + charsToString ( buf . Release [ : ] ) str += " " + charsToString ( buf . Version [ : ] ) str += " " + charsToString ( buf . Machine [ : ] ) str += " " + charsToString ( buf . Nodename [ : ] ) str += " " + charsToString ( buf . Domainname [ : ] ) + " " return str }

// Uname returns the uname of the host machine.

Uname returns the uname of the host machine .


func DecodeReadRequest(r *http.Request) (*prompb.ReadRequest, error) {
	compressed, err := ioutil.ReadAll(io.LimitReader(r.Body, decodeReadLimit))
	if err != nil {
		return nil, err
	}

	reqBuf, err := snappy.Decode(nil, compressed)
	if err != nil {
		return nil, err
	}

	var req prompb.ReadRequest
	if err := proto.Unmarshal(reqBuf, &req); err != nil {
		return nil, err
	}

	return &req, nil
}

func DecodeReadRequest ( r * http . Request ) ( * prompb . ReadRequest , error ) { compressed , err := ioutil . ReadAll ( io . LimitReader ( r . Body , decodeReadLimit ) ) if err != nil { return nil , err } reqBuf , err := snappy . Decode ( nil , compressed ) if err != nil { return nil , err } var req prompb . ReadRequest if err := proto . Unmarshal ( reqBuf , & req ) ; err != nil { return nil , err } return & req , nil }

// DecodeReadRequest reads a remote.Request from a http.Request.

DecodeReadRequest reads a remote . Request from a http . Request .


func EncodeReadResponse(resp *prompb.ReadResponse, w http.ResponseWriter) error {
	data, err := proto.Marshal(resp)
	if err != nil {
		return err
	}

	w.Header().Set("Content-Type", "application/x-protobuf")
	w.Header().Set("Content-Encoding", "snappy")

	compressed := snappy.Encode(nil, data)
	_, err = w.Write(compressed)
	return err
}

func EncodeReadResponse ( resp * prompb . ReadResponse , w http . ResponseWriter ) error { data , err := proto . Marshal ( resp ) if err != nil { return err } w . Header ( ) . Set ( " " , " " ) w . Header ( ) . Set ( " " , " " ) compressed := snappy . Encode ( nil , data ) _ , err = w . Write ( compressed ) return err }

// EncodeReadResponse writes a remote.Response to a http.ResponseWriter.

EncodeReadResponse writes a remote . Response to a http . ResponseWriter .


func ToQuery(from, to int64, matchers []*labels.Matcher, p *storage.SelectParams) (*prompb.Query, error) {
	ms, err := toLabelMatchers(matchers)
	if err != nil {
		return nil, err
	}

	var rp *prompb.ReadHints
	if p != nil {
		rp = &prompb.ReadHints{
			StepMs:  p.Step,
			Func:    p.Func,
			StartMs: p.Start,
			EndMs:   p.End,
		}
	}

	return &prompb.Query{
		StartTimestampMs: from,
		EndTimestampMs:   to,
		Matchers:         ms,
		Hints:            rp,
	}, nil
}

func ToQuery ( from , to int64 , matchers [ ] * labels . Matcher , p * storage . SelectParams ) ( * prompb . Query , error ) { ms , err := toLabelMatchers ( matchers ) if err != nil { return nil , err } var rp * prompb . ReadHints if p != nil { rp = & prompb . ReadHints { StepMs : p . Step , Func : p . Func , StartMs : p . Start , EndMs : p . End , } } return & prompb . Query { StartTimestampMs : from , EndTimestampMs : to , Matchers : ms , Hints : rp , } , nil }


func FromQuery(req *prompb.Query) (int64, int64, []*labels.Matcher, *storage.SelectParams, error) {
	matchers, err := fromLabelMatchers(req.Matchers)
	if err != nil {
		return 0, 0, nil, nil, err
	}
	var selectParams *storage.SelectParams
	if req.Hints != nil {
		selectParams = &storage.SelectParams{
			Start: req.Hints.StartMs,
			End:   req.Hints.EndMs,
			Step:  req.Hints.StepMs,
			Func:  req.Hints.Func,
		}
	}

	return req.StartTimestampMs, req.EndTimestampMs, matchers, selectParams, nil
}

func FromQuery ( req * prompb . Query ) ( int64 , int64 , [ ] * labels . Matcher , * storage . SelectParams , error ) { matchers , err := fromLabelMatchers ( req . Matchers ) if err != nil { return 0 , 0 , nil , nil , err } var selectParams * storage . SelectParams if req . Hints != nil { selectParams = & storage . SelectParams { Start : req . Hints . StartMs , End : req . Hints . EndMs , Step : req . Hints . StepMs , Func : req . Hints . Func , } } return req . StartTimestampMs , req . EndTimestampMs , matchers , selectParams , nil }


func ToQueryResult(ss storage.SeriesSet, sampleLimit int) (*prompb.QueryResult, error) {
	numSamples := 0
	resp := &prompb.QueryResult{}
	for ss.Next() {
		series := ss.At()
		iter := series.Iterator()
		samples := []prompb.Sample{}

		for iter.Next() {
			numSamples++
			if sampleLimit > 0 && numSamples > sampleLimit {
				return nil, HTTPError{
					msg:    fmt.Sprintf("exceeded sample limit (%d)", sampleLimit),
					status: http.StatusBadRequest,
				}
			}
			ts, val := iter.At()
			samples = append(samples, prompb.Sample{
				Timestamp: ts,
				Value:     val,
			})
		}
		if err := iter.Err(); err != nil {
			return nil, err
		}

		resp.Timeseries = append(resp.Timeseries, &prompb.TimeSeries{
			Labels:  labelsToLabelsProto(series.Labels()),
			Samples: samples,
		})
	}
	if err := ss.Err(); err != nil {
		return nil, err
	}
	return resp, nil
}

func ToQueryResult ( ss storage . SeriesSet , sampleLimit int ) ( * prompb . QueryResult , error ) { numSamples := 0 resp := & prompb . QueryResult { } for ss . Next ( ) { series := ss . At ( ) iter := series . Iterator ( ) samples := [ ] prompb . Sample { } for iter . Next ( ) { numSamples ++ if sampleLimit > 0 && numSamples > sampleLimit { return nil , HTTPError { msg : fmt . Sprintf ( " " , sampleLimit ) , status : http . StatusBadRequest , } } ts , val := iter . At ( ) samples = append ( samples , prompb . Sample { Timestamp : ts , Value : val , } ) } if err := iter . Err ( ) ; err != nil { return nil , err } resp . Timeseries = append ( resp . Timeseries , & prompb . TimeSeries { Labels : labelsToLabelsProto ( series . Labels ( ) ) , Samples : samples , } ) } if err := ss . Err ( ) ; err != nil { return nil , err } return resp , nil }

// ToQueryResult builds a QueryResult proto.

ToQueryResult builds a QueryResult proto .


func FromQueryResult(res *prompb.QueryResult) storage.SeriesSet {
	series := make([]storage.Series, 0, len(res.Timeseries))
	for _, ts := range res.Timeseries {
		labels := labelProtosToLabels(ts.Labels)
		if err := validateLabelsAndMetricName(labels); err != nil {
			return errSeriesSet{err: err}
		}

		series = append(series, &concreteSeries{
			labels:  labels,
			samples: ts.Samples,
		})
	}
	sort.Sort(byLabel(series))
	return &concreteSeriesSet{
		series: series,
	}
}

func FromQueryResult ( res * prompb . QueryResult ) storage . SeriesSet { series := make ( [ ] storage . Series , 0 , len ( res . Timeseries ) ) for _ , ts := range res . Timeseries { labels := labelProtosToLabels ( ts . Labels ) if err := validateLabelsAndMetricName ( labels ) ; err != nil { return errSeriesSet { err : err } } series = append ( series , & concreteSeries { labels : labels , samples : ts . Samples , } ) } sort . Sort ( byLabel ( series ) ) return & concreteSeriesSet { series : series , } }

// FromQueryResult unpacks a QueryResult proto.

FromQueryResult unpacks a QueryResult proto .


func (c *concreteSeriesIterator) Seek(t int64) bool {
	c.cur = sort.Search(len(c.series.samples), func(n int) bool {
		return c.series.samples[n].Timestamp >= t
	})
	return c.cur < len(c.series.samples)
}

func ( c * concreteSeriesIterator ) Seek ( t int64 ) bool { c . cur = sort . Search ( len ( c . series . samples ) , func ( n int ) bool { return c . series . samples [ n ] . Timestamp >= t } ) return c . cur < len ( c . series . samples ) }

// Seek implements storage.SeriesIterator.

Seek implements storage . SeriesIterator .


func (c *concreteSeriesIterator) At() (t int64, v float64) {
	s := c.series.samples[c.cur]
	return s.Timestamp, s.Value
}

func ( c * concreteSeriesIterator ) At ( ) ( t int64 , v float64 ) { s := c . series . samples [ c . cur ] return s . Timestamp , s . Value }

// At implements storage.SeriesIterator.

At implements storage . SeriesIterator .


func (c *concreteSeriesIterator) Next() bool {
	c.cur++
	return c.cur < len(c.series.samples)
}

func ( c * concreteSeriesIterator ) Next ( ) bool { c . cur ++ return c . cur < len ( c . series . samples ) }

// Next implements storage.SeriesIterator.

Next implements storage . SeriesIterator .


func NewBufferIterator(it SeriesIterator, delta int64) *BufferedSeriesIterator {
	bit := &BufferedSeriesIterator{
		buf:   newSampleRing(delta, 16),
		delta: delta,
	}
	bit.Reset(it)

	return bit
}

func NewBufferIterator ( it SeriesIterator , delta int64 ) * BufferedSeriesIterator { bit := & BufferedSeriesIterator { buf : newSampleRing ( delta , 16 ) , delta : delta , } bit . Reset ( it ) return bit }

// NewBufferIterator returns a new iterator that buffers the values within the
// time range of the current element and the duration of delta before.

NewBufferIterator returns a new iterator that buffers the values within the time range of the current element and the duration of delta before .


func (b *BufferedSeriesIterator) Reset(it SeriesIterator) {
	b.it = it
	b.lastTime = math.MinInt64
	b.ok = true
	b.buf.reset()
	b.buf.delta = b.delta
	it.Next()
}

func ( b * BufferedSeriesIterator ) Reset ( it SeriesIterator ) { b . it = it b . lastTime = math . MinInt64 b . ok = true b . buf . reset ( ) b . buf . delta = b . delta it . Next ( ) }

// Reset re-uses the buffer with a new iterator, resetting the buffered time
// delta to its original value.

Reset re - uses the buffer with a new iterator resetting the buffered time delta to its original value .


func (b *BufferedSeriesIterator) ReduceDelta(delta int64) bool {
	return b.buf.reduceDelta(delta)
}

func ( b * BufferedSeriesIterator ) ReduceDelta ( delta int64 ) bool { return b . buf . reduceDelta ( delta ) }

// ReduceDelta lowers the buffered time delta, for the current SeriesIterator only.

ReduceDelta lowers the buffered time delta for the current SeriesIterator only .


func (b *BufferedSeriesIterator) PeekBack(n int) (t int64, v float64, ok bool) {
	return b.buf.nthLast(n)
}

func ( b * BufferedSeriesIterator ) PeekBack ( n int ) ( t int64 , v float64 , ok bool ) { return b . buf . nthLast ( n ) }

// PeekBack returns the nth previous element of the iterator. If there is none buffered,
// ok is false.

PeekBack returns the nth previous element of the iterator . If there is none buffered ok is false .


func (b *BufferedSeriesIterator) Seek(t int64) bool {
	t0 := t - b.buf.delta

	// If the delta would cause us to seek backwards, preserve the buffer
	// and just continue regular advancement while filling the buffer on the way.
	if t0 > b.lastTime {
		b.buf.reset()

		b.ok = b.it.Seek(t0)
		if !b.ok {
			return false
		}
		b.lastTime, _ = b.Values()
	}

	if b.lastTime >= t {
		return true
	}
	for b.Next() {
		if b.lastTime >= t {
			return true
		}
	}

	return false
}

// Seek advances the iterator to the element at time t or greater.

Seek advances the iterator to the element at time t or greater .


func (b *BufferedSeriesIterator) Next() bool {
	if !b.ok {
		return false
	}

	// Add current element to buffer before advancing.
	b.buf.add(b.it.At())

	b.ok = b.it.Next()
	if b.ok {
		b.lastTime, _ = b.Values()
	}

	return b.ok
}

// Next advances the iterator to the next element.

Next advances the iterator to the next element .


func (r *sampleRing) iterator() SeriesIterator {
	r.it.r = r
	r.it.i = -1
	return &r.it
}

func ( r * sampleRing ) iterator ( ) SeriesIterator { r . it . r = r r . it . i = - 1 return & r . it }

// Returns the current iterator. Invalidates previously returned iterators.

Returns the current iterator . Invalidates previously returned iterators .


func (r *sampleRing) reduceDelta(delta int64) bool {
	if delta > r.delta {
		return false
	}
	r.delta = delta

	if r.l == 0 {
		return true
	}

	// Free head of the buffer of samples that just fell out of the range.
	l := len(r.buf)
	tmin := r.buf[r.i].t - delta
	for r.buf[r.f].t < tmin {
		r.f++
		if r.f >= l {
			r.f -= l
		}
		r.l--
	}
	return true
}

// reduceDelta lowers the buffered time delta, dropping any samples that are
// out of the new delta range.

reduceDelta lowers the buffered time delta dropping any samples that are out of the new delta range .


func (r *sampleRing) nthLast(n int) (int64, float64, bool) {
	if n > r.l {
		return 0, 0, false
	}
	t, v := r.at(r.l - n)
	return t, v, true
}

func ( r * sampleRing ) nthLast ( n int ) ( int64 , float64 , bool ) { if n > r . l { return 0 , 0 , false } t , v := r . at ( r . l - n ) return t , v , true }

// nthLast returns the nth most recent element added to the ring.

nthLast returns the nth most recent element added to the ring .


func (l *openMetricsLexer) next() byte {
	l.i++
	if l.i >= len(l.b) {
		l.err = io.EOF
		return byte(tEOF)
	}
	// Lex struggles with null bytes. If we are in a label value or help string, where
	// they are allowed, consume them here immediately.
	for l.b[l.i] == 0 && (l.state == sLValue || l.state == sMeta2 || l.state == sComment) {
		l.i++
		if l.i >= len(l.b) {
			l.err = io.EOF
			return byte(tEOF)
		}
	}
	return l.b[l.i]
}

// next advances the openMetricsLexer to the next character.

next advances the openMetricsLexer to the next character .


func (p *OpenMetricsParser) Unit() ([]byte, []byte) {
	// The Prometheus format does not have units.
	return p.l.b[p.offsets[0]:p.offsets[1]], p.text
}

// Unit returns the metric name and unit in the current entry.
// Must only be called after Next returned a unit entry.
// The returned byte slices become invalid after the next call to Next.

Unit returns the metric name and unit in the current entry . Must only be called after Next returned a unit entry . The returned byte slices become invalid after the next call to Next .


func (p *OpenMetricsParser) Metric(l *labels.Labels) string {
	// Allocate the full immutable string immediately, so we just
	// have to create references on it below.
	s := string(p.series)

	*l = append(*l, labels.Label{
		Name:  labels.MetricName,
		Value: s[:p.offsets[0]-p.start],
	})

	for i := 1; i < len(p.offsets); i += 4 {
		a := p.offsets[i] - p.start
		b := p.offsets[i+1] - p.start
		c := p.offsets[i+2] - p.start
		d := p.offsets[i+3] - p.start

		// Replacer causes allocations. Replace only when necessary.
		if strings.IndexByte(s[c:d], byte('\\')) >= 0 {
			*l = append(*l, labels.Label{Name: s[a:b], Value: lvalReplacer.Replace(s[c:d])})
			continue
		}
		*l = append(*l, labels.Label{Name: s[a:b], Value: s[c:d]})
	}

	// Sort labels. We can skip the first entry since the metric name is
	// already at the right place.
	sort.Sort((*l)[1:])

	return s
}

// Metric writes the labels of the current sample into the passed labels.
// It returns the string from which the metric was parsed.

Metric writes the labels of the current sample into the passed labels . It returns the string from which the metric was parsed .


func coalesceBuckets(buckets buckets) buckets {
	last := buckets[0]
	i := 0
	for _, b := range buckets[1:] {
		if b.upperBound == last.upperBound {
			last.count += b.count
		} else {
			buckets[i] = last
			last = b
			i++
		}
	}
	buckets[i] = last
	return buckets[:i+1]
}

func coalesceBuckets ( buckets buckets ) buckets { last := buckets [ 0 ] i := 0 for _ , b := range buckets [ 1 : ] { if b . upperBound == last . upperBound { last . count += b . count } else { buckets [ i ] = last last = b i ++ } } buckets [ i ] = last return buckets [ : i + 1 ] }

// coalesceBuckets merges buckets with the same upper bound.
//
// The input buckets must be sorted.

coalesceBuckets merges buckets with the same upper bound . The input buckets must be sorted .


func (t *TimestampCollector) Collect(ch chan<- prometheus.Metric) {
	// New map to dedup filenames.
	uniqueFiles := make(map[string]float64)
	t.lock.RLock()
	for fileSD := range t.discoverers {
		fileSD.lock.RLock()
		for filename, timestamp := range fileSD.timestamps {
			uniqueFiles[filename] = timestamp
		}
		fileSD.lock.RUnlock()
	}
	t.lock.RUnlock()
	for filename, timestamp := range uniqueFiles {
		ch <- prometheus.MustNewConstMetric(
			t.Description,
			prometheus.GaugeValue,
			timestamp,
			filename,
		)
	}
}

func
(
t
*
TimestampCollector
)
Collect
(
ch
chan
<-
prometheus
.
Metric
)
{
// New map to dedup filenames.
uniqueFiles
:=
make
(
map
[
string
]
float64
)
t
.
lock
.
RLock
(
)
for
fileSD
:=
range
t
.
discoverers
{
fileSD
.
lock
.
RLock
(
)
for
filename
,
timestamp
:=
range
fileSD
.
timestamps
{
uniqueFiles
[
filename
]
=
timestamp
}
fileSD
.
lock
.
RUnlock
(
)
}
t
.
lock
.
RUnlock
(
)
for
filename
,
timestamp
:=
range
uniqueFiles
{
ch
<-
prometheus
.
MustNewConstMetric
(
t
.
Description
,
prometheus
.
GaugeValue
,
timestamp
,
filename
,
)
}
}

// Collect creates constant metrics for each file with last modified time of the file.

Collect creates constant metrics for each file with last modified time of the file .


func NewTimestampCollector() *TimestampCollector {
	return &TimestampCollector{
		Description: prometheus.NewDesc(
			"prometheus_sd_file_mtime_seconds",
			"Timestamp (mtime) of files read by FileSD. Timestamp is set at read time.",
			[]string{"filename"},
			nil,
		),
		discoverers: make(map[*Discovery]struct{}),
	}
}

func NewTimestampCollector ( ) * TimestampCollector { return & TimestampCollector { Description : prometheus . NewDesc ( " " , " " , [ ] string { " " } , nil , ) , discoverers : make ( map [ * Discovery ] struct { } ) , } }

// NewTimestampCollector creates a TimestampCollector.

NewTimestampCollector creates a TimestampCollector .


func NewDiscovery(conf *SDConfig, logger log.Logger) *Discovery {
	if logger == nil {
		logger = log.NewNopLogger()
	}

	disc := &Discovery{
		paths:      conf.Files,
		interval:   time.Duration(conf.RefreshInterval),
		timestamps: make(map[string]float64),
		logger:     logger,
	}
	fileSDTimeStamp.addDiscoverer(disc)
	return disc
}

func NewDiscovery ( conf * SDConfig , logger log . Logger ) * Discovery { if logger == nil { logger = log . NewNopLogger ( ) } disc := & Discovery { paths : conf . Files , interval : time . Duration ( conf . RefreshInterval ) , timestamps : make ( map [ string ] float64 ) , logger : logger , } fileSDTimeStamp . addDiscoverer ( disc ) return disc }

// NewDiscovery returns a new file discovery for the given paths.

NewDiscovery returns a new file discovery for the given paths .


func (d *Discovery) listFiles() []string {
	var paths []string
	for _, p := range d.paths {
		files, err := filepath.Glob(p)
		if err != nil {
			level.Error(d.logger).Log("msg", "Error expanding glob", "glob", p, "err", err)
			continue
		}
		paths = append(paths, files...)
	}
	return paths
}

func ( d * Discovery ) listFiles ( ) [ ] string { var paths [ ] string for _ , p := range d . paths { files , err := filepath . Glob ( p ) if err != nil { level . Error ( d . logger ) . Log ( " " , " " , " " , p , " " , err ) continue } paths = append ( paths , files ... ) } return paths }

// listFiles returns a list of all files that match the configured patterns.

listFiles returns a list of all files that match the configured patterns .


func (d *Discovery) watchFiles() {
	if d.watcher == nil {
		panic("no watcher configured")
	}
	for _, p := range d.paths {
		if idx := strings.LastIndex(p, "/"); idx > -1 {
			p = p[:idx]
		} else {
			p = "./"
		}
		if err := d.watcher.Add(p); err != nil {
			level.Error(d.logger).Log("msg", "Error adding file watch", "path", p, "err", err)
		}
	}
}

func ( d * Discovery ) watchFiles ( ) { if d . watcher == nil { panic ( " " ) } for _ , p := range d . paths { if idx := strings . LastIndex ( p , " " ) ; idx > - 1 { p = p [ : idx ] } else { p = " " } if err := d . watcher . Add ( p ) ; err != nil { level . Error ( d . logger ) . Log ( " " , " " , " " , p , " " , err ) } } }

// watchFiles sets watches on all full paths or directories that were configured for
// this file discovery.

watchFiles sets watches on all full paths or directories that were configured for this file discovery .


func (d *Discovery) stop() {
	level.Debug(d.logger).Log("msg", "Stopping file discovery...", "paths", fmt.Sprintf("%v", d.paths))

	done := make(chan struct{})
	defer close(done)

	fileSDTimeStamp.removeDiscoverer(d)

	// Closing the watcher will deadlock unless all events and errors are drained.
	go func() {
		for {
			select {
			case <-d.watcher.Errors:
			case <-d.watcher.Events:
				// Drain all events and errors.
			case <-done:
				return
			}
		}
	}()
	if err := d.watcher.Close(); err != nil {
		level.Error(d.logger).Log("msg", "Error closing file watcher", "paths", fmt.Sprintf("%v", d.paths), "err", err)
	}

	level.Debug(d.logger).Log("msg", "File discovery stopped")
}


func (d *Discovery) refresh(ctx context.Context, ch chan<- []*targetgroup.Group) {
	t0 := time.Now()
	defer func() {
		fileSDScanDuration.Observe(time.Since(t0).Seconds())
	}()
	ref := map[string]int{}
	for _, p := range d.listFiles() {
		tgroups, err := d.readFile(p)
		if err != nil {
			fileSDReadErrorsCount.Inc()

			level.Error(d.logger).Log("msg", "Error reading file", "path", p, "err", err)
			// Prevent deletion down below.
			ref[p] = d.lastRefresh[p]
			continue
		}
		select {
		case ch <- tgroups:
		case <-ctx.Done():
			return
		}

		ref[p] = len(tgroups)
	}
	// Send empty updates for sources that disappeared.
	for f, n := range d.lastRefresh {
		m, ok := ref[f]
		if !ok || n > m {
			level.Debug(d.logger).Log("msg", "file_sd refresh found file that should be removed", "file", f)
			d.deleteTimestamp(f)
			for i := m; i < n; i++ {
				select {
				case ch <- []*targetgroup.Group{{Source: fileSource(f, i)}}:
				case <-ctx.Done():
					return
				}
			}
		}
	}
	d.lastRefresh = ref

	d.watchFiles()
}

// refresh reads all files matching the discovery's patterns and sends the respective
// updated target groups through the channel.

refresh reads all files matching the discovery s patterns and sends the respective updated target groups through the channel .


func (d *Discovery) readFile(filename string) ([]*targetgroup.Group, error) {
	fd, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	content, err := ioutil.ReadAll(fd)
	if err != nil {
		return nil, err
	}

	info, err := fd.Stat()
	if err != nil {
		return nil, err
	}

	var targetGroups []*targetgroup.Group

	switch ext := filepath.Ext(filename); strings.ToLower(ext) {
	case ".json":
		if err := json.Unmarshal(content, &targetGroups); err != nil {
			return nil, err
		}
	case ".yml", ".yaml":
		if err := yaml.UnmarshalStrict(content, &targetGroups); err != nil {
			return nil, err
		}
	default:
		panic(errors.Errorf("discovery.File.readFile: unhandled file extension %q", ext))
	}

	for i, tg := range targetGroups {
		if tg == nil {
			err = errors.New("nil target group item found")
			return nil, err
		}

		tg.Source = fileSource(filename, i)
		if tg.Labels == nil {
			tg.Labels = model.LabelSet{}
		}
		tg.Labels[fileSDFilepathLabel] = model.LabelValue(filename)
	}

	d.writeTimestamp(filename, float64(info.ModTime().Unix()))

	return targetGroups, nil
}

func ( d * Discovery ) readFile ( filename string ) ( [ ] * targetgroup . Group , error ) { fd , err := os . Open ( filename ) if err != nil { return nil , err } defer fd . Close ( ) content , err := ioutil . ReadAll ( fd ) if err != nil { return nil , err } info , err := fd . Stat ( ) if err != nil { return nil , err } var targetGroups [ ] * targetgroup . Group switch ext := filepath . Ext ( filename ) ; strings . ToLower ( ext ) { case " " : if err := json . Unmarshal ( content , & targetGroups ) ; err != nil { return nil , err } case " " , " " : if err := yaml . UnmarshalStrict ( content , & targetGroups ) ; err != nil { return nil , err } default : panic ( errors . Errorf ( " " , ext ) ) } for i , tg := range targetGroups { if tg == nil { err = errors . New ( " " ) return nil , err } tg . Source = fileSource ( filename , i ) if tg . Labels == nil { tg . Labels = model . LabelSet { } } tg . Labels [ fileSDFilepathLabel ] = model . LabelValue ( filename ) } d . writeTimestamp ( filename , float64 ( info . ModTime ( ) . Unix ( ) ) ) return targetGroups , nil }

// readFile reads a JSON or YAML list of targets groups from the file, depending on its
// file extension. It returns full configuration target groups.

readFile reads a JSON or YAML list of targets groups from the file depending on its file extension . It returns full configuration target groups .


func fileSource(filename string, i int) string {
	return fmt.Sprintf("%s:%d", filename, i)
}

func fileSource ( filename string , i int ) string { return fmt . Sprintf ( " " , filename , i ) }

// fileSource returns a source ID for the i-th target group in the file.

fileSource returns a source ID for the i - th target group in the file .


func NewRecordingRule(name string, vector promql.Expr, lset labels.Labels) *RecordingRule {
	return &RecordingRule{
		name:   name,
		vector: vector,
		health: HealthUnknown,
		labels: lset,
	}
}

func NewRecordingRule ( name string , vector promql . Expr , lset labels . Labels ) * RecordingRule { return & RecordingRule { name : name , vector : vector , health : HealthUnknown , labels : lset , } }

// NewRecordingRule returns a new recording rule.

NewRecordingRule returns a new recording rule .


func (rule *RecordingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, _ *url.URL) (promql.Vector, error) {
	vector, err := query(ctx, rule.vector.String(), ts)
	if err != nil {
		rule.SetHealth(HealthBad)
		rule.SetLastError(err)
		return nil, err
	}
	// Override the metric name and labels.
	for i := range vector {
		sample := &vector[i]

		lb := labels.NewBuilder(sample.Metric)

		lb.Set(labels.MetricName, rule.name)

		for _, l := range rule.labels {
			if l.Value == "" {
				lb.Del(l.Name)
			} else {
				lb.Set(l.Name, l.Value)
			}
		}

		sample.Metric = lb.Labels()
	}
	rule.SetHealth(HealthGood)
	rule.SetLastError(err)
	return vector, nil
}

func
(
rule
*
RecordingRule
)
Eval
(
ctx
context
.
Context
,
ts
time
.
Time
,
query
QueryFunc
,
_
*
url
.
URL
)
(
promql
.
Vector
,
error
)
{
vector
,
err
:=
query
(
ctx
,
rule
.
vector
.
String
(
)
,
ts
)
if
err
!=
{
rule
.
SetHealth
(
HealthBad
)
rule
.
SetLastError
(
err
)
return
,
err
}
// Override the metric name and labels.
for
i
:=
range
vector
{
sample
:=
&
vector
[
i
]
lb
:=
labels
.
NewBuilder
(
sample
.
Metric
)
lb
.
Set
(
labels
.
MetricName
,
rule
.
name
)
for
_
,
l
:=
range
rule
.
labels
{
if
l
.
Value
==
"
"
{
lb
.
Del
(
l
.
Name
)
}
else
{
lb
.
Set
(
l
.
Name
,
l
.
Value
)
}
}
sample
.
Metric
=
lb
.
Labels
(
)
}
rule
.
SetHealth
(
HealthGood
)
rule
.
SetLastError
(
err
)
return
vector
,
}

// Eval evaluates the rule and then overrides the metric names and labels accordingly.

Eval evaluates the rule and then overrides the metric names and labels accordingly .


func (rule *RecordingRule) SetEvaluationDuration(dur time.Duration) {
	rule.mtx.Lock()
	defer rule.mtx.Unlock()
	rule.evaluationDuration = dur
}

func ( rule * RecordingRule ) SetEvaluationDuration ( dur time . Duration ) { rule . mtx . Lock ( ) defer rule . mtx . Unlock ( ) rule . evaluationDuration = dur }

// SetEvaluationDuration updates evaluationDuration to the time in seconds it took to evaluate the rule on its last evaluation.

SetEvaluationDuration updates evaluationDuration to the time in seconds it took to evaluate the rule on its last evaluation .


func (rule *RecordingRule) SetLastError(err error) {
	rule.mtx.Lock()
	defer rule.mtx.Unlock()
	rule.lastError = err
}

func ( rule * RecordingRule ) SetLastError ( err error ) { rule . mtx . Lock ( ) defer rule . mtx . Unlock ( ) rule . lastError = err }

// SetLastError sets the current error seen by the recording rule.

SetLastError sets the current error seen by the recording rule .


func (rule *RecordingRule) LastError() error {
	rule.mtx.Lock()
	defer rule.mtx.Unlock()
	return rule.lastError
}

func ( rule * RecordingRule ) LastError ( ) error { rule . mtx . Lock ( ) defer rule . mtx . Unlock ( ) return rule . lastError }

// LastError returns the last error seen by the recording rule.

LastError returns the last error seen by the recording rule .


func (rule *RecordingRule) SetHealth(health RuleHealth) {
	rule.mtx.Lock()
	defer rule.mtx.Unlock()
	rule.health = health
}

func ( rule * RecordingRule ) SetHealth ( health RuleHealth ) { rule . mtx . Lock ( ) defer rule . mtx . Unlock ( ) rule . health = health }

// SetHealth sets the current health of the recording rule.

SetHealth sets the current health of the recording rule .


func (rule *RecordingRule) Health() RuleHealth {
	rule.mtx.Lock()
	defer rule.mtx.Unlock()
	return rule.health
}

func ( rule * RecordingRule ) Health ( ) RuleHealth { rule . mtx . Lock ( ) defer rule . mtx . Unlock ( ) return rule . health }

// Health returns the current health of the recording rule.

Health returns the current health of the recording rule .


func (rule *RecordingRule) GetEvaluationDuration() time.Duration {
	rule.mtx.Lock()
	defer rule.mtx.Unlock()
	return rule.evaluationDuration
}

func ( rule * RecordingRule ) GetEvaluationDuration ( ) time . Duration { rule . mtx . Lock ( ) defer rule . mtx . Unlock ( ) return rule . evaluationDuration }

// GetEvaluationDuration returns the time in seconds it took to evaluate the recording rule.

GetEvaluationDuration returns the time in seconds it took to evaluate the recording rule .