func newAzureResourceFromID(id string, logger log.Logger) (azureResource, error) {
	// Resource IDs have the following format.
	// /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/PROVIDER/TYPE/NAME
	// or if embedded resource then
	// /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/PROVIDER/TYPE/NAME/TYPE/NAME
	s := strings.Split(id, "/")
	if len(s) != 9 && len(s) != 11 {
		err := errors.Errorf("invalid ID '%s'. Refusing to create azureResource", id)
		level.Error(logger).Log("err", err)
		return azureResource{}, err
	}

	return azureResource{
		Name:          strings.ToLower(s[8]),
		ResourceGroup: strings.ToLower(s[4]),
	}, nil
}

// Create a new azureResource object from an ID string.

Create a new azureResource object from an ID string .


func (t *Timer) String() string {
	return fmt.Sprintf("%s: %s", t.name, t.duration)
}

func ( t * Timer ) String ( ) string { return fmt . Sprintf ( " " , t . name , t . duration ) }

// Return a string representation of the Timer.

Return a string representation of the Timer .


func (t Timers) Swap(i, j int) {
	t[i], t[j] = t[j], t[i]
}

func ( t Timers ) Swap ( i , j int ) { t [ i ] , t [ j ] = t [ j ] , t [ i ] }


func (t *TimerGroup) String() string {
	timers := byCreationTimeSorter{}
	for _, timer := range t.timers {
		timers.Timers = append(timers.Timers, timer)
	}
	sort.Sort(timers)
	result := &bytes.Buffer{}
	for _, timer := range timers.Timers {
		fmt.Fprintf(result, "%s\n", timer)
	}
	return result.String()
}

func ( t * TimerGroup ) String ( ) string { timers := byCreationTimeSorter { } for _ , timer := range t . timers { timers . Timers = append ( timers . Timers , timer ) } sort . Sort ( timers ) result := & bytes . Buffer { } for _ , timer := range timers . Timers { fmt . Fprintf ( result , " \n " , timer ) } return result . String ( ) }

// Return a string representation of a TimerGroup.

Return a string representation of a TimerGroup .


func RegisterAdminHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
	return RegisterAdminHandlerClient(ctx, mux, NewAdminClient(conn))
}

func RegisterAdminHandler ( ctx context . Context , mux * runtime . ServeMux , conn * grpc . ClientConn ) error { return RegisterAdminHandlerClient ( ctx , mux , NewAdminClient ( conn ) ) }

// RegisterAdminHandler registers the http handlers for service Admin to "mux".
// The handlers forward requests to the grpc endpoint over "conn".

RegisterAdminHandler registers the http handlers for service Admin to mux . The handlers forward requests to the grpc endpoint over conn .


func ParseExpr(input string) (Expr, error) {
	p := newParser(input)

	expr, err := p.parseExpr()
	if err != nil {
		return nil, err
	}
	err = p.typecheck(expr)
	return expr, err
}

func ParseExpr ( input string ) ( Expr , error ) { p := newParser ( input ) expr , err := p . parseExpr ( ) if err != nil { return nil , err } err = p . typecheck ( expr ) return expr , err }

// ParseExpr returns the expression parsed from the input.

ParseExpr returns the expression parsed from the input .


func ParseMetric(input string) (m labels.Labels, err error) {
	p := newParser(input)
	defer p.recover(&err)

	m = p.metric()
	if p.peek().typ != ItemEOF {
		p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
	}
	return m, nil
}

func ParseMetric ( input string ) ( m labels . Labels , err error ) { p := newParser ( input ) defer p . recover ( & err ) m = p . metric ( ) if p . peek ( ) . typ != ItemEOF { p . errorf ( " " , p . lex . input [ p . lex . lastPos : ] ) } return m , nil }

// ParseMetric parses the input into a metric


func ParseMetricSelector(input string) (m []*labels.Matcher, err error) {
	p := newParser(input)
	defer p.recover(&err)

	name := ""
	if t := p.peek().typ; t == ItemMetricIdentifier || t == ItemIdentifier {
		name = p.next().val
	}
	vs := p.VectorSelector(name)
	if p.peek().typ != ItemEOF {
		p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
	}
	return vs.LabelMatchers, nil
}

func ParseMetricSelector ( input string ) ( m [ ] * labels . Matcher , err error ) { p := newParser ( input ) defer p . recover ( & err ) name := " " if t := p . peek ( ) . typ ; t == ItemMetricIdentifier || t == ItemIdentifier { name = p . next ( ) . val } vs := p . VectorSelector ( name ) if p . peek ( ) . typ != ItemEOF { p . errorf ( " " , p . lex . input [ p . lex . lastPos : ] ) } return vs . LabelMatchers , nil }

// ParseMetricSelector parses the provided textual metric selector into a list of
// label matchers.

ParseMetricSelector parses the provided textual metric selector into a list of label matchers .


func newParser(input string) *parser {
	p := &parser{
		lex: lex(input),
	}
	return p
}

func newParser ( input string ) * parser { p := & parser { lex : lex ( input ) , } return p }


func (p *parser) parseExpr() (expr Expr, err error) {
	defer p.recover(&err)

	for p.peek().typ != ItemEOF {
		if p.peek().typ == ItemComment {
			continue
		}
		if expr != nil {
			p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
		}
		expr = p.expr()
	}

	if expr == nil {
		p.errorf("no expression found in input")
	}
	return
}

func ( p * parser ) parseExpr ( ) ( expr Expr , err error ) { defer p . recover ( & err ) for p . peek ( ) . typ != ItemEOF { if p . peek ( ) . typ == ItemComment { continue } if expr != nil { p . errorf ( " " , p . lex . input [ p . lex . lastPos : ] ) } expr = p . expr ( ) } if expr == nil { p . errorf ( " " ) } return }

// parseExpr parses a single expression from the input.

parseExpr parses a single expression from the input .


func parseSeriesDesc(input string) (labels.Labels, []sequenceValue, error) {
	p := newParser(input)
	p.lex.seriesDesc = true

	return p.parseSeriesDesc()
}

func parseSeriesDesc ( input string ) ( labels . Labels , [ ] sequenceValue , error ) { p := newParser ( input ) p . lex . seriesDesc = true return p . parseSeriesDesc ( ) }

// parseSeriesDesc parses the description of a time series.

parseSeriesDesc parses the description of a time series .


func (p *parser) typecheck(node Node) (err error) {
	defer p.recover(&err)

	p.checkType(node)
	return nil
}

func ( p * parser ) typecheck ( node Node ) ( err error ) { defer p . recover ( & err ) p . checkType ( node ) return nil }

// typecheck checks correct typing of the parsed statements or expression.

typecheck checks correct typing of the parsed statements or expression .


func (p *parser) next() item {
	if p.peekCount > 0 {
		p.peekCount--
	} else {
		t := p.lex.nextItem()
		// Skip comments.
		for t.typ == ItemComment {
			t = p.lex.nextItem()
		}
		p.token[0] = t
	}
	if p.token[p.peekCount].typ == ItemError {
		p.errorf("%s", p.token[p.peekCount].val)
	}
	return p.token[p.peekCount]
}

func
(
p
*
parser
)
next
(
)
item
{
if
p
.
peekCount
>
0
{
p
.
peekCount
}
else
{
t
:=
p
.
lex
.
nextItem
(
)
// Skip comments.
for
t
.
typ
==
ItemComment
{
t
=
p
.
lex
.
nextItem
(
)
}
p
.
token
[
0
]
=
t
}
if
p
.
token
[
p
.
peekCount
]
.
typ
==
ItemError
{
p
.
errorf
(
"
"
,
p
.
token
[
p
.
peekCount
]
.
val
)
}
return
p
.
token
[
p
.
peekCount
]
}


func (p *parser) peek() item {
	if p.peekCount > 0 {
		return p.token[p.peekCount-1]
	}
	p.peekCount = 1

	t := p.lex.nextItem()
	// Skip comments.
	for t.typ == ItemComment {
		t = p.lex.nextItem()
	}
	p.token[0] = t
	return p.token[0]
}

func
(
p
*
parser
)
peek
(
)
item
{
if
p
.
peekCount
>
0
{
return
p
.
token
[
p
.
peekCount
1
]
}
p
.
peekCount
=
1
t
:=
p
.
lex
.
nextItem
(
)
// Skip comments.
for
t
.
typ
==
ItemComment
{
t
=
p
.
lex
.
nextItem
(
)
}
p
.
token
[
0
]
=
t
return
p
.
token
[
0
]
}

// peek returns but does not consume the next token.

peek returns but does not consume the next token .


func (p *parser) errorf(format string, args ...interface{}) {
	p.error(errors.Errorf(format, args...))
}

func ( p * parser ) errorf ( format string , args ... interface { } ) { p . error ( errors . Errorf ( format , args ... ) ) }

// errorf formats the error and terminates processing.

errorf formats the error and terminates processing .


func (p *parser) error(err error) {
	perr := &ParseErr{
		Line: p.lex.lineNumber(),
		Pos:  p.lex.linePosition(),
		Err:  err,
	}
	if strings.Count(strings.TrimSpace(p.lex.input), "\n") == 0 {
		perr.Line = 0
	}
	panic(perr)
}

func ( p * parser ) error ( err error ) { perr := & ParseErr { Line : p . lex . lineNumber ( ) , Pos : p . lex . linePosition ( ) , Err : err , } if strings . Count ( strings . TrimSpace ( p . lex . input ) , " \n " ) == 0 { perr . Line = 0 } panic ( perr ) }


func (p *parser) expect(exp ItemType, context string) item {
	token := p.next()
	if token.typ != exp {
		p.errorf("unexpected %s in %s, expected %s", token.desc(), context, exp.desc())
	}
	return token
}

func ( p * parser ) expect ( exp ItemType , context string ) item { token := p . next ( ) if token . typ != exp { p . errorf ( " " , token . desc ( ) , context , exp . desc ( ) ) } return token }

// expect consumes the next token and guarantees it has the required type.

expect consumes the next token and guarantees it has the required type .


func (p *parser) expectOneOf(exp1, exp2 ItemType, context string) item {
	token := p.next()
	if token.typ != exp1 && token.typ != exp2 {
		p.errorf("unexpected %s in %s, expected %s or %s", token.desc(), context, exp1.desc(), exp2.desc())
	}
	return token
}

func ( p * parser ) expectOneOf ( exp1 , exp2 ItemType , context string ) item { token := p . next ( ) if token . typ != exp1 && token . typ != exp2 { p . errorf ( " " , token . desc ( ) , context , exp1 . desc ( ) , exp2 . desc ( ) ) } return token }

// expectOneOf consumes the next token and guarantees it has one of the required types.

expectOneOf consumes the next token and guarantees it has one of the required types .


func (p *parser) recover(errp *error) {
	e := recover()
	if _, ok := e.(runtime.Error); ok {
		// Print the stack trace but do not inhibit the running application.
		buf := make([]byte, 64<<10)
		buf = buf[:runtime.Stack(buf, false)]

		fmt.Fprintf(os.Stderr, "parser panic: %v\n%s", e, buf)
		*errp = errUnexpected
	} else if e != nil {
		*errp = e.(error)
	}
	p.lex.close()
}

// recover is the handler that turns panics into returns from the top level of Parse.

recover is the handler that turns panics into returns from the top level of Parse .


func (p *parser) expr() Expr {
	// Parse the starting expression.
	expr := p.unaryExpr()

	// Loop through the operations and construct a binary operation tree based
	// on the operators' precedence.
	for {
		// If the next token is not an operator the expression is done.
		op := p.peek().typ
		if !op.isOperator() {
			// Check for subquery.
			if op == ItemLeftBracket {
				expr = p.subqueryOrRangeSelector(expr, false)
				if s, ok := expr.(*SubqueryExpr); ok {
					// Parse optional offset.
					if p.peek().typ == ItemOffset {
						offset := p.offset()
						s.Offset = offset
					}
				}
			}
			return expr
		}
		p.next() // Consume operator.

		// Parse optional operator matching options. Its validity
		// is checked in the type-checking stage.
		vecMatching := &VectorMatching{
			Card: CardOneToOne,
		}
		if op.isSetOperator() {
			vecMatching.Card = CardManyToMany
		}

		returnBool := false
		// Parse bool modifier.
		if p.peek().typ == ItemBool {
			if !op.isComparisonOperator() {
				p.errorf("bool modifier can only be used on comparison operators")
			}
			p.next()
			returnBool = true
		}

		// Parse ON/IGNORING clause.
		if p.peek().typ == ItemOn || p.peek().typ == ItemIgnoring {
			if p.peek().typ == ItemOn {
				vecMatching.On = true
			}
			p.next()
			vecMatching.MatchingLabels = p.labels()

			// Parse grouping.
			if t := p.peek().typ; t == ItemGroupLeft || t == ItemGroupRight {
				p.next()
				if t == ItemGroupLeft {
					vecMatching.Card = CardManyToOne
				} else {
					vecMatching.Card = CardOneToMany
				}
				if p.peek().typ == ItemLeftParen {
					vecMatching.Include = p.labels()
				}
			}
		}

		for _, ln := range vecMatching.MatchingLabels {
			for _, ln2 := range vecMatching.Include {
				if ln == ln2 && vecMatching.On {
					p.errorf("label %q must not occur in ON and GROUP clause at once", ln)
				}
			}
		}

		// Parse the next operand.
		rhs := p.unaryExpr()

		// Assign the new root based on the precedence of the LHS and RHS operators.
		expr = p.balance(expr, op, rhs, vecMatching, returnBool)
	}
}


