2015-01-21 20:07:45 +01:00
// Copyright 2013 The Prometheus Authors
2013-01-04 12:17:31 +01:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2013-07-14 23:03:56 +02:00
2018-02-01 09:55:07 +00:00
package scrape
2012-12-25 13:50:36 +01:00
import (
2013-01-04 14:41:47 +01:00
"fmt"
2016-02-28 19:56:18 +01:00
"hash/fnv"
2016-11-22 12:48:30 +01:00
"net"
2015-02-19 18:58:47 +01:00
"net/url"
2013-04-10 14:26:07 +02:00
"strings"
2014-12-03 18:07:23 +01:00
"sync"
2012-12-25 13:50:36 +01:00
"time"
2013-06-25 14:02:27 +02:00
2019-03-25 16:01:12 -07:00
"github.com/pkg/errors"
2015-08-20 17:18:46 +02:00
"github.com/prometheus/common/model"
2013-07-30 17:18:07 +02:00
2015-04-20 12:24:25 +02:00
"github.com/prometheus/prometheus/config"
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-30 01:31:34 +05:30
"github.com/prometheus/prometheus/discovery/targetgroup"
2016-12-29 09:27:30 +01:00
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/relabel"
2018-05-18 03:32:11 -04:00
"github.com/prometheus/prometheus/pkg/textparse"
2017-05-29 14:08:55 +01:00
"github.com/prometheus/prometheus/pkg/value"
2015-03-15 03:36:15 +01:00
"github.com/prometheus/prometheus/storage"
2012-12-25 13:50:36 +01:00
)
2015-05-18 13:14:41 +02:00
// TargetHealth describes the health state of a target.
2016-02-28 20:23:26 +01:00
type TargetHealth string
2015-08-21 23:01:08 +02:00
2016-02-28 20:23:26 +01:00
// The possible health states of a target based on the last performed scrape.
2012-12-25 13:50:36 +01:00
const (
2016-02-28 20:23:26 +01:00
HealthUnknown TargetHealth = "unknown"
HealthGood TargetHealth = "up"
HealthBad TargetHealth = "down"
2012-12-25 13:50:36 +01:00
)
2015-05-18 13:14:41 +02:00
// Target refers to a singular HTTP or HTTPS endpoint.
type Target struct {
2015-06-05 21:42:39 +01:00
// Labels before any processing.
2016-12-29 09:27:30 +01:00
discoveredLabels labels . Labels
2016-02-15 10:31:38 +01:00
// Any labels that are added to this target and its metrics.
2016-12-29 09:27:30 +01:00
labels labels . Labels
2019-08-02 21:52:15 +08:00
// Additional URL parameters that are part of the target URL.
2016-02-28 19:56:18 +01:00
params url . Values
2016-02-28 20:23:26 +01:00
2018-10-12 12:26:59 -04:00
mtx sync . RWMutex
lastError error
lastScrape time . Time
lastScrapeDuration time . Duration
health TargetHealth
2019-12-04 15:18:27 +00:00
metadata MetricMetadataStore
2012-12-25 13:50:36 +01:00
}
2014-12-10 16:16:49 +01:00
// NewTarget creates a reasonably configured target for querying.
2016-12-29 09:27:30 +01:00
func NewTarget ( labels , discoveredLabels labels . Labels , params url . Values ) * Target {
2016-02-28 19:21:50 +01:00
return & Target {
2016-12-02 13:31:43 +01:00
labels : labels ,
discoveredLabels : discoveredLabels ,
params : params ,
health : HealthUnknown ,
2013-01-04 14:41:47 +01:00
}
2015-03-15 03:36:15 +01:00
}
2013-04-16 17:22:10 +02:00
2015-05-18 13:14:41 +02:00
func ( t * Target ) String ( ) string {
2016-02-28 19:56:18 +01:00
return t . URL ( ) . String ( )
2016-02-12 15:43:27 +01:00
}
2019-12-04 15:18:27 +00:00
type MetricMetadataStore interface {
ListMetadata ( ) [ ] MetricMetadata
GetMetadata ( metric string ) ( MetricMetadata , bool )
2020-01-29 11:13:18 +00:00
SizeMetadata ( ) int
LengthMetadata ( ) int
2018-05-18 03:32:11 -04:00
}
// MetricMetadata is a piece of metadata for a metric.
type MetricMetadata struct {
Metric string
Type textparse . MetricType
Help string
2018-10-05 17:11:16 +01:00
Unit string
2018-05-18 03:32:11 -04:00
}
func ( t * Target ) MetadataList ( ) [ ] MetricMetadata {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
if t . metadata == nil {
return nil
}
2019-12-04 15:18:27 +00:00
return t . metadata . ListMetadata ( )
2018-05-18 03:32:11 -04:00
}
2020-01-29 11:13:18 +00:00
func ( t * Target ) MetadataSize ( ) int {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
if t . metadata == nil {
return 0
}
return t . metadata . SizeMetadata ( )
}
func ( t * Target ) MetadataLength ( ) int {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
if t . metadata == nil {
return 0
}
return t . metadata . LengthMetadata ( )
}
2018-05-18 03:32:11 -04:00
// Metadata returns type and help metadata for the given metric.
func ( t * Target ) Metadata ( metric string ) ( MetricMetadata , bool ) {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
if t . metadata == nil {
return MetricMetadata { } , false
}
2019-12-04 15:18:27 +00:00
return t . metadata . GetMetadata ( metric )
2018-05-18 03:32:11 -04:00
}
2019-12-04 15:18:27 +00:00
func ( t * Target ) SetMetadataStore ( s MetricMetadataStore ) {
2018-05-18 03:32:11 -04:00
t . mtx . Lock ( )
defer t . mtx . Unlock ( )
t . metadata = s
}
2016-02-28 19:56:18 +01:00
// hash returns an identifying hash for the target.
func ( t * Target ) hash ( ) uint64 {
h := fnv . New64a ( )
2019-05-03 15:11:28 +02:00
//nolint: errcheck
2016-12-29 09:27:30 +01:00
h . Write ( [ ] byte ( fmt . Sprintf ( "%016d" , t . labels . Hash ( ) ) ) )
2019-05-03 15:11:28 +02:00
//nolint: errcheck
2016-02-28 19:56:18 +01:00
h . Write ( [ ] byte ( t . URL ( ) . String ( ) ) )
2016-02-15 15:22:57 +01:00
2016-02-28 19:56:18 +01:00
return h . Sum64 ( )
2016-02-15 15:22:57 +01:00
}
// offset returns the time until the next scrape cycle for the target.
2019-03-12 10:46:15 +00:00
// It includes the global server jitterSeed for scrapes from multiple Prometheus to try to be at different times.
func ( t * Target ) offset ( interval time . Duration , jitterSeed uint64 ) time . Duration {
2016-02-15 15:22:57 +01:00
now := time . Now ( ) . UnixNano ( )
2019-03-12 10:46:15 +00:00
// Base is a pinned to absolute time, no matter how often offset is called.
2016-02-15 15:22:57 +01:00
var (
2018-12-05 17:58:39 +08:00
base = int64 ( interval ) - now % int64 ( interval )
2019-03-12 10:46:15 +00:00
offset = ( t . hash ( ) ^ jitterSeed ) % uint64 ( interval )
2016-02-15 15:22:57 +01:00
next = base + int64 ( offset )
)
if next > int64 ( interval ) {
next -= int64 ( interval )
}
return time . Duration ( next )
}
2016-02-28 19:56:18 +01:00
// Labels returns a copy of the set of all public labels of the target.
2016-12-29 09:27:30 +01:00
func ( t * Target ) Labels ( ) labels . Labels {
lset := make ( labels . Labels , 0 , len ( t . labels ) )
for _ , l := range t . labels {
if ! strings . HasPrefix ( l . Name , model . ReservedLabelPrefix ) {
lset = append ( lset , l )
2016-02-28 19:56:18 +01:00
}
}
return lset
2016-02-12 15:43:27 +01:00
}
2016-12-02 13:31:43 +01:00
// DiscoveredLabels returns a copy of the target's labels before any processing.
2016-12-29 09:27:30 +01:00
func ( t * Target ) DiscoveredLabels ( ) labels . Labels {
2018-04-10 00:08:26 +03:00
t . mtx . Lock ( )
defer t . mtx . Unlock ( )
2016-12-29 09:27:30 +01:00
lset := make ( labels . Labels , len ( t . discoveredLabels ) )
copy ( lset , t . discoveredLabels )
return lset
2016-02-12 15:43:27 +01:00
}
2018-02-07 12:29:27 +02:00
// SetDiscoveredLabels sets new DiscoveredLabels
func ( t * Target ) SetDiscoveredLabels ( l labels . Labels ) {
2018-04-10 00:08:26 +03:00
t . mtx . Lock ( )
defer t . mtx . Unlock ( )
2018-02-07 12:29:27 +02:00
t . discoveredLabels = l
}
2016-02-12 15:43:27 +01:00
// URL returns a copy of the target's URL.
func ( t * Target ) URL ( ) * url . URL {
params := url . Values { }
2016-02-28 19:56:18 +01:00
for k , v := range t . params {
2016-02-12 15:43:27 +01:00
params [ k ] = make ( [ ] string , len ( v ) )
copy ( params [ k ] , v )
}
2016-12-29 09:27:30 +01:00
for _ , l := range t . labels {
if ! strings . HasPrefix ( l . Name , model . ParamLabelPrefix ) {
2016-02-12 15:43:27 +01:00
continue
}
2016-12-29 09:27:30 +01:00
ks := l . Name [ len ( model . ParamLabelPrefix ) : ]
2016-02-12 15:43:27 +01:00
if len ( params [ ks ] ) > 0 {
2018-03-21 10:25:22 +01:00
params [ ks ] [ 0 ] = l . Value
2016-02-12 15:43:27 +01:00
} else {
2016-12-29 09:27:30 +01:00
params [ ks ] = [ ] string { l . Value }
2016-02-12 15:43:27 +01:00
}
}
return & url . URL {
2018-03-21 10:25:22 +01:00
Scheme : t . labels . Get ( model . SchemeLabel ) ,
Host : t . labels . Get ( model . AddressLabel ) ,
Path : t . labels . Get ( model . MetricsPathLabel ) ,
2016-02-12 15:43:27 +01:00
RawQuery : params . Encode ( ) ,
}
}
2019-11-11 14:42:24 -07:00
// Report sets target data about the last scrape.
func ( t * Target ) Report ( start time . Time , dur time . Duration , err error ) {
2016-02-28 20:23:26 +01:00
t . mtx . Lock ( )
defer t . mtx . Unlock ( )
if err == nil {
t . health = HealthGood
} else {
t . health = HealthBad
}
t . lastError = err
t . lastScrape = start
2018-10-12 12:26:59 -04:00
t . lastScrapeDuration = dur
2016-02-28 20:23:26 +01:00
}
// LastError returns the error encountered during the last scrape.
func ( t * Target ) LastError ( ) error {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
return t . lastError
}
// LastScrape returns the time of the last scrape.
func ( t * Target ) LastScrape ( ) time . Time {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
return t . lastScrape
}
2018-10-12 12:26:59 -04:00
// LastScrapeDuration returns how long the last scrape of the target took.
func ( t * Target ) LastScrapeDuration ( ) time . Duration {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
return t . lastScrapeDuration
}
2016-02-28 20:23:26 +01:00
// Health returns the last known health state of the target.
func ( t * Target ) Health ( ) TargetHealth {
t . mtx . RLock ( )
defer t . mtx . RUnlock ( )
return t . health
2016-02-15 16:21:03 +01:00
}
2016-03-02 09:10:20 +01:00
// Targets is a sortable list of targets.
type Targets [ ] * Target
func ( ts Targets ) Len ( ) int { return len ( ts ) }
func ( ts Targets ) Less ( i , j int ) bool { return ts [ i ] . URL ( ) . String ( ) < ts [ j ] . URL ( ) . String ( ) }
func ( ts Targets ) Swap ( i , j int ) { ts [ i ] , ts [ j ] = ts [ j ] , ts [ i ] }
2017-05-29 14:08:55 +01:00
var errSampleLimit = errors . New ( "sample limit exceeded" )
2017-01-30 17:30:28 +01:00
// limitAppender limits the number of total appended samples in a batch.
type limitAppender struct {
storage . Appender
limit int
i int
}
2017-09-07 14:14:41 +02:00
func ( app * limitAppender ) Add ( lset labels . Labels , t int64 , v float64 ) ( uint64 , error ) {
2017-05-29 14:08:55 +01:00
if ! value . IsStaleNaN ( v ) {
app . i ++
if app . i > app . limit {
2017-09-07 14:14:41 +02:00
return 0 , errSampleLimit
2017-05-29 14:08:55 +01:00
}
2017-02-01 15:59:37 +01:00
}
ref , err := app . Appender . Add ( lset , t , v )
if err != nil {
2017-09-07 14:14:41 +02:00
return 0 , err
2017-02-01 15:59:37 +01:00
}
return ref , nil
}
2020-02-06 15:58:38 +00:00
func ( app * limitAppender ) AddFast ( ref uint64 , t int64 , v float64 ) error {
2017-05-29 14:08:55 +01:00
if ! value . IsStaleNaN ( v ) {
app . i ++
if app . i > app . limit {
return errSampleLimit
}
2017-01-30 17:30:28 +01:00
}
2020-02-06 15:58:38 +00:00
err := app . Appender . AddFast ( ref , t , v )
2017-10-20 16:59:53 +03:00
return err
2017-01-30 17:30:28 +01:00
}
2017-07-04 14:55:33 +02:00
type timeLimitAppender struct {
storage . Appender
maxTime int64
}
2017-09-07 14:14:41 +02:00
func ( app * timeLimitAppender ) Add ( lset labels . Labels , t int64 , v float64 ) ( uint64 , error ) {
2017-07-04 14:55:33 +02:00
if t > app . maxTime {
2017-09-07 14:14:41 +02:00
return 0 , storage . ErrOutOfBounds
2017-07-04 14:55:33 +02:00
}
ref , err := app . Appender . Add ( lset , t , v )
if err != nil {
2017-09-07 14:14:41 +02:00
return 0 , err
2017-07-04 14:55:33 +02:00
}
return ref , nil
}
2020-02-06 15:58:38 +00:00
func ( app * timeLimitAppender ) AddFast ( ref uint64 , t int64 , v float64 ) error {
2017-07-04 14:55:33 +02:00
if t > app . maxTime {
return storage . ErrOutOfBounds
}
2020-02-06 15:58:38 +00:00
err := app . Appender . AddFast ( ref , t , v )
2017-10-20 16:59:53 +03:00
return err
2017-07-04 14:55:33 +02:00
}
2016-11-22 12:48:30 +01:00
// populateLabels builds a label set from the given label set and scrape configuration.
// It returns a label set before relabeling was applied as the second return value.
2017-12-04 15:12:28 +00:00
// Returns the original discovered label set found before relabelling was applied if the target is dropped during relabeling.
2016-12-29 09:27:30 +01:00
func populateLabels ( lset labels . Labels , cfg * config . ScrapeConfig ) ( res , orig labels . Labels , err error ) {
// Copy labels into the labelset for the target if they are not set already.
scrapeLabels := [ ] labels . Label {
{ Name : model . JobLabel , Value : cfg . JobName } ,
{ Name : model . MetricsPathLabel , Value : cfg . MetricsPath } ,
{ Name : model . SchemeLabel , Value : cfg . Scheme } ,
2016-11-22 12:48:30 +01:00
}
2016-12-29 09:27:30 +01:00
lb := labels . NewBuilder ( lset )
for _ , l := range scrapeLabels {
if lv := lset . Get ( l . Name ) ; lv == "" {
lb . Set ( l . Name , l . Value )
2016-11-22 12:48:30 +01:00
}
}
// Encode scrape query parameters as labels.
for k , v := range cfg . Params {
if len ( v ) > 0 {
2016-12-29 09:27:30 +01:00
lb . Set ( model . ParamLabelPrefix + k , v [ 0 ] )
2016-11-22 12:48:30 +01:00
}
}
2016-12-29 09:27:30 +01:00
preRelabelLabels := lb . Labels ( )
lset = relabel . Process ( preRelabelLabels , cfg . RelabelConfigs ... )
2016-11-22 12:48:30 +01:00
// Check if the target was dropped.
if lset == nil {
2017-12-04 15:12:28 +00:00
return nil , preRelabelLabels , nil
2016-11-22 12:48:30 +01:00
}
2017-06-23 13:15:44 +02:00
if v := lset . Get ( model . AddressLabel ) ; v == "" {
2019-03-25 16:01:12 -07:00
return nil , nil , errors . New ( "no address" )
2017-06-09 16:18:19 +01:00
}
2016-11-22 12:48:30 +01:00
2016-12-29 09:27:30 +01:00
lb = labels . NewBuilder ( lset )
2016-11-22 12:48:30 +01:00
// addPort checks whether we should add a default port to the address.
// If the address is not valid, we don't append a port either.
addPort := func ( s string ) bool {
// If we can split, a port exists and we don't have to add one.
if _ , _ , err := net . SplitHostPort ( s ) ; err == nil {
return false
}
// If adding a port makes it valid, the previous error
// was not due to an invalid address and we can append a port.
_ , _ , err := net . SplitHostPort ( s + ":1234" )
return err == nil
}
2016-12-29 09:27:30 +01:00
addr := lset . Get ( model . AddressLabel )
2016-11-22 12:48:30 +01:00
// If it's an address with no trailing port, infer it based on the used scheme.
2016-12-29 09:27:30 +01:00
if addPort ( addr ) {
2016-11-22 12:48:30 +01:00
// Addresses reaching this point are already wrapped in [] if necessary.
2016-12-29 09:27:30 +01:00
switch lset . Get ( model . SchemeLabel ) {
2016-11-22 12:48:30 +01:00
case "http" , "" :
addr = addr + ":80"
case "https" :
addr = addr + ":443"
default :
2019-03-25 16:01:12 -07:00
return nil , nil , errors . Errorf ( "invalid scheme: %q" , cfg . Scheme )
2016-11-22 12:48:30 +01:00
}
2016-12-29 09:27:30 +01:00
lb . Set ( model . AddressLabel , addr )
2016-11-22 12:48:30 +01:00
}
2016-12-29 09:27:30 +01:00
if err := config . CheckTargetAddress ( model . LabelValue ( addr ) ) ; err != nil {
2016-11-22 12:48:30 +01:00
return nil , nil , err
}
// Meta labels are deleted after relabelling. Other internal labels propagate to
// the target which decides whether they will be part of their label set.
2016-12-29 09:27:30 +01:00
for _ , l := range lset {
if strings . HasPrefix ( l . Name , model . MetaLabelPrefix ) {
lb . Del ( l . Name )
2016-11-22 12:48:30 +01:00
}
}
// Default the instance label to the target address.
2016-12-29 09:27:30 +01:00
if v := lset . Get ( model . InstanceLabel ) ; v == "" {
lb . Set ( model . InstanceLabel , addr )
2016-11-22 12:48:30 +01:00
}
2017-06-23 13:15:44 +02:00
res = lb . Labels ( )
for _ , l := range res {
// Check label values are valid, drop the target if not.
if ! model . LabelValue ( l . Value ) . IsValid ( ) {
2019-03-25 16:01:12 -07:00
return nil , nil , errors . Errorf ( "invalid label value for %q: %q" , l . Name , l . Value )
2017-06-23 13:15:44 +02:00
}
}
return res , preRelabelLabels , nil
2016-11-22 12:48:30 +01:00
}
// targetsFromGroup builds targets based on the given TargetGroup and config.
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-30 01:31:34 +05:30
func targetsFromGroup ( tg * targetgroup . Group , cfg * config . ScrapeConfig ) ( [ ] * Target , error ) {
2016-11-22 12:48:30 +01:00
targets := make ( [ ] * Target , 0 , len ( tg . Targets ) )
2016-12-29 09:27:30 +01:00
for i , tlset := range tg . Targets {
lbls := make ( [ ] labels . Label , 0 , len ( tlset ) + len ( tg . Labels ) )
for ln , lv := range tlset {
lbls = append ( lbls , labels . Label { Name : string ( ln ) , Value : string ( lv ) } )
}
2016-11-22 12:48:30 +01:00
for ln , lv := range tg . Labels {
2016-12-29 09:27:30 +01:00
if _ , ok := tlset [ ln ] ; ! ok {
lbls = append ( lbls , labels . Label { Name : string ( ln ) , Value : string ( lv ) } )
2016-11-22 12:48:30 +01:00
}
}
2016-12-29 09:27:30 +01:00
lset := labels . New ( lbls ... )
lbls , origLabels , err := populateLabels ( lset , cfg )
2016-11-22 12:48:30 +01:00
if err != nil {
2019-03-25 16:01:12 -07:00
return nil , errors . Wrapf ( err , "instance %d in group %s" , i , tg )
2016-11-22 12:48:30 +01:00
}
2017-12-04 15:12:28 +00:00
if lbls != nil || origLabels != nil {
2016-12-29 09:27:30 +01:00
targets = append ( targets , NewTarget ( lbls , origLabels , cfg . Params ) )
2016-11-22 12:48:30 +01:00
}
}
return targets , nil
}