func (p *parser) number(val string) float64 {
	n, err := strconv.ParseInt(val, 0, 64)
	f := float64(n)
	if err != nil {
		f, err = strconv.ParseFloat(val, 64)
	}
	if err != nil {
		p.errorf("error parsing number: %s", err)
	}
	return f
}

func ( p * parser ) number ( val string ) float64 { n , err := strconv . ParseInt ( val , 0 , 64 ) f := float64 ( n ) if err != nil { f , err = strconv . ParseFloat ( val , 64 ) } if err != nil { p . errorf ( " " , err ) } return f }


func (p *parser) expectType(node Node, want ValueType, context string) {
	t := p.checkType(node)
	if t != want {
		p.errorf("expected type %s in %s, got %s", documentedType(want), context, documentedType(t))
	}
}

func ( p * parser ) expectType ( node Node , want ValueType , context string ) { t := p . checkType ( node ) if t != want { p . errorf ( " " , documentedType ( want ) , context , documentedType ( t ) ) } }

// expectType checks the type of the node and raises an error if it
// is not of the expected type.

expectType checks the type of the node and raises an error if it is not of the expected type .


func (s *Storage) Appender() (storage.Appender, error) {
	return &timestampTracker{
		storage: s,
	}, nil
}

func ( s * Storage ) Appender ( ) ( storage . Appender , error ) { return & timestampTracker { storage : s , } , nil }

// Appender implements scrape.Appendable.

Appender implements scrape . Appendable .


func (t *timestampTracker) Add(_ labels.Labels, ts int64, v float64) (uint64, error) {
	t.samples++
	if ts > t.highestTimestamp {
		t.highestTimestamp = ts
	}
	return 0, nil
}

func ( t * timestampTracker ) Add ( _ labels . Labels , ts int64 , v float64 ) ( uint64 , error ) { t . samples ++ if ts > t . highestTimestamp { t . highestTimestamp = ts } return 0 , nil }


func (t *timestampTracker) AddFast(l labels.Labels, _ uint64, ts int64, v float64) error {
	_, err := t.Add(l, ts, v)
	return err
}

func ( t * timestampTracker ) AddFast ( l labels . Labels , _ uint64 , ts int64 , v float64 ) error { _ , err := t . Add ( l , ts , v ) return err }


func (t *timestampTracker) Commit() error {
	t.storage.samplesIn.incr(t.samples)

	samplesIn.Add(float64(t.samples))
	highestTimestamp.Set(float64(t.highestTimestamp / 1000))
	return nil
}

func ( t * timestampTracker ) Commit ( ) error { t . storage . samplesIn . incr ( t . samples ) samplesIn . Add ( float64 ( t . samples ) ) highestTimestamp . Set ( float64 ( t . highestTimestamp / 1000 ) ) return nil }


func (p *problems) Add(mf dto.MetricFamily, text string) {
	*p = append(*p, Problem{
		Metric: mf.GetName(),
		Text:   text,
	})
}

func ( p * problems ) Add ( mf dto . MetricFamily , text string ) { * p = append ( * p , Problem { Metric : mf . GetName ( ) , Text : text , } ) }

// Add appends a new Problem to the slice for the specified metric, with
// the specified issue text.

Add appends a new Problem to the slice for the specified metric with the specified issue text .


func (l *Linter) Lint() ([]Problem, error) {
	// TODO(mdlayher): support for protobuf exposition format?
	d := expfmt.NewDecoder(l.r, expfmt.FmtText)

	var problems []Problem

	var mf dto.MetricFamily
	for {
		if err := d.Decode(&mf); err != nil {
			if err == io.EOF {
				break
			}

			return nil, err
		}

		problems = append(problems, lint(mf)...)
	}

	// Ensure deterministic output.
	sort.SliceStable(problems, func(i, j int) bool {
		if problems[i].Metric < problems[j].Metric {
			return true
		}

		return problems[i].Text < problems[j].Text
	})

	return problems, nil
}

// Lint performs a linting pass, returning a slice of Problems indicating any
// issues found in the metrics stream.  The slice is sorted by metric name
// and issue description.

Lint performs a linting pass returning a slice of Problems indicating any issues found in the metrics stream . The slice is sorted by metric name and issue description .


func lint(mf dto.MetricFamily) []Problem {
	fns := []func(mf dto.MetricFamily) []Problem{
		lintHelp,
		lintMetricUnits,
		lintCounter,
		lintHistogramSummaryReserved,
	}

	var problems []Problem
	for _, fn := range fns {
		problems = append(problems, fn(mf)...)
	}

	// TODO(mdlayher): lint rules for specific metrics types.
	return problems
}

// lint is the entry point for linting a single metric.

lint is the entry point for linting a single metric .


func lintHelp(mf dto.MetricFamily) []Problem {
	var problems problems

	// Expect all metrics to have help text available.
	if mf.Help == nil {
		problems.Add(mf, "no help text")
	}

	return problems
}

// lintHelp detects issues related to the help text for a metric.

lintHelp detects issues related to the help text for a metric .


func lintMetricUnits(mf dto.MetricFamily) []Problem {
	var problems problems

	unit, base, ok := metricUnits(*mf.Name)
	if !ok {
		// No known units detected.
		return nil
	}

	// Unit is already a base unit.
	if unit == base {
		return nil
	}

	problems.Add(mf, fmt.Sprintf("use base unit %q instead of %q", base, unit))

	return problems
}

func
lintMetricUnits
(
mf
dto
.
MetricFamily
)
[
]
Problem
{
var
problems
problems
unit
,
base
,
ok
:=
metricUnits
(
*
mf
.
Name
)
if
!
ok
{
// No known units detected.
return
}
// Unit is already a base unit.
if
unit
==
base
{
return
}
problems
.
Add
(
mf
,
fmt
.
Sprintf
(
"
"
,
base
,
unit
)
)
return
problems
}

// lintMetricUnits detects issues with metric unit names.

lintMetricUnits detects issues with metric unit names .


func lintCounter(mf dto.MetricFamily) []Problem {
	var problems problems

	isCounter := mf.GetType() == dto.MetricType_COUNTER
	isUntyped := mf.GetType() == dto.MetricType_UNTYPED
	hasTotalSuffix := strings.HasSuffix(mf.GetName(), "_total")

	switch {
	case isCounter && !hasTotalSuffix:
		problems.Add(mf, `counter metrics should have "_total" suffix`)
	case !isUntyped && !isCounter && hasTotalSuffix:
		problems.Add(mf, `non-counter metrics should not have "_total" suffix`)
	}

	return problems
}

// lintCounter detects issues specific to counters, as well as patterns that should
// only be used with counters.

lintCounter detects issues specific to counters as well as patterns that should only be used with counters .


func (c *Client) Write(samples model.Samples) error {
	conn, err := net.DialTimeout(c.transport, c.address, c.timeout)
	if err != nil {
		return err
	}
	defer conn.Close()

	var buf bytes.Buffer
	for _, s := range samples {
		k := pathFromMetric(s.Metric, c.prefix)
		t := float64(s.Timestamp.UnixNano()) / 1e9
		v := float64(s.Value)
		if math.IsNaN(v) || math.IsInf(v, 0) {
			level.Debug(c.logger).Log("msg", "cannot send value to Graphite, skipping sample", "value", v, "sample", s)
			continue
		}
		fmt.Fprintf(&buf, "%s %f %f\n", k, v, t)
	}

	_, err = conn.Write(buf.Bytes())
	return err
}

func ( c * Client ) Write ( samples model . Samples ) error { conn , err := net . DialTimeout ( c . transport , c . address , c . timeout ) if err != nil { return err } defer conn . Close ( ) var buf bytes . Buffer for _ , s := range samples { k := pathFromMetric ( s . Metric , c . prefix ) t := float64 ( s . Timestamp . UnixNano ( ) ) / 1e9 v := float64 ( s . Value ) if math . IsNaN ( v ) || math . IsInf ( v , 0 ) { level . Debug ( c . logger ) . Log ( " " , " " , " " , v , " " , s ) continue } fmt . Fprintf ( & buf , " \n " , k , v , t ) } _ , err = conn . Write ( buf . Bytes ( ) ) return err }

// Write sends a batch of samples to Graphite.

Write sends a batch of samples to Graphite .


func New(minSize, maxSize int, factor float64, makeFunc func(int) interface{}) *Pool {
	if minSize < 1 {
		panic("invalid minimum pool size")
	}
	if maxSize < 1 {
		panic("invalid maximum pool size")
	}
	if factor < 1 {
		panic("invalid factor")
	}

	var sizes []int

	for s := minSize; s <= maxSize; s = int(float64(s) * factor) {
		sizes = append(sizes, s)
	}

	p := &Pool{
		buckets: make([]sync.Pool, len(sizes)),
		sizes:   sizes,
		make:    makeFunc,
	}

	return p
}

func New ( minSize , maxSize int , factor float64 , makeFunc func ( int ) interface { } ) * Pool { if minSize < 1 { panic ( " " ) } if maxSize < 1 { panic ( " " ) } if factor < 1 { panic ( " " ) } var sizes [ ] int for s := minSize ; s <= maxSize ; s = int ( float64 ( s ) * factor ) { sizes = append ( sizes , s ) } p := & Pool { buckets : make ( [ ] sync . Pool , len ( sizes ) ) , sizes : sizes , make : makeFunc , } return p }

// New returns a new Pool with size buckets for minSize to maxSize
// increasing by the given factor.

New returns a new Pool with size buckets for minSize to maxSize increasing by the given factor .


func (p *Pool) Get(sz int) interface{} {
	for i, bktSize := range p.sizes {
		if sz > bktSize {
			continue
		}
		b := p.buckets[i].Get()
		if b == nil {
			b = p.make(bktSize)
		}
		return b
	}
	return p.make(sz)
}

func ( p * Pool ) Get ( sz int ) interface { } { for i , bktSize := range p . sizes { if sz > bktSize { continue } b := p . buckets [ i ] . Get ( ) if b == nil { b = p . make ( bktSize ) } return b } return p . make ( sz ) }

// Get returns a new byte slices that fits the given size.

Get returns a new byte slices that fits the given size .


func (p *Pool) Put(s interface{}) {
	slice := reflect.ValueOf(s)

	if slice.Kind() != reflect.Slice {
		panic(fmt.Sprintf("%+v is not a slice", slice))
	}
	for i, size := range p.sizes {
		if slice.Cap() > size {
			continue
		}
		p.buckets[i].Put(slice.Slice(0, 0).Interface())
		return
	}
}

func ( p * Pool ) Put ( s interface { } ) { slice := reflect . ValueOf ( s ) if slice . Kind ( ) != reflect . Slice { panic ( fmt . Sprintf ( " " , slice ) ) } for i , size := range p . sizes { if slice . Cap ( ) > size { continue } p . buckets [ i ] . Put ( slice . Slice ( 0 , 0 ) . Interface ( ) ) return } }

// Put adds a slice to the right bucket in the pool.

Put adds a slice to the right bucket in the pool .


func (m Matrix) TotalSamples() int {
	numSamples := 0
	for _, series := range m {
		numSamples += len(series.Points)
	}
	return numSamples
}

func ( m Matrix ) TotalSamples ( ) int { numSamples := 0 for _ , series := range m { numSamples += len ( series . Points ) } return numSamples }

// TotalSamples returns the total number of samples in the series within a matrix.

TotalSamples returns the total number of samples in the series within a matrix .


func (r *Result) Vector() (Vector, error) {
	if r.Err != nil {
		return nil, r.Err
	}
	v, ok := r.Value.(Vector)
	if !ok {
		return nil, errors.New("query result is not a Vector")
	}
	return v, nil
}

func ( r * Result ) Vector ( ) ( Vector , error ) { if r . Err != nil { return nil , r . Err } v , ok := r . Value . ( Vector ) if ! ok { return nil , errors . New ( " " ) } return v , nil }

// Vector returns a Vector if the result value is one. An error is returned if
// the result was an error or the result value is not a Vector.

Vector returns a Vector if the result value is one . An error is returned if the result was an error or the result value is not a Vector .


func (r *Result) Scalar() (Scalar, error) {
	if r.Err != nil {
		return Scalar{}, r.Err
	}
	v, ok := r.Value.(Scalar)
	if !ok {
		return Scalar{}, errors.New("query result is not a Scalar")
	}
	return v, nil
}

func ( r * Result ) Scalar ( ) ( Scalar , error ) { if r . Err != nil { return Scalar { } , r . Err } v , ok := r . Value . ( Scalar ) if ! ok { return Scalar { } , errors . New ( " " ) } return v , nil }

// Scalar returns a Scalar value. An error is returned if
// the result was an error or the result value is not a Scalar.

Scalar returns a Scalar value . An error is returned if the result was an error or the result value is not a Scalar .


func NewDiscovery(conf *SDConfig, logger log.Logger) *Discovery {
	creds := credentials.NewStaticCredentials(conf.AccessKey, string(conf.SecretKey), "")
	if conf.AccessKey == "" && conf.SecretKey == "" {
		creds = nil
	}
	if logger == nil {
		logger = log.NewNopLogger()
	}
	d := &Discovery{
		aws: &aws.Config{
			Endpoint:    &conf.Endpoint,
			Region:      &conf.Region,
			Credentials: creds,
		},
		profile:  conf.Profile,
		roleARN:  conf.RoleARN,
		filters:  conf.Filters,
		interval: time.Duration(conf.RefreshInterval),
		port:     conf.Port,
	}
	d.Discovery = refresh.NewDiscovery(
		logger,
		"ec2",
		time.Duration(conf.RefreshInterval),
		d.refresh,
	)
	return d
}

func NewDiscovery ( conf * SDConfig , logger log . Logger ) * Discovery { creds := credentials . NewStaticCredentials ( conf . AccessKey , string ( conf . SecretKey ) , " " ) if conf . AccessKey == " " && conf . SecretKey == " " { creds = nil } if logger == nil { logger = log . NewNopLogger ( ) } d := & Discovery { aws : & aws . Config { Endpoint : & conf . Endpoint , Region : & conf . Region , Credentials : creds , } , profile : conf . Profile , roleARN : conf . RoleARN , filters : conf . Filters , interval : time . Duration ( conf . RefreshInterval ) , port : conf . Port , } d . Discovery = refresh . NewDiscovery ( logger , " " , time . Duration ( conf . RefreshInterval ) , d . refresh , ) return d }

// NewDiscovery returns a new EC2Discovery which periodically refreshes its targets.

NewDiscovery returns a new EC2Discovery which periodically refreshes its targets .


func NewQueueManager(logger log.Logger, walDir string, samplesIn *ewmaRate, cfg config.QueueConfig, externalLabels labels.Labels, relabelConfigs []*relabel.Config, client StorageClient, flushDeadline time.Duration) *QueueManager {
	if logger == nil {
		logger = log.NewNopLogger()
	}

	name := client.Name()
	logger = log.With(logger, "queue", name)
	t := &QueueManager{
		logger:         logger,
		flushDeadline:  flushDeadline,
		cfg:            cfg,
		externalLabels: externalLabels,
		relabelConfigs: relabelConfigs,
		client:         client,

		seriesLabels:         make(map[uint64][]prompb.Label),
		seriesSegmentIndexes: make(map[uint64]int),
		droppedSeries:        make(map[uint64]struct{}),

		numShards:   cfg.MinShards,
		reshardChan: make(chan int),
		quit:        make(chan struct{}),

		samplesIn:          samplesIn,
		samplesDropped:     newEWMARate(ewmaWeight, shardUpdateDuration),
		samplesOut:         newEWMARate(ewmaWeight, shardUpdateDuration),
		samplesOutDuration: newEWMARate(ewmaWeight, shardUpdateDuration),
	}

	t.watcher = NewWALWatcher(logger, name, t, walDir)
	t.shards = t.newShards()

	return t
}

func NewQueueManager ( logger log . Logger , walDir string , samplesIn * ewmaRate , cfg config . QueueConfig , externalLabels labels . Labels , relabelConfigs [ ] * relabel . Config , client StorageClient , flushDeadline time . Duration ) * QueueManager { if logger == nil { logger = log . NewNopLogger ( ) } name := client . Name ( ) logger = log . With ( logger , " " , name ) t := & QueueManager { logger : logger , flushDeadline : flushDeadline , cfg : cfg , externalLabels : externalLabels , relabelConfigs : relabelConfigs , client : client , seriesLabels : make ( map [ uint64 ] [ ] prompb . Label ) , seriesSegmentIndexes : make ( map [ uint64 ] int ) , droppedSeries : make ( map [ uint64 ] struct { } ) , numShards : cfg . MinShards , reshardChan : make ( chan int ) , quit : make ( chan struct { } ) , samplesIn : samplesIn , samplesDropped : newEWMARate ( ewmaWeight , shardUpdateDuration ) , samplesOut : newEWMARate ( ewmaWeight , shardUpdateDuration ) , samplesOutDuration : newEWMARate ( ewmaWeight , shardUpdateDuration ) , } t . watcher = NewWALWatcher ( logger , name , t , walDir ) t . shards = t . newShards ( ) return t }

// NewQueueManager builds a new QueueManager.

NewQueueManager builds a new QueueManager .


func (t *QueueManager) Append(s []tsdb.RefSample) bool {
	type enqueuable struct {
		ts  prompb.TimeSeries
		ref uint64
	}

	tempSamples := make([]enqueuable, 0, len(s))
	t.seriesMtx.Lock()
	for _, sample := range s {
		// If we have no labels for the series, due to relabelling or otherwise, don't send the sample.
		if _, ok := t.seriesLabels[sample.Ref]; !ok {
			t.droppedSamplesTotal.Inc()
			t.samplesDropped.incr(1)
			if _, ok := t.droppedSeries[sample.Ref]; !ok {
				level.Info(t.logger).Log("msg", "dropped sample for series that was not explicitly dropped via relabelling", "ref", sample.Ref)
			}
			continue
		}
		tempSamples = append(tempSamples, enqueuable{
			ts: prompb.TimeSeries{
				Labels: t.seriesLabels[sample.Ref],
				Samples: []prompb.Sample{
					prompb.Sample{
						Value:     float64(sample.V),
						Timestamp: sample.T,
					},
				},
			},
			ref: sample.Ref,
		})
	}
	t.seriesMtx.Unlock()

outer:
	for _, sample := range tempSamples {
		// This will only loop if the queues are being resharded.
		backoff := t.cfg.MinBackoff
		for {
			select {
			case <-t.quit:
				return false
			default:
			}

			if t.shards.enqueue(sample.ref, sample.ts) {
				continue outer
			}

			t.enqueueRetriesMetric.Inc()
			time.Sleep(time.Duration(backoff))
			backoff = backoff * 2
			if backoff > t.cfg.MaxBackoff {
				backoff = t.cfg.MaxBackoff
			}
		}
	}
	return true
}

// Append queues a sample to be sent to the remote storage. Blocks until all samples are
// enqueued on their shards or a shutdown signal is received.

Append queues a sample to be sent to the remote storage . Blocks until all samples are enqueued on their shards or a shutdown signal is received .


func (t *QueueManager) Start() {
	// Setup the QueueManagers metrics. We do this here rather than in the
	// constructor because of the ordering of creating Queue Managers's, stopping them,
	// and then starting new ones in storage/remote/storage.go ApplyConfig.
	name := t.client.Name()
	t.highestSentTimestampMetric = &maxGauge{
		Gauge: queueHighestSentTimestamp.WithLabelValues(name),
	}
	t.pendingSamplesMetric = queuePendingSamples.WithLabelValues(name)
	t.enqueueRetriesMetric = enqueueRetriesTotal.WithLabelValues(name)
	t.droppedSamplesTotal = droppedSamplesTotal.WithLabelValues(name)
	t.numShardsMetric = numShards.WithLabelValues(name)
	t.failedSamplesTotal = failedSamplesTotal.WithLabelValues(name)
	t.sentBatchDuration = sentBatchDuration.WithLabelValues(name)
	t.succeededSamplesTotal = succeededSamplesTotal.WithLabelValues(name)
	t.retriedSamplesTotal = retriedSamplesTotal.WithLabelValues(name)
	t.shardCapacity = shardCapacity.WithLabelValues(name)

	// Initialise some metrics.
	t.shardCapacity.Set(float64(t.cfg.Capacity))
	t.pendingSamplesMetric.Set(0)

	t.shards.start(t.numShards)
	t.watcher.Start()

	t.wg.Add(2)
	go t.updateShardsLoop()
	go t.reshardLoop()
}

// Start the queue manager sending samples to the remote storage.
// Does not block.

Start the queue manager sending samples to the remote storage . Does not block .


func (t *QueueManager) Stop() {
	level.Info(t.logger).Log("msg", "Stopping remote storage...")
	defer level.Info(t.logger).Log("msg", "Remote storage stopped.")

	close(t.quit)
	t.wg.Wait()
	// Wait for all QueueManager routines to end before stopping shards and WAL watcher. This
	// is to ensure we don't end up executing a reshard and shards.stop() at the same time, which
	// causes a closed channel panic.
	t.shards.stop()
	t.watcher.Stop()

	// On shutdown, release the strings in the labels from the intern pool.
	t.seriesMtx.Lock()
	defer t.seriesMtx.Unlock()
	for _, labels := range t.seriesLabels {
		release(labels)
	}
	// Delete metrics so we don't have alerts for queues that are gone.
	name := t.client.Name()
	queueHighestSentTimestamp.DeleteLabelValues(name)
	queuePendingSamples.DeleteLabelValues(name)
	enqueueRetriesTotal.DeleteLabelValues(name)
	droppedSamplesTotal.DeleteLabelValues(name)
	numShards.DeleteLabelValues(name)
	failedSamplesTotal.DeleteLabelValues(name)
	sentBatchDuration.DeleteLabelValues(name)
	succeededSamplesTotal.DeleteLabelValues(name)
	retriedSamplesTotal.DeleteLabelValues(name)
	shardCapacity.DeleteLabelValues(name)
}

// Stop stops sending samples to the remote storage and waits for pending
// sends to complete.

Stop stops sending samples to the remote storage and waits for pending sends to complete .


func (t *QueueManager) StoreSeries(series []tsdb.RefSeries, index int) {
	// Lock before any calls to labelsToLabels proto, as that's where string interning is done.
	t.seriesMtx.Lock()
	defer t.seriesMtx.Unlock()

	temp := make(map[uint64][]prompb.Label, len(series))
	for _, s := range series {
		ls := processExternalLabels(s.Labels, t.externalLabels)
		rl := relabel.Process(ls, t.relabelConfigs...)
		if len(rl) == 0 {
			t.droppedSeries[s.Ref] = struct{}{}
			continue
		}
		temp[s.Ref] = labelsToLabelsProto(rl)
	}

	for ref, labels := range temp {
		t.seriesSegmentIndexes[ref] = index

		// We should not ever be replacing a series labels in the map, but just
		// in case we do we need to ensure we do not leak the replaced interned
		// strings.
		if orig, ok := t.seriesLabels[ref]; ok {
			release(orig)
		}
		t.seriesLabels[ref] = labels
	}
}

// StoreSeries keeps track of which series we know about for lookups when sending samples to remote.

StoreSeries keeps track of which series we know about for lookups when sending samples to remote .


func processExternalLabels(ls tsdbLabels.Labels, externalLabels labels.Labels) labels.Labels {
	i, j, result := 0, 0, make(labels.Labels, 0, len(ls)+len(externalLabels))
	for i < len(ls) && j < len(externalLabels) {
		if ls[i].Name < externalLabels[j].Name {
			result = append(result, labels.Label{
				Name:  ls[i].Name,
				Value: ls[i].Value,
			})
			i++
		} else if ls[i].Name > externalLabels[j].Name {
			result = append(result, externalLabels[j])
			j++
		} else {
			result = append(result, labels.Label{
				Name:  ls[i].Name,
				Value: ls[i].Value,
			})
			i++
			j++
		}
	}
	for ; i < len(ls); i++ {
		result = append(result, labels.Label{
			Name:  ls[i].Name,
			Value: ls[i].Value,
		})
	}
	result = append(result, externalLabels[j:]...)
	return result
}

func processExternalLabels ( ls tsdbLabels . Labels , externalLabels labels . Labels ) labels . Labels { i , j , result := 0 , 0 , make ( labels . Labels , 0 , len ( ls ) + len ( externalLabels ) ) for i < len ( ls ) && j < len ( externalLabels ) { if ls [ i ] . Name < externalLabels [ j ] . Name { result = append ( result , labels . Label { Name : ls [ i ] . Name , Value : ls [ i ] . Value , } ) i ++ } else if ls [ i ] . Name > externalLabels [ j ] . Name { result = append ( result , externalLabels [ j ] ) j ++ } else { result = append ( result , labels . Label { Name : ls [ i ] . Name , Value : ls [ i ] . Value , } ) i ++ j ++ } } for ; i < len ( ls ) ; i ++ { result = append ( result , labels . Label { Name : ls [ i ] . Name , Value : ls [ i ] . Value , } ) } result = append ( result , externalLabels [ j : ] ... ) return result }

// processExternalLabels merges externalLabels into ls. If ls contains
// a label in externalLabels, the value in ls wins.

processExternalLabels merges externalLabels into ls . If ls contains a label in externalLabels the value in ls wins .


func (s *shards) start(n int) {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	newQueues := make([]chan prompb.TimeSeries, n)
	for i := 0; i < n; i++ {
		newQueues[i] = make(chan prompb.TimeSeries, s.qm.cfg.Capacity)
	}

	s.queues = newQueues

	var hardShutdownCtx context.Context
	hardShutdownCtx, s.hardShutdown = context.WithCancel(context.Background())
	s.softShutdown = make(chan struct{})
	s.running = int32(n)
	s.done = make(chan struct{})
	for i := 0; i < n; i++ {
		go s.runShard(hardShutdownCtx, i, newQueues[i])
	}
	s.qm.numShardsMetric.Set(float64(n))
}

func ( s * shards ) start ( n int ) { s . mtx . Lock ( ) defer s . mtx . Unlock ( ) newQueues := make ( [ ] chan prompb . TimeSeries , n ) for i := 0 ; i < n ; i ++ { newQueues [ i ] = make ( chan prompb . TimeSeries , s . qm . cfg . Capacity ) } s . queues = newQueues var hardShutdownCtx context . Context hardShutdownCtx , s . hardShutdown = context . WithCancel ( context . Background ( ) ) s . softShutdown = make ( chan struct { } ) s . running = int32 ( n ) s . done = make ( chan struct { } ) for i := 0 ; i < n ; i ++ { go s . runShard ( hardShutdownCtx , i , newQueues [ i ] ) } s . qm . numShardsMetric . Set ( float64 ( n ) ) }

// start the shards; must be called before any call to enqueue.

start the shards ; must be called before any call to enqueue .


func (s *shards) stop() {
	// Attempt a clean shutdown, but only wait flushDeadline for all the shards
	// to cleanly exit.  As we're doing RPCs, enqueue can block indefinitely.
	// We must be able so call stop concurrently, hence we can only take the
	// RLock here.
	s.mtx.RLock()
	close(s.softShutdown)
	s.mtx.RUnlock()

	// Enqueue should now be unblocked, so we can take the write lock.  This
	// also ensures we don't race with writes to the queues, and get a panic:
	// send on closed channel.
	s.mtx.Lock()
	defer s.mtx.Unlock()
	for _, queue := range s.queues {
		close(queue)
	}
	select {
	case <-s.done:
		return
	case <-time.After(s.qm.flushDeadline):
		level.Error(s.qm.logger).Log("msg", "Failed to flush all samples on shutdown")
	}

	// Force an unclean shutdown.
	s.hardShutdown()
	<-s.done
}

// stop the shards; subsequent call to enqueue will return false.

stop the shards ; subsequent call to enqueue will return false .


func (s *shards) enqueue(ref uint64, sample prompb.TimeSeries) bool {
	s.mtx.RLock()
	defer s.mtx.RUnlock()

	select {
	case <-s.softShutdown:
		return false
	default:
	}

	shard := uint64(ref) % uint64(len(s.queues))
	select {
	case <-s.softShutdown:
		return false
	case s.queues[shard] <- sample:
		return true
	}
}

func ( s * shards ) enqueue ( ref uint64 , sample prompb . TimeSeries ) bool { s . mtx . RLock ( ) defer s . mtx . RUnlock ( ) select { case <- s . softShutdown : return false default : } shard := uint64 ( ref ) % uint64 ( len ( s . queues ) ) select { case <- s . softShutdown : return false case s . queues [ shard ] <- sample : return true } }

// enqueue a sample.  If we are currently in the process of shutting down or resharding,
// will return false; in this case, you should back off and retry.

enqueue a sample . If we are currently in the process of shutting down or resharding will return false ; in this case you should back off and retry .


func (s *shards) sendSamplesWithBackoff(ctx context.Context, samples []prompb.TimeSeries) error {
	backoff := s.qm.cfg.MinBackoff
	req, highest, err := buildWriteRequest(samples)
	if err != nil {
		// Failing to build the write request is non-recoverable, since it will
		// only error if marshaling the proto to bytes fails.
		return err
	}

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}
		begin := time.Now()
		err := s.qm.client.Store(ctx, req)

		s.qm.sentBatchDuration.Observe(time.Since(begin).Seconds())

		if err == nil {
			s.qm.succeededSamplesTotal.Add(float64(len(samples)))
			s.qm.highestSentTimestampMetric.Set(float64(highest / 1000))
			return nil
		}

		if _, ok := err.(recoverableError); !ok {
			return err
		}
		s.qm.retriedSamplesTotal.Add(float64(len(samples)))
		level.Debug(s.qm.logger).Log("msg", "failed to send batch, retrying", "err", err)

		time.Sleep(time.Duration(backoff))
		backoff = backoff * 2
		if backoff > s.qm.cfg.MaxBackoff {
			backoff = s.qm.cfg.MaxBackoff
		}
	}
}

// sendSamples to the remote storage with backoff for recoverable errors.

sendSamples to the remote storage with backoff for recoverable errors .


func New(l log.Logger, conf *SDConfig) (*Discovery, error) {
	if l == nil {
		l = log.NewNopLogger()
	}
	var (
		kcfg *rest.Config
		err  error
	)
	if conf.APIServer.URL == nil {
		// Use the Kubernetes provided pod service account
		// as described in https://kubernetes.io/docs/admin/service-accounts-admin/
		kcfg, err = rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
		level.Info(l).Log("msg", "Using pod service account via in-cluster config")
	} else {
		rt, err := config_util.NewRoundTripperFromConfig(conf.HTTPClientConfig, "kubernetes_sd")
		if err != nil {
			return nil, err
		}
		kcfg = &rest.Config{
			Host:      conf.APIServer.String(),
			Transport: rt,
		}
	}

	kcfg.UserAgent = "Prometheus/discovery"

	c, err := kubernetes.NewForConfig(kcfg)
	if err != nil {
		return nil, err
	}
	return &Discovery{
		client:             c,
		logger:             l,
		role:               conf.Role,
		namespaceDiscovery: &conf.NamespaceDiscovery,
		discoverers:        make([]discoverer, 0),
	}, nil
}

// New creates a new Kubernetes discovery for the given role.

New creates a new Kubernetes discovery for the given role .


func compileCORSRegexString(s string) (*regexp.Regexp, error) {
	r, err := relabel.NewRegexp(s)
	if err != nil {
		return nil, err
	}
	return r.Regexp, nil
}

func compileCORSRegexString ( s string ) ( * regexp . Regexp , error ) { r , err := relabel . NewRegexp ( s ) if err != nil { return nil , err } return r . Regexp , nil }

// compileCORSRegexString compiles given string and adds anchors


func computeExternalURL(u, listenAddr string) (*url.URL, error) {
	if u == "" {
		hostname, err := os.Hostname()
		if err != nil {
			return nil, err
		}
		_, port, err := net.SplitHostPort(listenAddr)
		if err != nil {
			return nil, err
		}
		u = fmt.Sprintf("http://%s:%s/", hostname, port)
	}

	if startsOrEndsWithQuote(u) {
		return nil, errors.New("URL must not begin or end with quotes")
	}

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

	ppref := strings.TrimRight(eu.Path, "/")
	if ppref != "" && !strings.HasPrefix(ppref, "/") {
		ppref = "/" + ppref
	}
	eu.Path = ppref

	return eu, nil
}

func computeExternalURL ( u , listenAddr string ) ( * url . URL , error ) { if u == " " { hostname , err := os . Hostname ( ) if err != nil { return nil , err } _ , port , err := net . SplitHostPort ( listenAddr ) if err != nil { return nil , err } u = fmt . Sprintf ( " " , hostname , port ) } if startsOrEndsWithQuote ( u ) { return nil , errors . New ( " " ) } eu , err := url . Parse ( u ) if err != nil { return nil , err } ppref := strings . TrimRight ( eu . Path , " " ) if ppref != " " && ! strings . HasPrefix ( ppref , " " ) { ppref = " " + ppref } eu . Path = ppref return eu , nil }

// computeExternalURL computes a sanitized external URL from a raw input. It infers unset
// URL parts from the OS and the given listen address.

computeExternalURL computes a sanitized external URL from a raw input . It infers unset URL parts from the OS and the given listen address .


func sendAlerts(s sender, externalURL string) rules.NotifyFunc {
	return func(ctx context.Context, expr string, alerts ...*rules.Alert) {
		var res []*notifier.Alert

		for _, alert := range alerts {
			a := &notifier.Alert{
				StartsAt:     alert.FiredAt,
				Labels:       alert.Labels,
				Annotations:  alert.Annotations,
				GeneratorURL: externalURL + strutil.TableLinkForExpression(expr),
			}
			if !alert.ResolvedAt.IsZero() {
				a.EndsAt = alert.ResolvedAt
			} else {
				a.EndsAt = alert.ValidUntil
			}
			res = append(res, a)
		}

		if len(alerts) > 0 {
			s.Send(res...)
		}
	}
}

func sendAlerts ( s sender , externalURL string ) rules . NotifyFunc { return func ( ctx context . Context , expr string , alerts ... * rules . Alert ) { var res [ ] * notifier . Alert for _ , alert := range alerts { a := & notifier . Alert { StartsAt : alert . FiredAt , Labels : alert . Labels , Annotations : alert . Annotations , GeneratorURL : externalURL + strutil . TableLinkForExpression ( expr ) , } if ! alert . ResolvedAt . IsZero ( ) { a . EndsAt = alert . ResolvedAt } else { a . EndsAt = alert . ValidUntil } res = append ( res , a ) } if len ( alerts ) > 0 { s . Send ( res ... ) } } }

// sendAlerts implements the rules.NotifyFunc for a Notifier.

sendAlerts implements the rules . NotifyFunc for a Notifier .


func (g *RuleGroups) Validate() (errs []error) {
	set := map[string]struct{}{}

	for _, g := range g.Groups {
		if g.Name == "" {
			errs = append(errs, errors.Errorf("Groupname should not be empty"))
		}

		if _, ok := set[g.Name]; ok {
			errs = append(
				errs,
				errors.Errorf("groupname: \"%s\" is repeated in the same file", g.Name),
			)
		}

		set[g.Name] = struct{}{}

		for i, r := range g.Rules {
			for _, err := range r.Validate() {
				var ruleName string
				if r.Alert != "" {
					ruleName = r.Alert
				} else {
					ruleName = r.Record
				}
				errs = append(errs, &Error{
					Group:    g.Name,
					Rule:     i,
					RuleName: ruleName,
					Err:      err,
				})
			}
		}
	}

	return errs
}

func ( g * RuleGroups ) Validate ( ) ( errs [ ] error ) { set := map [ string ] struct { } { } for _ , g := range g . Groups { if g . Name == " " { errs = append ( errs , errors . Errorf ( " " ) ) } if _ , ok := set [ g . Name ] ; ok { errs = append ( errs , errors . Errorf ( " \" \" " , g . Name ) , ) } set [ g . Name ] = struct { } { } for i , r := range g . Rules { for _ , err := range r . Validate ( ) { var ruleName string if r . Alert != " " { ruleName = r . Alert } else { ruleName = r . Record } errs = append ( errs , & Error { Group : g . Name , Rule : i , RuleName : ruleName , Err : err , } ) } } } return errs }

// Validate validates all rules in the rule groups.

Validate validates all rules in the rule groups .


func (r *Rule) Validate() (errs []error) {
	if r.Record != "" && r.Alert != "" {
		errs = append(errs, errors.Errorf("only one of 'record' and 'alert' must be set"))
	}
	if r.Record == "" && r.Alert == "" {
		errs = append(errs, errors.Errorf("one of 'record' or 'alert' must be set"))
	}

	if r.Expr == "" {
		errs = append(errs, errors.Errorf("field 'expr' must be set in rule"))
	} else if _, err := promql.ParseExpr(r.Expr); err != nil {
		errs = append(errs, errors.Errorf("could not parse expression: %s", err))
	}
	if r.Record != "" {
		if len(r.Annotations) > 0 {
			errs = append(errs, errors.Errorf("invalid field 'annotations' in recording rule"))
		}
		if r.For != 0 {
			errs = append(errs, errors.Errorf("invalid field 'for' in recording rule"))
		}
		if !model.IsValidMetricName(model.LabelValue(r.Record)) {
			errs = append(errs, errors.Errorf("invalid recording rule name: %s", r.Record))
		}
	}

	for k, v := range r.Labels {
		if !model.LabelName(k).IsValid() {
			errs = append(errs, errors.Errorf("invalid label name: %s", k))
		}

		if !model.LabelValue(v).IsValid() {
			errs = append(errs, errors.Errorf("invalid label value: %s", v))
		}
	}

	for k := range r.Annotations {
		if !model.LabelName(k).IsValid() {
			errs = append(errs, errors.Errorf("invalid annotation name: %s", k))
		}
	}

	errs = append(errs, testTemplateParsing(r)...)
	return errs
}

func ( r * Rule ) Validate ( ) ( errs [ ] error ) { if r . Record != " " && r . Alert != " " { errs = append ( errs , errors . Errorf ( " " ) ) } if r . Record == " " && r . Alert == " " { errs = append ( errs , errors . Errorf ( " " ) ) } if r . Expr == " " { errs = append ( errs , errors . Errorf ( " " ) ) } else if _ , err := promql . ParseExpr ( r . Expr ) ; err != nil { errs = append ( errs , errors . Errorf ( " " , err ) ) } if r . Record != " " { if len ( r . Annotations ) > 0 { errs = append ( errs , errors . Errorf ( " " ) ) } if r . For != 0 { errs = append ( errs , errors . Errorf ( " " ) ) } if ! model . IsValidMetricName ( model . LabelValue ( r . Record ) ) { errs = append ( errs , errors . Errorf ( " " , r . Record ) ) } } for k , v := range r . Labels { if ! model . LabelName ( k ) . IsValid ( ) { errs = append ( errs , errors . Errorf ( " " , k ) ) } if ! model . LabelValue ( v ) . IsValid ( ) { errs = append ( errs , errors . Errorf ( " " , v ) ) } } for k := range r . Annotations { if ! model . LabelName ( k ) . IsValid ( ) { errs = append ( errs , errors . Errorf ( " " , k ) ) } } errs = append ( errs , testTemplateParsing ( r ) ... ) return errs }

// Validate the rule and return a list of encountered errors.

Validate the rule and return a list of encountered errors .


func Parse(content []byte) (*RuleGroups, []error) {
	var groups RuleGroups
	if err := yaml.UnmarshalStrict(content, &groups); err != nil {
		return nil, []error{err}
	}
	return &groups, groups.Validate()
}

func Parse ( content [ ] byte ) ( * RuleGroups , [ ] error ) { var groups RuleGroups if err := yaml . UnmarshalStrict ( content , & groups ) ; err != nil { return nil , [ ] error { err } } return & groups , groups . Validate ( ) }

// Parse parses and validates a set of rules.

Parse parses and validates a set of rules .


func ParseFile(file string) (*RuleGroups, []error) {
	b, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, []error{err}
	}
	return Parse(b)
}

func ParseFile ( file string ) ( * RuleGroups , [ ] error ) { b , err := ioutil . ReadFile ( file ) if err != nil { return nil , [ ] error { err } } return Parse ( b ) }

// ParseFile reads and parses rules from a file.

ParseFile reads and parses rules from a file .


func TableLinkForExpression(expr string) string {
	escapedExpression := url.QueryEscape(expr)
	return fmt.Sprintf("/graph?g0.expr=%s&g0.tab=1", escapedExpression)
}

func TableLinkForExpression ( expr string ) string { escapedExpression := url . QueryEscape ( expr ) return fmt . Sprintf ( " " , escapedExpression ) }

// TableLinkForExpression creates an escaped relative link to the table view of
// the provided expression.

TableLinkForExpression creates an escaped relative link to the table view of the provided expression .


func GraphLinkForExpression(expr string) string {
	escapedExpression := url.QueryEscape(expr)
	return fmt.Sprintf("/graph?g0.expr=%s&g0.tab=0", escapedExpression)
}

func GraphLinkForExpression ( expr string ) string { escapedExpression := url . QueryEscape ( expr ) return fmt . Sprintf ( " " , escapedExpression ) }

// GraphLinkForExpression creates an escaped relative link to the graph view of
// the provided expression.

GraphLinkForExpression creates an escaped relative link to the graph view of the provided expression .


func NewFanout(logger log.Logger, primary Storage, secondaries ...Storage) Storage {
	return &fanout{
		logger:      logger,
		primary:     primary,
		secondaries: secondaries,
	}
}

func NewFanout ( logger log . Logger , primary Storage , secondaries ... Storage ) Storage { return & fanout { logger : logger , primary : primary , secondaries : secondaries , } }

// NewFanout returns a new fan-out Storage, which proxies reads and writes
// through to multiple underlying storages.

NewFanout returns a new fan - out Storage which proxies reads and writes through to multiple underlying storages .


func (f *fanout) Close() error {
	if err := f.primary.Close(); err != nil {
		return err
	}

	// TODO return multiple errors?
	var lastErr error
	for _, storage := range f.secondaries {
		if err := storage.Close(); err != nil {
			lastErr = err
		}
	}
	return lastErr
}

func
(
f
*
fanout
)
Close
(
)
error
{
if
err
:=
f
.
primary
.
Close
(
)
;
err
!=
{
return
err
}
// TODO return multiple errors?
var
lastErr
error
for
_
,
storage
:=
range
f
.
secondaries
{
if
err
:=
storage
.
Close
(
)
;
err
!=
{
lastErr
=
err
}
}
return
lastErr
}

// Close closes the storage and all its underlying resources.

Close closes the storage and all its underlying resources .


func NewMergeQuerier(primaryQuerier Querier, queriers []Querier) Querier {
	filtered := make([]Querier, 0, len(queriers))
	for _, querier := range queriers {
		if querier != NoopQuerier() {
			filtered = append(filtered, querier)
		}
	}

	setQuerierMap := make(map[SeriesSet]Querier)
	failedQueriers := make(map[Querier]struct{})

	switch len(filtered) {
	case 0:
		return NoopQuerier()
	case 1:
		return filtered[0]
	default:
		return &mergeQuerier{
			primaryQuerier: primaryQuerier,
			queriers:       filtered,
			failedQueriers: failedQueriers,
			setQuerierMap:  setQuerierMap,
		}
	}
}

func NewMergeQuerier ( primaryQuerier Querier , queriers [ ] Querier ) Querier { filtered := make ( [ ] Querier , 0 , len ( queriers ) ) for _ , querier := range queriers { if querier != NoopQuerier ( ) { filtered = append ( filtered , querier ) } } setQuerierMap := make ( map [ SeriesSet ] Querier ) failedQueriers := make ( map [ Querier ] struct { } ) switch len ( filtered ) { case 0 : return NoopQuerier ( ) case 1 : return filtered [ 0 ] default : return & mergeQuerier { primaryQuerier : primaryQuerier , queriers : filtered , failedQueriers : failedQueriers , setQuerierMap : setQuerierMap , } } }

// NewMergeQuerier returns a new Querier that merges results of input queriers.
// NB NewMergeQuerier will return NoopQuerier if no queriers are passed to it,
// and will filter NoopQueriers from its arguments, in order to reduce overhead
// when only one querier is passed.

NewMergeQuerier returns a new Querier that merges results of input queriers . NB NewMergeQuerier will return NoopQuerier if no queriers are passed to it and will filter NoopQueriers from its arguments in order to reduce overhead when only one querier is passed .


func (q *mergeQuerier) Select(params *SelectParams, matchers ...*labels.Matcher) (SeriesSet, Warnings, error) {
	seriesSets := make([]SeriesSet, 0, len(q.queriers))
	var warnings Warnings
	for _, querier := range q.queriers {
		set, wrn, err := querier.Select(params, matchers...)
		q.setQuerierMap[set] = querier
		if wrn != nil {
			warnings = append(warnings, wrn...)
		}
		if err != nil {
			q.failedQueriers[querier] = struct{}{}
			// If the error source isn't the primary querier, return the error as a warning and continue.
			if querier != q.primaryQuerier {
				warnings = append(warnings, err)
				continue
			} else {
				return nil, nil, err
			}
		}
		seriesSets = append(seriesSets, set)
	}
	return NewMergeSeriesSet(seriesSets, q), warnings, nil
}

// Select returns a set of series that matches the given label matchers.

Select returns a set of series that matches the given label matchers .


func (q *mergeQuerier) LabelValues(name string) ([]string, error) {
	var results [][]string
	for _, querier := range q.queriers {
		values, err := querier.LabelValues(name)
		if err != nil {
			return nil, err
		}
		results = append(results, values)
	}
	return mergeStringSlices(results), nil
}

func ( q * mergeQuerier ) LabelValues ( name string ) ( [ ] string , error ) { var results [ ] [ ] string for _ , querier := range q . queriers { values , err := querier . LabelValues ( name ) if err != nil { return nil , err } results = append ( results , values ) } return mergeStringSlices ( results ) , nil }

// LabelValues returns all potential values for a label name.

LabelValues returns all potential values for a label name .


func (q *mergeQuerier) LabelNames() ([]string, error) {
	labelNamesMap := make(map[string]struct{})
	for _, b := range q.queriers {
		names, err := b.LabelNames()
		if err != nil {
			return nil, errors.Wrap(err, "LabelNames() from Querier")
		}
		for _, name := range names {
			labelNamesMap[name] = struct{}{}
		}
	}

	labelNames := make([]string, 0, len(labelNamesMap))
	for name := range labelNamesMap {
		labelNames = append(labelNames, name)
	}
	sort.Strings(labelNames)

	return labelNames, nil
}

func ( q * mergeQuerier ) LabelNames ( ) ( [ ] string , error ) { labelNamesMap := make ( map [ string ] struct { } ) for _ , b := range q . queriers { names , err := b . LabelNames ( ) if err != nil { return nil , errors . Wrap ( err , " " ) } for _ , name := range names { labelNamesMap [ name ] = struct { } { } } } labelNames := make ( [ ] string , 0 , len ( labelNamesMap ) ) for name := range labelNamesMap { labelNames = append ( labelNames , name ) } sort . Strings ( labelNames ) return labelNames , nil }

// LabelNames returns all the unique label names present in the block in sorted order.

LabelNames returns all the unique label names present in the block in sorted order .


func (q *mergeQuerier) Close() error {
	// TODO return multiple errors?
	var lastErr error
	for _, querier := range q.queriers {
		if err := querier.Close(); err != nil {
			lastErr = err
		}
	}
	return lastErr
}

func
(
q
*
mergeQuerier
)
Close
(
)
error
{
// TODO return multiple errors?
var
lastErr
error
for
_
,
querier
:=
range
q
.
queriers
{
if
err
:=
querier
.
Close
(
)
;
err
!=
{
lastErr
=
err
}
}
return
lastErr
}

// Close releases the resources of the Querier.

Close releases the resources of the Querier .


func NewAlertingRule(
	name string, vec promql.Expr, hold time.Duration,
	labels, annotations, externalLabels labels.Labels,
	restored bool, logger log.Logger,
) *AlertingRule {
	el := make(map[string]string, len(externalLabels))
	for _, lbl := range externalLabels {
		el[lbl.Name] = lbl.Value
	}

	return &AlertingRule{
		name:           name,
		vector:         vec,
		holdDuration:   hold,
		labels:         labels,
		annotations:    annotations,
		externalLabels: el,
		health:         HealthUnknown,
		active:         map[uint64]*Alert{},
		logger:         logger,
		restored:       restored,
	}
}

func NewAlertingRule ( name string , vec promql . Expr , hold time . Duration , labels , annotations , externalLabels labels . Labels , restored bool , logger log . Logger , ) * AlertingRule { el := make ( map [ string ] string , len ( externalLabels ) ) for _ , lbl := range externalLabels { el [ lbl . Name ] = lbl . Value } return & AlertingRule { name : name , vector : vec , holdDuration : hold , labels : labels , annotations : annotations , externalLabels : el , health : HealthUnknown , active : map [ uint64 ] * Alert { } , logger : logger , restored : restored , } }

// NewAlertingRule constructs a new AlertingRule.

NewAlertingRule constructs a new AlertingRule .


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

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

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

SetLastError sets the current error seen by the alerting rule .


func (r *AlertingRule) LastError() error {
	r.mtx.Lock()
	defer r.mtx.Unlock()
	return r.lastError
}

func ( r * AlertingRule ) LastError ( ) error { r . mtx . Lock ( ) defer r . mtx . Unlock ( ) return r . lastError }

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

LastError returns the last error seen by the alerting rule .


func (r *AlertingRule) SetHealth(health RuleHealth) {
	r.mtx.Lock()
	defer r.mtx.Unlock()
	r.health = health
}

func ( r * AlertingRule ) SetHealth ( health RuleHealth ) { r . mtx . Lock ( ) defer r . mtx . Unlock ( ) r . health = health }

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

SetHealth sets the current health of the alerting rule .


func (r *AlertingRule) Health() RuleHealth {
	r.mtx.Lock()
	defer r.mtx.Unlock()
	return r.health
}

func ( r * AlertingRule ) Health ( ) RuleHealth { r . mtx . Lock ( ) defer r . mtx . Unlock ( ) return r . health }

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

Health returns the current health of the alerting rule .


func (r *AlertingRule) forStateSample(alert *Alert, ts time.Time, v float64) promql.Sample {
	lb := labels.NewBuilder(r.labels)

	for _, l := range alert.Labels {
		lb.Set(l.Name, l.Value)
	}

	lb.Set(labels.MetricName, alertForStateMetricName)
	lb.Set(labels.AlertName, r.name)

	s := promql.Sample{
		Metric: lb.Labels(),
		Point:  promql.Point{T: timestamp.FromTime(ts), V: v},
	}
	return s
}

func ( r * AlertingRule ) forStateSample ( alert * Alert , ts time . Time , v float64 ) promql . Sample { lb := labels . NewBuilder ( r . labels ) for _ , l := range alert . Labels { lb . Set ( l . Name , l . Value ) } lb . Set ( labels . MetricName , alertForStateMetricName ) lb . Set ( labels . AlertName , r . name ) s := promql . Sample { Metric : lb . Labels ( ) , Point : promql . Point { T : timestamp . FromTime ( ts ) , V : v } , } return s }

// forStateSample returns the sample for ALERTS_FOR_STATE.

forStateSample returns the sample for ALERTS_FOR_STATE .


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

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

// SetEvaluationDuration updates evaluationDuration to the duration it took to evaluate the rule on its last evaluation.

SetEvaluationDuration updates evaluationDuration to the duration it took to evaluate the rule on its last evaluation .


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

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

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

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


func (r *AlertingRule) State() AlertState {
	r.mtx.Lock()
	defer r.mtx.Unlock()

	maxState := StateInactive
	for _, a := range r.active {
		if a.State > maxState {
			maxState = a.State
		}
	}
	return maxState
}

func ( r * AlertingRule ) State ( ) AlertState { r . mtx . Lock ( ) defer r . mtx . Unlock ( ) maxState := StateInactive for _ , a := range r . active { if a . State > maxState { maxState = a . State } } return maxState }

// State returns the maximum state of alert instances for this rule.
// StateFiring > StatePending > StateInactive

State returns the maximum state of alert instances for this rule . StateFiring > StatePending > StateInactive


func (r *AlertingRule) ActiveAlerts() []*Alert {
	var res []*Alert
	for _, a := range r.currentAlerts() {
		if a.ResolvedAt.IsZero() {
			res = append(res, a)
		}
	}
	return res
}

func ( r * AlertingRule ) ActiveAlerts ( ) [ ] * Alert { var res [ ] * Alert for _ , a := range r . currentAlerts ( ) { if a . ResolvedAt . IsZero ( ) { res = append ( res , a ) } } return res }

// ActiveAlerts returns a slice of active alerts.

ActiveAlerts returns a slice of active alerts .


func (r *AlertingRule) currentAlerts() []*Alert {
	r.mtx.Lock()
	defer r.mtx.Unlock()

	alerts := make([]*Alert, 0, len(r.active))

	for _, a := range r.active {
		anew := *a
		alerts = append(alerts, &anew)
	}
	return alerts
}

func ( r * AlertingRule ) currentAlerts ( ) [ ] * Alert { r . mtx . Lock ( ) defer r . mtx . Unlock ( ) alerts := make ( [ ] * Alert , 0 , len ( r . active ) ) for _ , a := range r . active { anew := * a alerts = append ( alerts , & anew ) } return alerts }

// currentAlerts returns all instances of alerts for this rule. This may include
// inactive alerts that were previously firing.

currentAlerts returns all instances of alerts for this rule . This may include inactive alerts that were previously firing .


func (a *Adapter) refreshTargetGroups(allTargetGroups map[string][]*targetgroup.Group) {
	tempGroups := generateTargetGroups(allTargetGroups)

	if !reflect.DeepEqual(a.groups, tempGroups) {
		a.groups = tempGroups
		err := a.writeOutput()
		if err != nil {
			level.Error(log.With(a.logger, "component", "sd-adapter")).Log("err", err)
		}
	}
}

func ( a * Adapter ) refreshTargetGroups ( allTargetGroups map [ string ] [ ] * targetgroup . Group ) { tempGroups := generateTargetGroups ( allTargetGroups ) if ! reflect . DeepEqual ( a . groups , tempGroups ) { a . groups = tempGroups err := a . writeOutput ( ) if err != nil { level . Error ( log . With ( a . logger , " " , " " ) ) . Log ( " " , err ) } } }

// Parses incoming target groups updates. If the update contains changes to the target groups
// Adapter already knows about, or new target groups, we Marshal to JSON and write to file.

Parses incoming target groups updates . If the update contains changes to the target groups Adapter already knows about or new target groups we Marshal to JSON and write to file .


func (a *Adapter) writeOutput() error {
	arr := mapToArray(a.groups)
	b, _ := json.MarshalIndent(arr, "", "    ")

	dir, _ := filepath.Split(a.output)
	tmpfile, err := ioutil.TempFile(dir, "sd-adapter")
	if err != nil {
		return err
	}
	defer tmpfile.Close()

	_, err = tmpfile.Write(b)
	if err != nil {
		return err
	}

	err = os.Rename(tmpfile.Name(), a.output)
	if err != nil {
		return err
	}
	return nil
}

func ( a * Adapter ) writeOutput ( ) error { arr := mapToArray ( a . groups ) b , _ := json . MarshalIndent ( arr , " " , " " ) dir , _ := filepath . Split ( a . output ) tmpfile , err := ioutil . TempFile ( dir , " " ) if err != nil { return err } defer tmpfile . Close ( ) _ , err = tmpfile . Write ( b ) if err != nil { return err } err = os . Rename ( tmpfile . Name ( ) , a . output ) if err != nil { return err } return nil }

// Writes JSON formatted targets to output file.

Writes JSON formatted targets to output file .


func (a *Adapter) Run() {
	go a.manager.Run()
	a.manager.StartCustomProvider(a.ctx, a.name, a.disc)
	go a.runCustomSD(a.ctx)
}

func ( a * Adapter ) Run ( ) { go a . manager . Run ( ) a . manager . StartCustomProvider ( a . ctx , a . name , a . disc ) go a . runCustomSD ( a . ctx ) }

// Run starts a Discovery Manager and the custom service discovery implementation.

Run starts a Discovery Manager and the custom service discovery implementation .


func NewAdapter(ctx context.Context, file string, name string, d discovery.Discoverer, logger log.Logger) *Adapter {
	return &Adapter{
		ctx:     ctx,
		disc:    d,
		groups:  make(map[string]*customSD),
		manager: discovery.NewManager(ctx, logger),
		output:  file,
		name:    name,
		logger:  logger,
	}
}

func NewAdapter ( ctx context . Context , file string , name string , d discovery . Discoverer , logger log . Logger ) * Adapter { return & Adapter { ctx : ctx , disc : d , groups : make ( map [ string ] * customSD ) , manager : discovery . NewManager ( ctx , logger ) , output : file , name : name , logger : logger , } }

// NewAdapter creates a new instance of Adapter.

NewAdapter creates a new instance of Adapter .


func NewGroupMetrics(reg prometheus.Registerer) *Metrics {
	m := &Metrics{
		evalDuration: prometheus.NewSummary(
			prometheus.SummaryOpts{
				Namespace: namespace,
				Name:      "rule_evaluation_duration_seconds",
				Help:      "The duration for a rule to execute.",
			}),
		evalFailures: prometheus.NewCounter(
			prometheus.CounterOpts{
				Namespace: namespace,
				Name:      "rule_evaluation_failures_total",
				Help:      "The total number of rule evaluation failures.",
			}),
		evalTotal: prometheus.NewCounter(
			prometheus.CounterOpts{
				Namespace: namespace,
				Name:      "rule_evaluations_total",
				Help:      "The total number of rule evaluations.",
			}),
		iterationDuration: prometheus.NewSummary(prometheus.SummaryOpts{
			Namespace:  namespace,
			Name:       "rule_group_duration_seconds",
			Help:       "The duration of rule group evaluations.",
			Objectives: map[float64]float64{0.01: 0.001, 0.05: 0.005, 0.5: 0.05, 0.90: 0.01, 0.99: 0.001},
		}),
		iterationsMissed: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "rule_group_iterations_missed_total",
			Help:      "The total number of rule group evaluations missed due to slow rule group evaluation.",
		}),
		iterationsScheduled: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "rule_group_iterations_total",
			Help:      "The total number of scheduled rule group evaluations, whether executed or missed.",
		}),
		groupLastEvalTime: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "rule_group_last_evaluation_timestamp_seconds",
				Help:      "The timestamp of the last rule group evaluation in seconds.",
			},
			[]string{"rule_group"},
		),
		groupLastDuration: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "rule_group_last_duration_seconds",
				Help:      "The duration of the last rule group evaluation.",
			},
			[]string{"rule_group"},
		),
		groupRules: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "rule_group_rules",
				Help:      "The number of rules.",
			},
			[]string{"rule_group"},
		),
	}

	if reg != nil {
		reg.MustRegister(
			m.evalDuration,
			m.evalFailures,
			m.evalTotal,
			m.iterationDuration,
			m.iterationsMissed,
			m.iterationsScheduled,
			m.groupLastEvalTime,
			m.groupLastDuration,
			m.groupRules,
		)
	}

	return m
}

func NewGroupMetrics ( reg prometheus . Registerer ) * Metrics { m := & Metrics { evalDuration : prometheus . NewSummary ( prometheus . SummaryOpts { Namespace : namespace , Name : " " , Help : " " , } ) , evalFailures : prometheus . NewCounter ( prometheus . CounterOpts { Namespace : namespace , Name : " " , Help : " " , } ) , evalTotal : prometheus . NewCounter ( prometheus . CounterOpts { Namespace : namespace , Name : " " , Help : " " , } ) , iterationDuration : prometheus . NewSummary ( prometheus . SummaryOpts { Namespace : namespace , Name : " " , Help : " " , Objectives : map [ float64 ] float64 { 0.01 : 0.001 , 0.05 : 0.005 , 0.5 : 0.05 , 0.90 : 0.01 , 0.99 : 0.001 } , } ) , iterationsMissed : prometheus . NewCounter ( prometheus . CounterOpts { Namespace : namespace , Name : " " , Help : " " , } ) , iterationsScheduled : prometheus . NewCounter ( prometheus . CounterOpts { Namespace : namespace , Name : " " , Help : " " , } ) , groupLastEvalTime : prometheus . NewGaugeVec ( prometheus . GaugeOpts { Namespace : namespace , Name : " " , Help : " " , } , [ ] string { " " } , ) , groupLastDuration : prometheus . NewGaugeVec ( prometheus . GaugeOpts { Namespace : namespace , Name : " " , Help : " " , } , [ ] string { " " } , ) , groupRules : prometheus . NewGaugeVec ( prometheus . GaugeOpts { Namespace : namespace , Name : " " , Help : " " , } , [ ] string { " " } , ) , } if reg != nil { reg . MustRegister ( m . evalDuration , m . evalFailures , m . evalTotal , m . iterationDuration , m . iterationsMissed , m . iterationsScheduled , m . groupLastEvalTime , m . groupLastDuration , m . groupRules , ) } return m }

// NewGroupMetrics makes a new Metrics and registers them with then provided registerer,
// if not nil.

NewGroupMetrics makes a new Metrics and registers them with then provided registerer if not nil .


func EngineQueryFunc(engine *promql.Engine, q storage.Queryable) QueryFunc {
	return func(ctx context.Context, qs string, t time.Time) (promql.Vector, error) {
		q, err := engine.NewInstantQuery(q, qs, t)
		if err != nil {
			return nil, err
		}
		res := q.Exec(ctx)
		if res.Err != nil {
			return nil, res.Err
		}
		switch v := res.Value.(type) {
		case promql.Vector:
			return v, nil
		case promql.Scalar:
			return promql.Vector{promql.Sample{
				Point:  promql.Point(v),
				Metric: labels.Labels{},
			}}, nil
		default:
			return nil, errors.New("rule result is not a vector or scalar")
		}
	}
}

func EngineQueryFunc ( engine * promql . Engine , q storage . Queryable ) QueryFunc { return func ( ctx context . Context , qs string , t time . Time ) ( promql . Vector , error ) { q , err := engine . NewInstantQuery ( q , qs , t ) if err != nil { return nil , err } res := q . Exec ( ctx ) if res . Err != nil { return nil , res . Err } switch v := res . Value . ( type ) { case promql . Vector : return v , nil case promql . Scalar : return promql . Vector { promql . Sample { Point : promql . Point ( v ) , Metric : labels . Labels { } , } } , nil default : return nil , errors . New ( " " ) } } }

// EngineQueryFunc returns a new query function that executes instant queries against
// the given engine.
// It converts scalar into vector results.

EngineQueryFunc returns a new query function that executes instant queries against the given engine . It converts scalar into vector results .


func NewGroup(name, file string, interval time.Duration, rules []Rule, shouldRestore bool, opts *ManagerOptions) *Group {
	metrics := opts.Metrics
	if metrics == nil {
		metrics = NewGroupMetrics(opts.Registerer)
	}

	metrics.groupLastEvalTime.WithLabelValues(groupKey(file, name))
	metrics.groupLastDuration.WithLabelValues(groupKey(file, name))
	metrics.groupRules.WithLabelValues(groupKey(file, name)).Set(float64(len(rules)))

	return &Group{
		name:                 name,
		file:                 file,
		interval:             interval,
		rules:                rules,
		shouldRestore:        shouldRestore,
		opts:                 opts,
		seriesInPreviousEval: make([]map[string]labels.Labels, len(rules)),
		done:                 make(chan struct{}),
		terminated:           make(chan struct{}),
		logger:               log.With(opts.Logger, "group", name),
		metrics:              metrics,
	}
}

func NewGroup ( name , file string , interval time . Duration , rules [ ] Rule , shouldRestore bool , opts * ManagerOptions ) * Group { metrics := opts . Metrics if metrics == nil { metrics = NewGroupMetrics ( opts . Registerer ) } metrics . groupLastEvalTime . WithLabelValues ( groupKey ( file , name ) ) metrics . groupLastDuration . WithLabelValues ( groupKey ( file , name ) ) metrics . groupRules . WithLabelValues ( groupKey ( file , name ) ) . Set ( float64 ( len ( rules ) ) ) return & Group { name : name , file : file , interval : interval , rules : rules , shouldRestore : shouldRestore , opts : opts , seriesInPreviousEval : make ( [ ] map [ string ] labels . Labels , len ( rules ) ) , done : make ( chan struct { } ) , terminated : make ( chan struct { } ) , logger : log . With ( opts . Logger , " " , name ) , metrics : metrics , } }

// NewGroup makes a new Group with the given name, options, and rules.

NewGroup makes a new Group with the given name options and rules .


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

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

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

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


func (g *Group) setEvaluationDuration(dur time.Duration) {
	g.metrics.groupLastDuration.WithLabelValues(groupKey(g.file, g.name)).Set(dur.Seconds())

	g.mtx.Lock()
	defer g.mtx.Unlock()
	g.evaluationDuration = dur
}

func ( g * Group ) setEvaluationDuration ( dur time . Duration ) { g . metrics . groupLastDuration . WithLabelValues ( groupKey ( g . file , g . name ) ) . Set ( dur . Seconds ( ) ) g . mtx . Lock ( ) defer g . mtx . Unlock ( ) g . evaluationDuration = dur }

// setEvaluationDuration sets the time in seconds the last evaluation took.

setEvaluationDuration sets the time in seconds the last evaluation took .


func (g *Group) GetEvaluationTimestamp() time.Time {
	g.mtx.Lock()
	defer g.mtx.Unlock()
	return g.evaluationTimestamp
}

func ( g * Group ) GetEvaluationTimestamp ( ) time . Time { g . mtx . Lock ( ) defer g . mtx . Unlock ( ) return g . evaluationTimestamp }

// GetEvaluationTimestamp returns the time the last evaluation of the rule group took place.

GetEvaluationTimestamp returns the time the last evaluation of the rule group took place .


func (g *Group) setEvaluationTimestamp(ts time.Time) {
	g.metrics.groupLastEvalTime.WithLabelValues(groupKey(g.file, g.name)).Set(float64(ts.UnixNano()) / 1e9)

	g.mtx.Lock()
	defer g.mtx.Unlock()
	g.evaluationTimestamp = ts
}

func ( g * Group ) setEvaluationTimestamp ( ts time . Time ) { g . metrics . groupLastEvalTime . WithLabelValues ( groupKey ( g . file , g . name ) ) . Set ( float64 ( ts . UnixNano ( ) ) / 1e9 ) g . mtx . Lock ( ) defer g . mtx . Unlock ( ) g . evaluationTimestamp = ts }

// setEvaluationTimestamp updates evaluationTimestamp to the timestamp of when the rule group was last evaluated.

setEvaluationTimestamp updates evaluationTimestamp to the timestamp of when the rule group was last evaluated .


func (g *Group) evalTimestamp() time.Time {
	var (
		offset = int64(g.hash() % uint64(g.interval))
		now    = time.Now().UnixNano()
		adjNow = now - offset
		base   = adjNow - (adjNow % int64(g.interval))
	)

	return time.Unix(0, base+offset)
}

func ( g * Group ) evalTimestamp ( ) time . Time { var ( offset = int64 ( g . hash ( ) % uint64 ( g . interval ) ) now = time . Now ( ) . UnixNano ( ) adjNow = now - offset base = adjNow - ( adjNow % int64 ( g . interval ) ) ) return time . Unix ( 0 , base + offset ) }

// evalTimestamp returns the immediately preceding consistently slotted evaluation time.

evalTimestamp returns the immediately preceding consistently slotted evaluation time .


func (g *Group) CopyState(from *Group) {
	g.evaluationDuration = from.evaluationDuration

	ruleMap := make(map[string][]int, len(from.rules))

	for fi, fromRule := range from.rules {
		nameAndLabels := nameAndLabels(fromRule)
		l := ruleMap[nameAndLabels]
		ruleMap[nameAndLabels] = append(l, fi)
	}

	for i, rule := range g.rules {
		nameAndLabels := nameAndLabels(rule)
		indexes := ruleMap[nameAndLabels]
		if len(indexes) == 0 {
			continue
		}
		fi := indexes[0]
		g.seriesInPreviousEval[i] = from.seriesInPreviousEval[fi]
		ruleMap[nameAndLabels] = indexes[1:]

		ar, ok := rule.(*AlertingRule)
		if !ok {
			continue
		}
		far, ok := from.rules[fi].(*AlertingRule)
		if !ok {
			continue
		}

		for fp, a := range far.active {
			ar.active[fp] = a
		}
	}
}

func ( g * Group ) CopyState ( from * Group ) { g . evaluationDuration = from . evaluationDuration ruleMap := make ( map [ string ] [ ] int , len ( from . rules ) ) for fi , fromRule := range from . rules { nameAndLabels := nameAndLabels ( fromRule ) l := ruleMap [ nameAndLabels ] ruleMap [ nameAndLabels ] = append ( l , fi ) } for i , rule := range g . rules { nameAndLabels := nameAndLabels ( rule ) indexes := ruleMap [ nameAndLabels ] if len ( indexes ) == 0 { continue } fi := indexes [ 0 ] g . seriesInPreviousEval [ i ] = from . seriesInPreviousEval [ fi ] ruleMap [ nameAndLabels ] = indexes [ 1 : ] ar , ok := rule . ( * AlertingRule ) if ! ok { continue } far , ok := from . rules [ fi ] . ( * AlertingRule ) if ! ok { continue } for fp , a := range far . active { ar . active [ fp ] = a } } }

// CopyState copies the alerting rule and staleness related state from the given group.
//
// Rules are matched based on their name and labels. If there are duplicates, the
// first is matched with the first, second with the second etc.

CopyState copies the alerting rule and staleness related state from the given group . Rules are matched based on their name and labels . If there are duplicates the first is matched with the first second with the second etc .


func NewManager(o *ManagerOptions) *Manager {
	if o.Metrics == nil {
		o.Metrics = NewGroupMetrics(o.Registerer)
	}

	m := &Manager{
		groups: map[string]*Group{},
		opts:   o,
		block:  make(chan struct{}),
		logger: o.Logger,
	}

	if o.Registerer != nil {
		o.Registerer.MustRegister(m)
	}

	o.Metrics.iterationsMissed.Inc()
	return m
}

func NewManager ( o * ManagerOptions ) * Manager { if o . Metrics == nil { o . Metrics = NewGroupMetrics ( o . Registerer ) } m := & Manager { groups : map [ string ] * Group { } , opts : o , block : make ( chan struct { } ) , logger : o . Logger , } if o . Registerer != nil { o . Registerer . MustRegister ( m ) } o . Metrics . iterationsMissed . Inc ( ) return m }

// NewManager returns an implementation of Manager, ready to be started
// by calling the Run method.

NewManager returns an implementation of Manager ready to be started by calling the Run method .


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

	level.Info(m.logger).Log("msg", "Stopping rule manager...")

	for _, eg := range m.groups {
		eg.stop()
	}

	level.Info(m.logger).Log("msg", "Rule manager stopped")
}

func ( m * Manager ) Stop ( ) { m . mtx . Lock ( ) defer m . mtx . Unlock ( ) level . Info ( m . logger ) . Log ( " " , " " ) for _ , eg := range m . groups { eg . stop ( ) } level . Info ( m . logger ) . Log ( " " , " " ) }

// Stop the rule manager's rule evaluation cycles.

Stop the rule manager s rule evaluation cycles .


func (m *Manager) Update(interval time.Duration, files []string, externalLabels labels.Labels) error {
	m.mtx.Lock()
	defer m.mtx.Unlock()

	groups, errs := m.LoadGroups(interval, externalLabels, files...)
	if errs != nil {
		for _, e := range errs {
			level.Error(m.logger).Log("msg", "loading groups failed", "err", e)
		}
		return errors.New("error loading rules, previous rule set restored")
	}
	m.restored = true

	var wg sync.WaitGroup

	for _, newg := range groups {
		wg.Add(1)

		// If there is an old group with the same identifier, stop it and wait for
		// it to finish the current iteration. Then copy it into the new group.
		gn := groupKey(newg.name, newg.file)
		oldg, ok := m.groups[gn]
		delete(m.groups, gn)

		go func(newg *Group) {
			if ok {
				oldg.stop()
				newg.CopyState(oldg)
			}
			go func() {
				// Wait with starting evaluation until the rule manager
				// is told to run. This is necessary to avoid running
				// queries against a bootstrapping storage.
				<-m.block
				newg.run(m.opts.Context)
			}()
			wg.Done()
		}(newg)
	}

	// Stop remaining old groups.
	for _, oldg := range m.groups {
		oldg.stop()
	}

	wg.Wait()
	m.groups = groups

	return nil
}

// Update the rule manager's state as the config requires. If
// loading the new rules failed the old rule set is restored.

Update the rule manager s state as the config requires . If loading the new rules failed the old rule set is restored .


func (m *Manager) LoadGroups(
	interval time.Duration, externalLabels labels.Labels, filenames ...string,
) (map[string]*Group, []error) {
	groups := make(map[string]*Group)

	shouldRestore := !m.restored

	for _, fn := range filenames {
		rgs, errs := rulefmt.ParseFile(fn)
		if errs != nil {
			return nil, errs
		}

		for _, rg := range rgs.Groups {
			itv := interval
			if rg.Interval != 0 {
				itv = time.Duration(rg.Interval)
			}

			rules := make([]Rule, 0, len(rg.Rules))
			for _, r := range rg.Rules {
				expr, err := promql.ParseExpr(r.Expr)
				if err != nil {
					return nil, []error{err}
				}

				if r.Alert != "" {
					rules = append(rules, NewAlertingRule(
						r.Alert,
						expr,
						time.Duration(r.For),
						labels.FromMap(r.Labels),
						labels.FromMap(r.Annotations),
						externalLabels,
						m.restored,
						log.With(m.logger, "alert", r.Alert),
					))
					continue
				}
				rules = append(rules, NewRecordingRule(
					r.Record,
					expr,
					labels.FromMap(r.Labels),
				))
			}

			groups[groupKey(rg.Name, fn)] = NewGroup(rg.Name, fn, itv, rules, shouldRestore, m.opts)
		}
	}

	return groups, nil
}

func ( m * Manager ) LoadGroups ( interval time . Duration , externalLabels labels . Labels , filenames ... string , ) ( map [ string ] * Group , [ ] error ) { groups := make ( map [ string ] * Group ) shouldRestore := ! m . restored for _ , fn := range filenames { rgs , errs := rulefmt . ParseFile ( fn ) if errs != nil { return nil , errs } for _ , rg := range rgs . Groups { itv := interval if rg . Interval != 0 { itv = time . Duration ( rg . Interval ) } rules := make ( [ ] Rule , 0 , len ( rg . Rules ) ) for _ , r := range rg . Rules { expr , err := promql . ParseExpr ( r . Expr ) if err != nil { return nil , [ ] error { err } } if r . Alert != " " { rules = append ( rules , NewAlertingRule ( r . Alert , expr , time . Duration ( r . For ) , labels . FromMap ( r . Labels ) , labels . FromMap ( r . Annotations ) , externalLabels , m . restored , log . With ( m . logger , " " , r . Alert ) , ) ) continue } rules = append ( rules , NewRecordingRule ( r . Record , expr , labels . FromMap ( r . Labels ) , ) ) } groups [ groupKey ( rg . Name , fn ) ] = NewGroup ( rg . Name , fn , itv , rules , shouldRestore , m . opts ) } } return groups , nil }

// LoadGroups reads groups from a list of files.

LoadGroups reads groups from a list of files .


func (m *Manager) RuleGroups() []*Group {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	rgs := make([]*Group, 0, len(m.groups))
	for _, g := range m.groups {
		rgs = append(rgs, g)
	}

	// Sort rule groups by file, then by name.
	sort.Slice(rgs, func(i, j int) bool {
		if rgs[i].file != rgs[j].file {
			return rgs[i].file < rgs[j].file
		}
		return rgs[i].name < rgs[j].name
	})

	return rgs
}

// RuleGroups returns the list of manager's rule groups.

RuleGroups returns the list of manager s rule groups .


func (m *Manager) Rules() []Rule {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	var rules []Rule
	for _, g := range m.groups {
		rules = append(rules, g.rules...)
	}

	return rules
}

func ( m * Manager ) Rules ( ) [ ] Rule { m . mtx . RLock ( ) defer m . mtx . RUnlock ( ) var rules [ ] Rule for _ , g := range m . groups { rules = append ( rules , g . rules ... ) } return rules }

// Rules returns the list of the manager's rules.

Rules returns the list of the manager s rules .


func (m *Manager) AlertingRules() []*AlertingRule {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	alerts := []*AlertingRule{}
	for _, rule := range m.Rules() {
		if alertingRule, ok := rule.(*AlertingRule); ok {
			alerts = append(alerts, alertingRule)
		}
	}
	return alerts
}

func ( m * Manager ) AlertingRules ( ) [ ] * AlertingRule { m . mtx . RLock ( ) defer m . mtx . RUnlock ( ) alerts := [ ] * AlertingRule { } for _ , rule := range m . Rules ( ) { if alertingRule , ok := rule . ( * AlertingRule ) ; ok { alerts = append ( alerts , alertingRule ) } } return alerts }

// AlertingRules returns the list of the manager's alerting rules.

AlertingRules returns the list of the manager s alerting rules .


func (m *Manager) Collect(ch chan<- prometheus.Metric) {
	for _, g := range m.RuleGroups() {
		ch <- prometheus.MustNewConstMetric(groupInterval,
			prometheus.GaugeValue,
			g.interval.Seconds(),
			groupKey(g.file, g.name))
	}
}

func ( m * Manager ) Collect ( ch chan <- prometheus . Metric ) { for _ , g := range m . RuleGroups ( ) { ch <- prometheus . MustNewConstMetric ( groupInterval , prometheus . GaugeValue , g . interval . Seconds ( ) , groupKey ( g . file , g . name ) ) } }

// Collect implements prometheus.Collector.

Collect implements prometheus . Collector .


func NewWALWatcher(logger log.Logger, name string, writer writeTo, walDir string) *WALWatcher {
	if logger == nil {
		logger = log.NewNopLogger()
	}
	return &WALWatcher{
		logger: logger,
		writer: writer,
		walDir: path.Join(walDir, "wal"),
		name:   name,
		quit:   make(chan struct{}),
		done:   make(chan struct{}),

		maxSegment: -1,
	}
}

func NewWALWatcher ( logger log . Logger , name string , writer writeTo , walDir string ) * WALWatcher { if logger == nil { logger = log . NewNopLogger ( ) } return & WALWatcher { logger : logger , writer : writer , walDir : path . Join ( walDir , " " ) , name : name , quit : make ( chan struct { } ) , done : make ( chan struct { } ) , maxSegment : - 1 , } }

// NewWALWatcher creates a new WAL watcher for a given WriteTo.

NewWALWatcher creates a new WAL watcher for a given WriteTo .


func (w *WALWatcher) Start() {
	w.setMetrics()
	level.Info(w.logger).Log("msg", "starting WAL watcher", "queue", w.name)

	go w.loop()
}

func ( w * WALWatcher ) Start ( ) { w . setMetrics ( ) level . Info ( w . logger ) . Log ( " " , " " , " " , w . name ) go w . loop ( ) }


func (w *WALWatcher) Stop() {
	close(w.quit)
	<-w.done

	// Records read metric has series and samples.
	watcherRecordsRead.DeleteLabelValues(w.name, "series")
	watcherRecordsRead.DeleteLabelValues(w.name, "samples")
	watcherRecordDecodeFails.DeleteLabelValues(w.name)
	watcherSamplesSentPreTailing.DeleteLabelValues(w.name)
	watcherCurrentSegment.DeleteLabelValues(w.name)

	level.Info(w.logger).Log("msg", "WAL watcher stopped", "queue", w.name)
}


func (w *WALWatcher) findSegmentForIndex(index int) (int, error) {
	refs, err := w.segments(w.walDir)
	if err != nil {
		return -1, nil
	}

	for _, r := range refs {
		if r >= index {
			return r, nil
		}
	}

	return -1, errors.New("failed to find segment for index")
}

func ( w * WALWatcher ) findSegmentForIndex ( index int ) ( int , error ) { refs , err := w . segments ( w . walDir ) if err != nil { return - 1 , nil } for _ , r := range refs { if r >= index { return r , nil } } return - 1 , errors . New ( " " ) }

// findSegmentForIndex finds the first segment greater than or equal to index.

findSegmentForIndex finds the first segment greater than or equal to index .


func (w *WALWatcher) watch(segmentNum int, tail bool) error {
	segment, err := wal.OpenReadSegment(wal.SegmentName(w.walDir, segmentNum))
	if err != nil {
		return err
	}
	defer segment.Close()

	reader := wal.NewLiveReader(w.logger, segment)

	readTicker := time.NewTicker(readPeriod)
	defer readTicker.Stop()

	checkpointTicker := time.NewTicker(checkpointPeriod)
	defer checkpointTicker.Stop()

	segmentTicker := time.NewTicker(segmentCheckPeriod)
	defer segmentTicker.Stop()

	// If we're replaying the segment we need to know the size of the file to know
	// when to return from watch and move on to the next segment.
	size := int64(math.MaxInt64)
	if !tail {
		segmentTicker.Stop()
		checkpointTicker.Stop()
		var err error
		size, err = getSegmentSize(w.walDir, segmentNum)
		if err != nil {
			return errors.Wrap(err, "getSegmentSize")
		}
	}

	for {
		select {
		case <-w.quit:
			return nil

		case <-checkpointTicker.C:
			// Periodically check if there is a new checkpoint so we can garbage
			// collect labels. As this is considered an optimisation, we ignore
			// errors during checkpoint processing.
			if err := w.garbageCollectSeries(segmentNum); err != nil {
				level.Warn(w.logger).Log("msg", "error process checkpoint", "err", err)
			}

		case <-segmentTicker.C:
			_, last, err := w.firstAndLast()
			if err != nil {
				return errors.Wrap(err, "segments")
			}

			// Check if new segments exists.
			if last <= segmentNum {
				continue
			}

			err = w.readSegment(reader, segmentNum, tail)

			// Ignore errors reading to end of segment whilst replaying the WAL.
			if !tail {
				if err != nil && err != io.EOF {
					level.Warn(w.logger).Log("msg", "ignoring error reading to end of segment, may have dropped data", "err", err)
				} else if reader.Offset() != size {
					level.Warn(w.logger).Log("msg", "expected to have read whole segment, may have dropped data", "segment", segmentNum, "read", reader.Offset(), "size", size)
				}
				return nil
			}

			// Otherwise, when we are tailing, non-EOFs are fatal.
			if err != io.EOF {
				return err
			}

			return nil

		case <-readTicker.C:
			err = w.readSegment(reader, segmentNum, tail)

			// Ignore all errors reading to end of segment whilst replaying the WAL.
			if !tail {
				if err != nil && err != io.EOF {
					level.Warn(w.logger).Log("msg", "ignoring error reading to end of segment, may have dropped data", "segment", segmentNum, "err", err)
				} else if reader.Offset() != size {
					level.Warn(w.logger).Log("msg", "expected to have read whole segment, may have dropped data", "segment", segmentNum, "read", reader.Offset(), "size", size)
				}
				return nil
			}

			// Otherwise, when we are tailing, non-EOFs are fatal.
			if err != io.EOF {
				return err
			}
		}
	}
}

// Use tail true to indicate that the reader is currently on a segment that is
// actively being written to. If false, assume it's a full segment and we're
// replaying it on start to cache the series records.

Use tail true to indicate that the reader is currently on a segment that is actively being written to . If false assume it s a full segment and we re replaying it on start to cache the series records .


func (w *WALWatcher) readCheckpoint(checkpointDir string) error {
	level.Debug(w.logger).Log("msg", "reading checkpoint", "dir", checkpointDir)
	index, err := checkpointNum(checkpointDir)
	if err != nil {
		return errors.Wrap(err, "checkpointNum")
	}

	// Ensure we read the whole contents of every segment in the checkpoint dir.
	segs, err := w.segments(checkpointDir)
	if err != nil {
		return errors.Wrap(err, "Unable to get segments checkpoint dir")
	}
	for _, seg := range segs {
		size, err := getSegmentSize(checkpointDir, seg)
		if err != nil {
			return errors.Wrap(err, "getSegmentSize")
		}

		sr, err := wal.OpenReadSegment(wal.SegmentName(checkpointDir, seg))
		if err != nil {
			return errors.Wrap(err, "unable to open segment")
		}
		defer sr.Close()

		r := wal.NewLiveReader(w.logger, sr)
		if err := w.readSegment(r, index, false); err != io.EOF && err != nil {
			return errors.Wrap(err, "readSegment")
		}

		if r.Offset() != size {
			return fmt.Errorf("readCheckpoint wasn't able to read all data from the checkpoint %s/%08d, size: %d, totalRead: %d", checkpointDir, seg, size, r.Offset())
		}
	}

	level.Debug(w.logger).Log("msg", "read series references from checkpoint", "checkpoint", checkpointDir)
	return nil
}

// Read all the series records from a Checkpoint directory.

Read all the series records from a Checkpoint directory .


func getSegmentSize(dir string, index int) (int64, error) {
	i := int64(-1)
	fi, err := os.Stat(wal.SegmentName(dir, index))
	if err == nil {
		i = fi.Size()
	}
	return i, err
}

func getSegmentSize ( dir string , index int ) ( int64 , error ) { i := int64 ( - 1 ) fi , err := os . Stat ( wal . SegmentName ( dir , index ) ) if err == nil { i = fi . Size ( ) } return i , err }


func (zl ZookeeperLogger) Printf(s string, i ...interface{}) {
	level.Info(zl.logger).Log("msg", fmt.Sprintf(s, i...))
}

func ( zl ZookeeperLogger ) Printf ( s string , i ... interface { } ) { level . Info ( zl . logger ) . Log ( " " , fmt . Sprintf ( s , i ... ) ) }


func NewZookeeperTreeCache(conn *zk.Conn, path string, events chan ZookeeperTreeCacheEvent, logger log.Logger) *ZookeeperTreeCache {
	tc := &ZookeeperTreeCache{
		conn:   conn,
		prefix: path,
		events: events,
		stop:   make(chan struct{}),

		logger: logger,
	}
	tc.head = &zookeeperTreeCacheNode{
		events:   make(chan zk.Event),
		children: map[string]*zookeeperTreeCacheNode{},
		stopped:  true,
	}
	go tc.loop(path)
	return tc
}

func NewZookeeperTreeCache ( conn * zk . Conn , path string , events chan ZookeeperTreeCacheEvent , logger log . Logger ) * ZookeeperTreeCache { tc := & ZookeeperTreeCache { conn : conn , prefix : path , events : events , stop : make ( chan struct { } ) , logger : logger , } tc . head = & zookeeperTreeCacheNode { events : make ( chan zk . Event ) , children : map [ string ] * zookeeperTreeCacheNode { } , stopped : true , } go tc . loop ( path ) return tc }

// NewZookeeperTreeCache creates a new ZookeeperTreeCache for a given path.

NewZookeeperTreeCache creates a new ZookeeperTreeCache for a given path .


func NewManager(ctx context.Context, logger log.Logger, options ...func(*Manager)) *Manager {
	if logger == nil {
		logger = log.NewNopLogger()
	}
	mgr := &Manager{
		logger:         logger,
		syncCh:         make(chan map[string][]*targetgroup.Group),
		targets:        make(map[poolKey]map[string]*targetgroup.Group),
		discoverCancel: []context.CancelFunc{},
		ctx:            ctx,
		updatert:       5 * time.Second,
		triggerSend:    make(chan struct{}, 1),
	}
	for _, option := range options {
		option(mgr)
	}
	return mgr
}

func NewManager ( ctx context . Context , logger log . Logger , options ... func ( * Manager ) ) * Manager { if logger == nil { logger = log . NewNopLogger ( ) } mgr := & Manager { logger : logger , syncCh : make ( chan map [ string ] [ ] * targetgroup . Group ) , targets : make ( map [ poolKey ] map [ string ] * targetgroup . Group ) , discoverCancel : [ ] context . CancelFunc { } , ctx : ctx , updatert : 5 * time . Second , triggerSend : make ( chan struct { } , 1 ) , } for _ , option := range options { option ( mgr ) } return mgr }

// NewManager is the Discovery Manager constructor.

NewManager is the Discovery Manager constructor .


func Name(n string) func(*Manager) {
	return func(m *Manager) {
		m.mtx.Lock()
		defer m.mtx.Unlock()
		m.name = n
	}
}

func Name ( n string ) func ( * Manager ) { return func ( m * Manager ) { m . mtx . Lock ( ) defer m . mtx . Unlock ( ) m . name = n } }


func (m *Manager) Run() error {
	go m.sender()
	for range m.ctx.Done() {
		m.cancelDiscoverers()
		return m.ctx.Err()
	}
	return nil
}

func ( m * Manager ) Run ( ) error { go m . sender ( ) for range m . ctx . Done ( ) { m . cancelDiscoverers ( ) return m . ctx . Err ( ) } return nil }


func (m *Manager) ApplyConfig(cfg map[string]sd_config.ServiceDiscoveryConfig) error {
	m.mtx.Lock()
	defer m.mtx.Unlock()

	for pk := range m.targets {
		if _, ok := cfg[pk.setName]; !ok {
			discoveredTargets.DeleteLabelValues(m.name, pk.setName)
		}
	}
	m.cancelDiscoverers()
	for name, scfg := range cfg {
		m.registerProviders(scfg, name)
		discoveredTargets.WithLabelValues(m.name, name).Set(0)
	}
	for _, prov := range m.providers {
		m.startProvider(m.ctx, prov)
	}

	return nil
}

func ( m * Manager ) ApplyConfig ( cfg map [ string ] sd_config . ServiceDiscoveryConfig ) error { m . mtx . Lock ( ) defer m . mtx . Unlock ( ) for pk := range m . targets { if _ , ok := cfg [ pk . setName ] ; ! ok { discoveredTargets . DeleteLabelValues ( m . name , pk . setName ) } } m . cancelDiscoverers ( ) for name , scfg := range cfg { m . registerProviders ( scfg , name ) discoveredTargets . WithLabelValues ( m . name , name ) . Set ( 0 ) } for _ , prov := range m . providers { m . startProvider ( m . ctx , prov ) } return nil }

// ApplyConfig removes all running discovery providers and starts new ones using the provided config.

ApplyConfig removes all running discovery providers and starts new ones using the provided config .


func (m *Manager) StartCustomProvider(ctx context.Context, name string, worker Discoverer) {
	p := &provider{
		name: name,
		d:    worker,
		subs: []string{name},
	}
	m.providers = append(m.providers, p)
	m.startProvider(ctx, p)
}

func ( m * Manager ) StartCustomProvider ( ctx context . Context , name string , worker Discoverer ) { p := & provider { name : name , d : worker , subs : [ ] string { name } , } m . providers = append ( m . providers , p ) m . startProvider ( ctx , p ) }

// StartCustomProvider is used for sdtool. Only use this if you know what you're doing.

StartCustomProvider is used for sdtool . Only use this if you know what you re doing .


func (sd *StaticProvider) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
	// We still have to consider that the consumer exits right away in which case
	// the context will be canceled.
	select {
	case ch <- sd.TargetGroups:
	case <-ctx.Done():
	}
	close(ch)
}


func NewNerveDiscovery(conf *NerveSDConfig, logger log.Logger) (*Discovery, error) {
	return NewDiscovery(conf.Servers, time.Duration(conf.Timeout), conf.Paths, logger, parseNerveMember)
}

func NewNerveDiscovery ( conf * NerveSDConfig , logger log . Logger ) ( * Discovery , error ) { return NewDiscovery ( conf . Servers , time . Duration ( conf . Timeout ) , conf . Paths , logger , parseNerveMember ) }

// NewNerveDiscovery returns a new Discovery for the given Nerve config.

NewNerveDiscovery returns a new Discovery for the given Nerve config .