From 9cea5d9df80f65b9e985887218e597227d93d25c Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Tue, 30 Apr 2013 20:20:14 +0200 Subject: [PATCH] Convert the Prometheus configuration to protocol buffers. --- Makefile | 10 +- appstate/appstate.go | 2 +- config/Makefile | 21 +- config/config.go | 159 ++--- config/config.proto | 70 +++ config/config_test.go | 62 +- config/fixtures/bad_job_option.conf.input | 21 - config/fixtures/empty.conf.printed | 8 - config/fixtures/invalid_job_name.conf.input | 3 + config/fixtures/invalid_label_name.conf.input | 10 + .../fixtures/invalid_proto_format.conf.input | 11 + .../invalid_scrape_interval.conf.input | 10 + config/fixtures/minimal.conf.input | 37 +- config/fixtures/minimal.conf.printed | 20 - config/fixtures/sample.conf.input | 98 ++-- config/fixtures/sample.conf.printed | 49 -- config/generated/.gitignore | 1 + config/helpers.go | 67 --- config/lexer.l | 56 -- config/lexer.l.go | 551 ------------------ config/load.go | 77 +-- config/parser.y | 115 ---- config/parser.y.go | 420 ------------- config/printer.go | 89 --- main.go | 2 +- retrieval/targetmanager.go | 43 +- retrieval/targetmanager_test.go | 16 +- rules/manager.go | 6 +- web/api/targets.go | 4 +- web/status.go | 2 +- 30 files changed, 366 insertions(+), 1674 deletions(-) create mode 100644 config/config.proto delete mode 100644 config/fixtures/bad_job_option.conf.input delete mode 100644 config/fixtures/empty.conf.printed create mode 100644 config/fixtures/invalid_job_name.conf.input create mode 100644 config/fixtures/invalid_label_name.conf.input create mode 100644 config/fixtures/invalid_proto_format.conf.input create mode 100644 config/fixtures/invalid_scrape_interval.conf.input delete mode 100644 config/fixtures/minimal.conf.printed delete mode 100644 config/fixtures/sample.conf.printed create mode 100644 config/generated/.gitignore delete mode 100644 config/helpers.go delete mode 100644 config/lexer.l delete mode 100644 config/lexer.l.go delete mode 100644 config/parser.y delete mode 100644 config/parser.y.go delete mode 100644 config/printer.go diff --git a/Makefile b/Makefile index 5c0e666e01..209d28b520 100644 --- a/Makefile +++ b/Makefile @@ -39,11 +39,12 @@ advice: binary: build go build $(BUILDFLAGS) -o prometheus.build -build: preparation model web +build: preparation config model web go build $(BUILDFLAGS) . clean: $(MAKE) -C build clean + $(MAKE) -C config clean $(MAKE) -C model clean $(MAKE) -C web clean rm -rf $(TEST_ARTIFACTS) @@ -51,6 +52,9 @@ clean: -find . -type f -iname '*#' -exec rm '{}' ';' -find . -type f -iname '.#*' -exec rm '{}' ';' +config: preparation + $(MAKE) -C config + documentation: search_index godoc -http=:6060 -index -index_files='search_index' @@ -90,7 +94,7 @@ test: build go test ./utility/... $(GO_TEST_FLAGS) go test ./web/... $(GO_TEST_FLAGS) -web: preparation model +web: preparation config model $(MAKE) -C web -.PHONY: advice binary build clean documentation format model package preparation run search_index source_path test +.PHONY: advice binary build clean config documentation format model package preparation run search_index source_path test diff --git a/appstate/appstate.go b/appstate/appstate.go index b18af0caf0..9c77b5f3cb 100644 --- a/appstate/appstate.go +++ b/appstate/appstate.go @@ -24,7 +24,7 @@ import ( // runtime state. It enables simpler passing of this state to components that // require it. type ApplicationState struct { - Config *config.Config + Config config.Config RuleManager rules.RuleManager Storage metric.Storage TargetManager retrieval.TargetManager diff --git a/config/Makefile b/config/Makefile index bf8fc38993..df2497c2cc 100644 --- a/config/Makefile +++ b/config/Makefile @@ -11,13 +11,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -all: parser.y.go lexer.l.go +all: generated -parser.y.go: parser.y - go tool yacc -o parser.y.go -v "" parser.y +SUFFIXES: -lexer.l.go: parser.y.go lexer.l - golex lexer.l +MAKE_ARTIFACTS = generated-stamp + +include ../Makefile.INCLUDE + +generated: generated-stamp + +generated-stamp: config.proto + protoc --proto_path=$(PREFIX)/include:. --go_out=generated/ config.proto + touch $@ clean: - rm lexer.l.go parser.y.go + rm -rf generated/* + -rm -f $(MAKE_ARTIFACTS) + +.PHONY: generated diff --git a/config/config.go b/config/config.go index 383803b592..d5061dd04b 100644 --- a/config/config.go +++ b/config/config.go @@ -14,114 +14,119 @@ package config import ( - "errors" + "code.google.com/p/goprotobuf/proto" "fmt" - "github.com/prometheus/prometheus/model" + pb "github.com/prometheus/prometheus/config/generated" "github.com/prometheus/prometheus/utility" + "regexp" "time" ) +var jobNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_-]*$") +var labelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") + +// Config encapsulates the configuration of a Prometheus instance. It wraps the +// raw configuration protocol buffer to be able to add custom methods to it. type Config struct { - Global *GlobalConfig - Jobs []JobConfig + // The protobuf containing the actual configuration values. + pb.PrometheusConfig } -type GlobalConfig struct { - ScrapeInterval time.Duration - EvaluationInterval time.Duration - Labels model.LabelSet - RuleFiles []string +// String returns an ASCII serialization of the loaded configuration protobuf. +func (c Config) String() string { + return proto.MarshalTextString(&c.PrometheusConfig) } -type JobConfig struct { - Name string - ScrapeInterval time.Duration - Targets []Targets -} - -type Targets struct { - Endpoints []string - Labels model.LabelSet -} - -func New() *Config { - return &Config{ - Global: &GlobalConfig{Labels: model.LabelSet{}}, +// validateLabels validates whether label names have the correct format. +func (c Config) validateLabels(labels *pb.LabelPairs) error { + if labels == nil { + return nil } -} - -func (config *Config) AddJob(options map[string]string, targets []Targets) error { - name, ok := options["name"] - if !ok { - return errors.New("Missing job name") - } - if len(targets) == 0 { - return fmt.Errorf("No targets configured for job '%v'", name) - } - job := JobConfig{ - Targets: tmpJobTargets, - } - for option, value := range options { - if err := job.SetOption(option, value); err != nil { - return err + for _, label := range labels.Label { + if !labelNameRE.MatchString(label.GetName()) { + return fmt.Errorf("Invalid label name '%s'", label.GetName()) } } - config.Jobs = append(config.Jobs, job) return nil } -func (config *Config) GetJobByName(name string) (jobConfig *JobConfig) { - for _, job := range config.Jobs { - if job.Name == name { - jobConfig = &job +// Validate checks an entire parsed Config for the validity of its fields. +func (c Config) Validate() error { + // Check the global configuration section for validity. + global := c.Global + if _, err := utility.StringToDuration(global.GetScrapeInterval()); err != nil { + return fmt.Errorf("Invalid global scrape interval: %s", err) + } + if _, err := utility.StringToDuration(global.GetEvaluationInterval()); err != nil { + return fmt.Errorf("Invalid rule evaluation interval: %s", err) + } + if err := c.validateLabels(global.Labels); err != nil { + return fmt.Errorf("Invalid global labels: %s", err) + } + + // Check each job configuration for validity. + for _, job := range c.Job { + if !jobNameRE.MatchString(job.GetName()) { + return fmt.Errorf("Invalid job name '%s'", job.GetName()) + } + if _, err := utility.StringToDuration(job.GetScrapeInterval()); err != nil { + return fmt.Errorf("Invalid scrape interval for job '%s': %s", job.GetName(), err) + } + for _, targetGroup := range job.TargetGroup { + if err := c.validateLabels(targetGroup.Labels); err != nil { + return fmt.Errorf("Invalid labels for job '%s': %s", job.GetName(), err) + } + } + } + + return nil +} + +// GetJobByName finds a job by its name in a Config object. +func (c Config) GetJobByName(name string) (jobConfig *JobConfig) { + for _, job := range c.Job { + if job.GetName() == name { + jobConfig = &JobConfig{*job} break } } return } -func (config *GlobalConfig) SetOption(option string, value string) (err error) { - switch option { - case "scrape_interval": - config.ScrapeInterval, err = utility.StringToDuration(value) - return nil - case "evaluation_interval": - config.EvaluationInterval, err = utility.StringToDuration(value) - return err - default: - err = fmt.Errorf("Unrecognized global configuration option '%v'", option) +// Jobs returns all the jobs in a Config object. +func (c Config) Jobs() (jobs []JobConfig) { + for _, job := range c.Job { + jobs = append(jobs, JobConfig{*job}) } return } -func (config *GlobalConfig) SetLabels(labels model.LabelSet) { - for k, v := range labels { - config.Labels[k] = v +// stringToDuration converts a string to a duration and dies on invalid format. +func stringToDuration(intervalStr string) time.Duration { + duration, err := utility.StringToDuration(intervalStr) + if err != nil { + panic(err) } + return duration } -func (config *GlobalConfig) AddRuleFiles(ruleFiles []string) { - for _, ruleFile := range ruleFiles { - config.RuleFiles = append(config.RuleFiles, ruleFile) - } +// ScrapeInterval gets the default scrape interval for a Config. +func (c Config) ScrapeInterval() time.Duration { + return stringToDuration(c.Global.GetScrapeInterval()) } -func (job *JobConfig) SetOption(option string, value string) (err error) { - switch option { - case "name": - job.Name = value - case "scrape_interval": - job.ScrapeInterval, err = utility.StringToDuration(value) - default: - err = fmt.Errorf("Unrecognized job configuration option '%v'", option) - } - return +// EvaluationInterval gets the default evaluation interval for a Config. +func (c Config) EvaluationInterval() time.Duration { + return stringToDuration(c.Global.GetEvaluationInterval()) } -func (job *JobConfig) AddTargets(endpoints []string, labels model.LabelSet) { - targets := Targets{ - Endpoints: endpoints, - Labels: labels, - } - job.Targets = append(job.Targets, targets) +// JobConfig encapsulates the configuration of a single job. It wraps the raw +// job protocol buffer to be able to add custom methods to it. +type JobConfig struct { + pb.JobConfig +} + +// EvaluationInterval gets the scrape interval for a job. +func (c JobConfig) ScrapeInterval() time.Duration { + return stringToDuration(c.GetScrapeInterval()) } diff --git a/config/config.proto b/config/config.proto new file mode 100644 index 0000000000..b49695ab10 --- /dev/null +++ b/config/config.proto @@ -0,0 +1,70 @@ +// Copyright 2013 Prometheus Team +// 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. + +package io.prometheus; + +// A label/value pair suitable for attaching to timeseries. +message LabelPair { + // The name of the label. Must adhere to the regex "[a-zA-Z_][a-zA-Z0-9_]*". + optional string name = 1; + // The value of the label. May contain any characters. + optional string value = 2; +} + +// A set of label/value pairs. +message LabelPairs { + repeated LabelPair label = 1; +} + +// The global Prometheus configuration section. +message GlobalConfig { + // How frequently to scrape targets by default. Must be a valid Prometheus + // duration string in the form "[0-9]+[smhdwy]". + optional string scrape_interval = 1 [default = "1m"]; + // How frequently to evaluate rules by default. Must be a valid Prometheus + // duration string in the form "[0-9]+[smhdwy]". + optional string evaluation_interval = 2 [default = "1m"]; + // The labels to add to any timeseries that this Prometheus instance scrapes. + optional LabelPairs labels = 3; + // The list of file names of rule files to load. + repeated string rule_file = 4; +} + +// A labeled group of targets to scrape for a job. +message TargetGroup { + // The list of endpoints to scrape via HTTP. + repeated string target = 1; + // The labels to add to any timeseries scraped for this target group. + optional LabelPairs labels = 2; +} + +// The configuration for a Prometheus job to scrape. +message JobConfig { + // The job name. Must adhere to the regex "[a-zA-Z_][a-zA-Z0-9_-]*". + required string name = 1; + // How frequently to scrape targets from this job. Overrides the global + // default. + optional string scrape_interval = 2; + // List of labeled target groups for this job. + repeated TargetGroup target_group = 3; +} + +// The top-level Prometheus configuration. +message PrometheusConfig { + // Global Prometheus configuration options. If omitted, an empty global + // configuration with default values (see GlobalConfig definition) will be + // created. + optional GlobalConfig global = 1; + // The list of jobs to scrape. + repeated JobConfig job = 2; +} diff --git a/config/config_test.go b/config/config_test.go index 523b7bf725..3c8422a36b 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -14,8 +14,6 @@ package config import ( - "fmt" - "io/ioutil" "path" "strings" "testing" @@ -25,37 +23,41 @@ var fixturesPath = "fixtures" var configTests = []struct { inputFile string - printedFile string shouldFail bool errContains string }{ { - inputFile: "minimal.conf.input", - printedFile: "minimal.conf.printed", + inputFile: "minimal.conf.input", }, { - inputFile: "sample.conf.input", - printedFile: "sample.conf.printed", + inputFile: "sample.conf.input", }, { - // TODO: Options that are not provided should be set to sane defaults or - // create errors during config loading (as appropriate). Right now, these - // options remain at their zero-values, which is probably not what we want. - inputFile: "empty.conf.input", - printedFile: "empty.conf.printed", + inputFile: "empty.conf.input", + }, + { + inputFile: "invalid_proto_format.conf.input", + shouldFail: true, + errContains: "unknown field name", + }, + { + inputFile: "invalid_scrape_interval.conf.input", + shouldFail: true, + errContains: "Invalid global scrape interval", + }, + { + inputFile: "invalid_job_name.conf.input", + shouldFail: true, + errContains: "Invalid job name", + }, + { + inputFile: "invalid_label_name.conf.input", + shouldFail: true, + errContains: "Invalid label name", }, - // TODO: To enable testing of bad configs, we first need to change config - // loading so that it doesn't exit when loading a bad config. Instead, the - // configuration error should be passed back all the way to the caller. - // - //{ - // inputFile: "bad_job_option.conf.input", - // shouldFail: true, - // errContains: "Missing job name", - //}, } func TestConfigs(t *testing.T) { for i, configTest := range configTests { - testConfig, err := LoadFromFile(path.Join(fixturesPath, configTest.inputFile)) + _, err := LoadFromFile(path.Join(fixturesPath, configTest.inputFile)) if err != nil { if !configTest.shouldFail { @@ -65,22 +67,6 @@ func TestConfigs(t *testing.T) { t.Fatalf("%d. Expected error containing '%v', got: %v", i, configTest.errContains, err) } } - } else { - printedConfig, err := ioutil.ReadFile(path.Join(fixturesPath, configTest.printedFile)) - if err != nil { - t.Fatalf("%d. Error reading config %v: %v", i, configTest.inputFile, err) - continue - } - expected := string(printedConfig) - actual := testConfig.ToString(0) - - if actual != expected { - t.Errorf("%d. %v: printed config doesn't match expected output", i, configTest.inputFile) - t.Errorf("Expected:\n%v\n\nActual:\n%v\n", expected, actual) - t.Fatalf("Writing expected and actual printed configs to /tmp for diffing (see test source for paths)") - ioutil.WriteFile(fmt.Sprintf("/tmp/%s.expected", configTest.printedFile), []byte(expected), 0600) - ioutil.WriteFile(fmt.Sprintf("/tmp/%s.actual", configTest.printedFile), []byte(actual), 0600) - } } } } diff --git a/config/fixtures/bad_job_option.conf.input b/config/fixtures/bad_job_option.conf.input deleted file mode 100644 index 8914ed292d..0000000000 --- a/config/fixtures/bad_job_option.conf.input +++ /dev/null @@ -1,21 +0,0 @@ -global { - scrape_interval = "30s" - evaluation_interval = "30s" - labels { - monitor = "test" - } - rule_files = [ - "prometheus.rules" - ] -} - -job { - jobname = "prometheus" - scrape_interval = "15s" - - targets { - endpoints = [ - "http://localhost:9090/metrics.json" - ] - } -} diff --git a/config/fixtures/empty.conf.printed b/config/fixtures/empty.conf.printed deleted file mode 100644 index b2c9c87380..0000000000 --- a/config/fixtures/empty.conf.printed +++ /dev/null @@ -1,8 +0,0 @@ -global { - scrape_interval = "0y" - evaluation_interval = "0y" - rule_files = [ - - ] -} - diff --git a/config/fixtures/invalid_job_name.conf.input b/config/fixtures/invalid_job_name.conf.input new file mode 100644 index 0000000000..e3923ac721 --- /dev/null +++ b/config/fixtures/invalid_job_name.conf.input @@ -0,0 +1,3 @@ +job: < + name: "1testjob" +> diff --git a/config/fixtures/invalid_label_name.conf.input b/config/fixtures/invalid_label_name.conf.input new file mode 100644 index 0000000000..bfc384bd04 --- /dev/null +++ b/config/fixtures/invalid_label_name.conf.input @@ -0,0 +1,10 @@ +global < + scrape_interval: "30s" + evaluation_interval: "30s" + labels: < + label: < + name: "monitor-test" + value: "test" + > + > +> diff --git a/config/fixtures/invalid_proto_format.conf.input b/config/fixtures/invalid_proto_format.conf.input new file mode 100644 index 0000000000..9d15ddec18 --- /dev/null +++ b/config/fixtures/invalid_proto_format.conf.input @@ -0,0 +1,11 @@ +global < + scrape_interval: "30s" + evaluation_interval: "30s" + unknown_field: "foo" + labels: < + label: < + name: "monitor" + value: "test" + > + > +> diff --git a/config/fixtures/invalid_scrape_interval.conf.input b/config/fixtures/invalid_scrape_interval.conf.input new file mode 100644 index 0000000000..e9274948a5 --- /dev/null +++ b/config/fixtures/invalid_scrape_interval.conf.input @@ -0,0 +1,10 @@ +global < + scrape_interval: "30" + evaluation_interval: "30s" + labels: < + label: < + name: "monitor" + value: "test" + > + > +> diff --git a/config/fixtures/minimal.conf.input b/config/fixtures/minimal.conf.input index 41ed13c7ae..135c316a77 100644 --- a/config/fixtures/minimal.conf.input +++ b/config/fixtures/minimal.conf.input @@ -1,21 +1,20 @@ -global { - scrape_interval = "30s" - evaluation_interval = "30s" - labels { - monitor = "test" - } - rule_files = [ - "prometheus.rules" - ] -} +global < + scrape_interval: "30s" + evaluation_interval: "30s" + labels: < + label: < + name: "monitor" + value: "test" + > + > + rule_file: "prometheus.rules" +> -job { - name = "prometheus" - scrape_interval = "15s" +job: < + name: "prometheus" + scrape_interval: "15s" - targets { - endpoints = [ - "http://localhost:9090/metrics.json" - ] - } -} + target_group: < + target: "http://localhost:9090/metrics.json" + > +> diff --git a/config/fixtures/minimal.conf.printed b/config/fixtures/minimal.conf.printed deleted file mode 100644 index 833f635bff..0000000000 --- a/config/fixtures/minimal.conf.printed +++ /dev/null @@ -1,20 +0,0 @@ -global { - scrape_interval = "30s" - evaluation_interval = "30s" - labels { - monitor = "test" - } - rule_files = [ - "prometheus.rules" - ] -} - -job { - name = "prometheus" - scrape_interval = "15s" - targets { - endpoints = [ - "http://localhost:9090/metrics.json" - ] - } -} diff --git a/config/fixtures/sample.conf.input b/config/fixtures/sample.conf.input index f8ece5cc75..5c03d674d4 100644 --- a/config/fixtures/sample.conf.input +++ b/config/fixtures/sample.conf.input @@ -1,51 +1,55 @@ -global { - scrape_interval = "30s" - evaluation_interval = "30s" - labels { - monitor = "test" - } - rule_files = [ - "prometheus.rules" - ] -} +global < + scrape_interval: "30s" + evaluation_interval: "30s" + labels: < + label: < + name: "monitor" + value: "test" + > + > + rule_file: "prometheus.rules" +> -job { - name = "prometheus" - scrape_interval = "15s" +job: < + name: "prometheus" + scrape_interval: "15s" - targets { - endpoints = [ - "http://localhost:9090/metrics.json" - ] - labels { - group = "canary" - } - } -} + target_group: < + target: "http://localhost:9090/metrics.json" + labels: < + label: < + name: "group" + value: "canary" + > + > + > +> -job { - name = "random" - scrape_interval = "30s" +job: < + name: "random" + scrape_interval: "30s" - targets { - endpoints = [ - "http://random.com:8080/metrics.json", - "http://random.com:8081/metrics.json", - "http://random.com:8082/metrics.json", - "http://random.com:8083/metrics.json", - "http://random.com:8084/metrics.json" - ] - labels { - group = "production" - } - } - targets { - endpoints = [ - "http://random.com:8085/metrics.json", - "http://random.com:8086/metrics.json" - ] - labels { - group = "canary" - } - } -} + target_group: < + target: "http://random.com:8080/metrics.json" + target: "http://random.com:8081/metrics.json" + target: "http://random.com:8082/metrics.json" + target: "http://random.com:8083/metrics.json" + target: "http://random.com:8084/metrics.json" + labels: < + label: < + name: "group" + value: "production" + > + > + > + target_group: < + target: "http://random.com:8085/metrics.json" + target: "http://random.com:8086/metrics.json" + labels: < + label: < + name: "group" + value: "canary" + > + > + > +> diff --git a/config/fixtures/sample.conf.printed b/config/fixtures/sample.conf.printed deleted file mode 100644 index aa46fa82fc..0000000000 --- a/config/fixtures/sample.conf.printed +++ /dev/null @@ -1,49 +0,0 @@ -global { - scrape_interval = "30s" - evaluation_interval = "30s" - labels { - monitor = "test" - } - rule_files = [ - "prometheus.rules" - ] -} - -job { - name = "prometheus" - scrape_interval = "15s" - targets { - endpoints = [ - "http://localhost:9090/metrics.json" - ] - labels { - group = "canary" - } - } -} - -job { - name = "random" - scrape_interval = "30s" - targets { - endpoints = [ - "http://random.com:8080/metrics.json", - "http://random.com:8081/metrics.json", - "http://random.com:8082/metrics.json", - "http://random.com:8083/metrics.json", - "http://random.com:8084/metrics.json" - ] - labels { - group = "production" - } - } - targets { - endpoints = [ - "http://random.com:8085/metrics.json", - "http://random.com:8086/metrics.json" - ] - labels { - group = "canary" - } - } -} diff --git a/config/generated/.gitignore b/config/generated/.gitignore new file mode 100644 index 0000000000..56086905e7 --- /dev/null +++ b/config/generated/.gitignore @@ -0,0 +1 @@ +config.pb.go diff --git a/config/helpers.go b/config/helpers.go deleted file mode 100644 index 8ef989345f..0000000000 --- a/config/helpers.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2013 Prometheus Team -// 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. - -package config - -import ( - "fmt" - "github.com/prometheus/prometheus/model" - "log" -) - -// Unfortunately, more global variables that are needed for parsing. -var tmpJobOptions = map[string]string{} -var tmpJobTargets = []Targets{} -var tmpTargetEndpoints = []string{} -var tmpTargetLabels = model.LabelSet{} - -func configError(error string, v ...interface{}) { - message := fmt.Sprintf(error, v...) - // TODO: Don't just die here. Pass errors back all the way to the caller - // instead. - log.Fatalf("Line %v, char %v: %s", yyline, yypos, message) -} - -func PushJobOption(option string, value string) { - tmpJobOptions[option] = value -} - -func PushJobTargets() { - targets := Targets{ - Endpoints: tmpTargetEndpoints, - Labels: tmpTargetLabels, - } - tmpJobTargets = append(tmpJobTargets, targets) - tmpTargetLabels = model.LabelSet{} - tmpTargetEndpoints = []string{} -} - -func PushTargetEndpoints(endpoints []string) { - for _, endpoint := range endpoints { - tmpTargetEndpoints = append(tmpTargetEndpoints, endpoint) - } -} - -func PushTargetLabels(labels model.LabelSet) { - for k, v := range labels { - tmpTargetLabels[k] = v - } -} - -func PopJob() { - if err := parsedConfig.AddJob(tmpJobOptions, tmpJobTargets); err != nil { - configError(err.Error()) - } - tmpJobOptions = map[string]string{} - tmpJobTargets = []Targets{} -} diff --git a/config/lexer.l b/config/lexer.l deleted file mode 100644 index 5c0a28b3d3..0000000000 --- a/config/lexer.l +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright 2013 Prometheus Team - * 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. */ - -%{ -package config -%} - -D [0-9] -L [a-zA-Z_] - -%s S_GLOBAL S_GLOBAL_LABELS S_JOB S_TARGETS S_TARGET_LABELS -%x S_COMMENTS - -%% -. { yypos++; REJECT } -\n { yyline++; yypos = 1; REJECT } - -"/*" { BEGIN(S_COMMENTS); } -"*/" { BEGIN(0) } -. { /* ignore chars within multi-line comments */ } - -\/\/[^\r\n]*\n { /* gobble up one-line comments */ } - -<0>global { BEGIN(S_GLOBAL); return GLOBAL } -labels { BEGIN(S_GLOBAL_LABELS); return LABELS } -rule_files { return RULE_FILES } -"}" { BEGIN(S_GLOBAL); REJECT } -"}" { BEGIN(0); REJECT } - -<0>job { BEGIN(S_JOB); return JOB } -targets { BEGIN(S_TARGETS); return TARGETS } -endpoints { return ENDPOINTS } -labels { BEGIN(S_TARGET_LABELS); return LABELS } -"}" { BEGIN(S_TARGETS); REJECT } -"}" { BEGIN(S_JOB); REJECT } -"}" { BEGIN(0); REJECT } - -{L}({L}|{D})+ { yylval.str = yytext; return IDENTIFIER } - -\"(\\.|[^\\"])*\" { yylval.str = yytext[1:len(yytext) - 1]; return STRING } -\'(\\.|[^\\'])*\' { yylval.str = yytext[1:len(yytext) - 1]; return STRING } - -[{}\[\]()=,] { return int(yytext[0]) } -. { /* don't print any remaining chars (whitespace) */ } -\n { /* don't print any remaining chars (whitespace) */ } -%% diff --git a/config/lexer.l.go b/config/lexer.l.go deleted file mode 100644 index 3355b498c4..0000000000 --- a/config/lexer.l.go +++ /dev/null @@ -1,551 +0,0 @@ -// Generated by golex -package config - - -import ( - "bufio" - "io" - "os" - "regexp" - "sort" -) - -var yyin io.Reader = os.Stdin -var yyout io.Writer = os.Stdout - -type yyrule struct { - regexp *regexp.Regexp - trailing *regexp.Regexp - startConds []yystartcondition - sol bool - action func() yyactionreturn -} - -type yyactionreturn struct { - userReturn int - returnType yyactionreturntype -} - -type yyactionreturntype int -const ( - yyRT_FALLTHROUGH yyactionreturntype = iota - yyRT_USER_RETURN - yyRT_REJECT -) - -var yydata string = "" -var yyorig string -var yyorigidx int - -var yytext string = "" -var yytextrepl bool = true -func yymore() { - yytextrepl = false -} - -func yyBEGIN(state yystartcondition) { - YY_START = state -} - -func yyECHO() { - yyout.Write([]byte(yytext)) -} - -func yyREJECT() { - panic("yyREJECT") -} - -var yylessed int -func yyless(n int) { - yylessed = len(yytext) - n -} - -func unput(c uint8) { - yyorig = yyorig[:yyorigidx] + string(c) + yyorig[yyorigidx:] - yydata = yydata[:len(yytext)-yylessed] + string(c) + yydata[len(yytext)-yylessed:] -} - -func input() int { - if len(yyorig) <= yyorigidx { - return EOF - } - c := yyorig[yyorigidx] - yyorig = yyorig[:yyorigidx] + yyorig[yyorigidx+1:] - yydata = yydata[:len(yytext)-yylessed] + yydata[len(yytext)-yylessed+1:] - return int(c) -} - -var EOF int = -1 -type yystartcondition int - -var INITIAL yystartcondition = 0 -var YY_START yystartcondition = INITIAL - -type yylexMatch struct { - index int - matchFunc func() yyactionreturn - sortLen int - advLen int -} - -type yylexMatchList []yylexMatch - -func (ml yylexMatchList) Len() int { - return len(ml) -} - -func (ml yylexMatchList) Less(i, j int) bool { - return ml[i].sortLen > ml[j].sortLen && ml[i].index > ml[j].index -} - -func (ml yylexMatchList) Swap(i, j int) { - ml[i], ml[j] = ml[j], ml[i] -} - -func yylex() int { - reader := bufio.NewReader(yyin) - - for { - line, err := reader.ReadString('\n') - if len(line) == 0 && err == io.EOF { - break - } - - yydata += line - } - - yyorig = yydata - yyorigidx = 0 - - yyactioninline(yyBEGIN) - - for len(yydata) > 0 { - matches := yylexMatchList(make([]yylexMatch, 0, 6)) - excl := yystartconditionexclmap[YY_START] - - for i, v := range yyrules { - sol := yyorigidx == 0 || yyorig[yyorigidx-1] == '\n' - - if v.sol && !sol { - continue - } - - // Check start conditions. - ok := false - - // YY_START or '*' must feature in v.startConds - for _, c := range v.startConds { - if c == YY_START || c == -1 { - ok = true - break - } - } - - if !excl { - // If v.startConds is empty, this is also acceptable. - if len(v.startConds) == 0 { - ok = true - } - } - - if !ok { - continue - } - - idxs := v.regexp.FindStringIndex(yydata) - if idxs != nil && idxs[0] == 0 { - // Check the trailing context, if any. - checksOk := true - sortLen := idxs[1] - advLen := idxs[1] - - if v.trailing != nil { - tridxs := v.trailing.FindStringIndex(yydata[idxs[1]:]) - if tridxs == nil || tridxs[0] != 0 { - checksOk = false - } else { - sortLen += tridxs[1] - } - } - - if checksOk { - matches = append(matches, yylexMatch{i, v.action, sortLen, advLen}) - } - } - } - - if yytextrepl { - yytext = "" - } - - sort.Sort(matches) - - tryMatch: - if len(matches) == 0 { - yytext += yydata[:1] - yydata = yydata[1:] - yyorigidx += 1 - - yyout.Write([]byte(yytext)) - } else { - m := matches[0] - yytext += yydata[:m.advLen] - yyorigidx += m.advLen - - yytextrepl, yylessed = true, 0 - ar := m.matchFunc() - - if ar.returnType != yyRT_REJECT { - yydata = yydata[m.advLen-yylessed:] - yyorigidx -= yylessed - } - - switch ar.returnType { - case yyRT_FALLTHROUGH: - // Do nothing. - case yyRT_USER_RETURN: - return ar.userReturn - case yyRT_REJECT: - matches = matches[1:] - yytext = yytext[:len(yytext)-m.advLen] - yyorigidx -= m.advLen - goto tryMatch - } - } - } - - return 0 -} -var S_TARGETS yystartcondition = 1027 -var S_JOB yystartcondition = 1026 -var S_GLOBAL yystartcondition = 1024 -var S_GLOBAL_LABELS yystartcondition = 1025 -var S_COMMENTS yystartcondition = 1029 -var S_TARGET_LABELS yystartcondition = 1028 -var yystartconditionexclmap = map[yystartcondition]bool{S_GLOBAL: false, S_GLOBAL_LABELS: false, S_COMMENTS: true, S_TARGET_LABELS: false, S_TARGETS: false, S_JOB: false, } -var yyrules []yyrule = []yyrule{{regexp.MustCompile("[^\\n]"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yypos++ - yyREJECT() - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\n"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyline++ - yypos = 1 - yyREJECT() - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("/\\*"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_COMMENTS) - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\*/"), nil, []yystartcondition{S_COMMENTS, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(0) - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("[^\\n]"), nil, []yystartcondition{S_COMMENTS, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\/\\/[^\\r\\n]*\\n"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("global"), nil, []yystartcondition{0, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_GLOBAL) - return yyactionreturn{GLOBAL, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("labels"), nil, []yystartcondition{S_GLOBAL, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_GLOBAL_LABELS) - return yyactionreturn{LABELS, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("rule_files"), nil, []yystartcondition{S_GLOBAL, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - return yyactionreturn{RULE_FILES, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\}"), nil, []yystartcondition{S_GLOBAL_LABELS, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_GLOBAL) - yyREJECT() - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\}"), nil, []yystartcondition{S_GLOBAL, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(0) - yyREJECT() - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("job"), nil, []yystartcondition{0, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_JOB) - return yyactionreturn{JOB, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("targets"), nil, []yystartcondition{S_JOB, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_TARGETS) - return yyactionreturn{TARGETS, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("endpoints"), nil, []yystartcondition{S_TARGETS, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - return yyactionreturn{ENDPOINTS, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("labels"), nil, []yystartcondition{S_TARGETS, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_TARGET_LABELS) - return yyactionreturn{LABELS, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\}"), nil, []yystartcondition{S_TARGET_LABELS, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_TARGETS) - yyREJECT() - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\}"), nil, []yystartcondition{S_TARGETS, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(S_JOB) - yyREJECT() - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\}"), nil, []yystartcondition{S_JOB, }, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yyBEGIN(0) - yyREJECT() - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("([a-zA-Z_])(([a-zA-Z_])|([0-9]))+"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yylval.str = yytext - return yyactionreturn{IDENTIFIER, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\\"(\\\\[^\\n]|[^\\\\\"])*\\\""), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yylval.str = yytext[1 : len(yytext)-1] - return yyactionreturn{STRING, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\'(\\\\[^\\n]|[^\\\\'])*\\'"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - yylval.str = yytext[1 : len(yytext)-1] - return yyactionreturn{STRING, yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("[{}\\[\\]()=,]"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - return yyactionreturn{int(yytext[0]), yyRT_USER_RETURN} - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("[^\\n]"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, {regexp.MustCompile("\\n"), nil, []yystartcondition{}, false, func() (yyar yyactionreturn) { - defer func() { - if r := recover(); r != nil { - if r != "yyREJECT" { - panic(r) - } - yyar.returnType = yyRT_REJECT - } - }() - { - } - return yyactionreturn{0, yyRT_FALLTHROUGH} -}}, } -func yyactioninline(BEGIN func(yystartcondition)) {} diff --git a/config/load.go b/config/load.go index f0b7407975..28d49da417 100644 --- a/config/load.go +++ b/config/load.go @@ -14,66 +14,35 @@ package config import ( - "errors" - "fmt" - "io" - "os" - "strings" + "code.google.com/p/goprotobuf/proto" + pb "github.com/prometheus/prometheus/config/generated" + "io/ioutil" ) -// NOTE: This parser is non-reentrant due to its dependence on global state. - -// GoLex sadly needs these global variables for storing temporary token/parsing information. -var yylval *yySymType // For storing extra token information, like the contents of a string. -var yyline int // Line number within the current file or buffer. -var yypos int // Character position within the current line. -var parsedConfig *Config // Temporary variable for storing the parsed configuration. - -type ConfigLexer struct { - errors []string -} - -func (lexer *ConfigLexer) Lex(lval *yySymType) int { - yylval = lval - token_type := yylex() - return token_type -} - -func (lexer *ConfigLexer) Error(errorStr string) { - err := fmt.Sprintf("Error reading config at line %v, char %v: %v", yyline, yypos, errorStr) - lexer.errors = append(lexer.errors, err) -} - -func LoadFromReader(configReader io.Reader) (*Config, error) { - parsedConfig = New() - yyin = configReader - yypos = 1 - yyline = 1 - yydata = "" - yytext = "" - - lexer := &ConfigLexer{} - yyParse(lexer) - - if len(lexer.errors) > 0 { - err := errors.New(strings.Join(lexer.errors, "\n")) - return &Config{}, err +func LoadFromString(configStr string) (config Config, err error) { + configProto := pb.PrometheusConfig{} + if err = proto.UnmarshalText(configStr, &configProto); err != nil { + return } - - return parsedConfig, nil + if configProto.Global == nil { + configProto.Global = &pb.GlobalConfig{} + } + for _, job := range configProto.Job { + if job.ScrapeInterval == nil { + job.ScrapeInterval = proto.String(configProto.Global.GetScrapeInterval()) + } + } + config = Config{configProto} + err = config.Validate() + return } -func LoadFromString(configString string) (*Config, error) { - configReader := strings.NewReader(configString) - return LoadFromReader(configReader) -} - -func LoadFromFile(fileName string) (*Config, error) { - configReader, err := os.Open(fileName) +func LoadFromFile(fileName string) (config Config, err error) { + configStr, err := ioutil.ReadFile(fileName) if err != nil { - return &Config{}, err + return } - defer configReader.Close() - return LoadFromReader(configReader) + config, err = LoadFromString(string(configStr)) + return } diff --git a/config/parser.y b/config/parser.y deleted file mode 100644 index b083a4a9b0..0000000000 --- a/config/parser.y +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2013 Prometheus Team -// 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. - -%{ - package config - - import "fmt" - import "github.com/prometheus/prometheus/model" -%} - -%union { - num model.SampleValue - str string - stringSlice []string - labelSet model.LabelSet -} - -%token IDENTIFIER STRING -%token GLOBAL JOB -%token RULE_FILES -%token LABELS TARGETS ENDPOINTS - -%type string_array string_list rule_files_stat endpoints_stat -%type labels_stat label_assign label_assign_list - -%start config - -%% -config : /* empty */ - | config config_stanza - ; - -config_stanza : GLOBAL '{' global_stat_list '}' - | JOB '{' job_stat_list '}' - { PopJob() } - ; - -global_stat_list : /* empty */ - | global_stat_list global_stat - ; - -global_stat : IDENTIFIER '=' STRING - { parsedConfig.Global.SetOption($1, $3) } - | labels_stat - { parsedConfig.Global.SetLabels($1) } - | rule_files_stat - { parsedConfig.Global.AddRuleFiles($1) } - ; - -labels_stat : LABELS '{' label_assign_list '}' - { $$ = $3 } - | LABELS '{' '}' - { $$ = model.LabelSet{} } - ; - -label_assign_list : label_assign - { $$ = $1 } - | label_assign_list ',' label_assign - { for k, v := range $3 { $$[k] = v } } - ; - -label_assign : IDENTIFIER '=' STRING - { $$ = model.LabelSet{ model.LabelName($1): model.LabelValue($3) } } - ; - -rule_files_stat : RULE_FILES '=' string_array - { $$ = $3 } - ; - -job_stat_list : /* empty */ - | job_stat_list job_stat - ; - -job_stat : IDENTIFIER '=' STRING - { PushJobOption($1, $3) } - | TARGETS '{' targets_stat_list '}' - { PushJobTargets() } - ; - -targets_stat_list : /* empty */ - | targets_stat_list targets_stat - ; - -targets_stat : endpoints_stat - { PushTargetEndpoints($1) } - | labels_stat - { PushTargetLabels($1) } - ; - -endpoints_stat : ENDPOINTS '=' string_array - { $$ = $3 } - ; - -string_array : '[' string_list ']' - { $$ = $2 } - | '[' ']' - { $$ = []string{} } - ; - -string_list : STRING - { $$ = []string{$1} } - | string_list ',' STRING - { $$ = append($$, $3) } - ; -%% diff --git a/config/parser.y.go b/config/parser.y.go deleted file mode 100644 index 614d514f4a..0000000000 --- a/config/parser.y.go +++ /dev/null @@ -1,420 +0,0 @@ - -//line parser.y:15 - package config - - import "fmt" - import "github.com/prometheus/prometheus/model" - -//line parser.y:21 -type yySymType struct { - yys int - num model.SampleValue - str string - stringSlice []string - labelSet model.LabelSet -} - -const IDENTIFIER = 57346 -const STRING = 57347 -const GLOBAL = 57348 -const JOB = 57349 -const RULE_FILES = 57350 -const LABELS = 57351 -const TARGETS = 57352 -const ENDPOINTS = 57353 - -var yyToknames = []string{ - "IDENTIFIER", - "STRING", - "GLOBAL", - "JOB", - "RULE_FILES", - "LABELS", - "TARGETS", - "ENDPOINTS", -} -var yyStatenames = []string{} - -const yyEofCode = 1 -const yyErrCode = 2 -const yyMaxDepth = 200 - -//line parser.y:115 - - -//line yacctab:1 -var yyExca = []int{ - -1, 1, - 1, -1, - -2, 0, -} - -const yyNprod = 29 -const yyPrivate = 57344 - -var yyTokenNames []string -var yyStates []string - -const yyLast = 53 - -var yyAct = []int{ - - 30, 28, 12, 48, 39, 47, 31, 34, 11, 35, - 49, 36, 15, 14, 29, 18, 38, 9, 14, 23, - 44, 19, 40, 27, 16, 50, 22, 20, 24, 21, - 6, 5, 3, 4, 46, 32, 43, 45, 25, 29, - 41, 33, 17, 10, 8, 7, 2, 1, 26, 42, - 51, 13, 37, -} -var yyPact = []int{ - - -1000, 26, -1000, 19, 18, -1000, -1000, 4, 11, -1000, - -1000, 13, -1000, -1000, 17, 12, -1000, -1000, 5, 16, - 33, 10, -10, 30, -1000, -1000, -6, -1000, -1000, -3, - -1000, -1, -1000, 9, -1000, 35, 29, -12, -1000, -1000, - -1000, -1000, -1000, -1000, -4, -1000, -1000, -1000, 20, -10, - -1000, -1000, -} -var yyPgo = []int{ - - 0, 0, 52, 51, 49, 2, 1, 48, 47, 46, - 45, 44, 43, 42, 41, 40, -} -var yyR1 = []int{ - - 0, 8, 8, 9, 9, 10, 10, 12, 12, 12, - 5, 5, 7, 7, 6, 3, 11, 11, 13, 13, - 14, 14, 15, 15, 4, 1, 1, 2, 2, -} -var yyR2 = []int{ - - 0, 0, 2, 4, 4, 0, 2, 3, 1, 1, - 4, 3, 1, 3, 3, 3, 0, 2, 3, 4, - 0, 2, 1, 1, 3, 3, 2, 1, 3, -} -var yyChk = []int{ - - -1000, -8, -9, 6, 7, 12, 12, -10, -11, 13, - -12, 4, -5, -3, 9, 8, 13, -13, 4, 10, - 14, 12, 14, 14, 12, 5, -7, 13, -6, 4, - -1, 16, 5, -14, 13, 15, 14, -2, 17, 5, - 13, -15, -4, -5, 11, -6, 5, 17, 15, 14, - 5, -1, -} -var yyDef = []int{ - - 1, -2, 2, 0, 0, 5, 16, 0, 0, 3, - 6, 0, 8, 9, 0, 0, 4, 17, 0, 0, - 0, 0, 0, 0, 20, 7, 0, 11, 12, 0, - 15, 0, 18, 0, 10, 0, 0, 0, 26, 27, - 19, 21, 22, 23, 0, 13, 14, 25, 0, 0, - 28, 24, -} -var yyTok1 = []int{ - - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 15, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 14, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 16, 3, 17, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 12, 3, 13, -} -var yyTok2 = []int{ - - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -} -var yyTok3 = []int{ - 0, -} - -//line yaccpar:1 - -/* parser for yacc output */ - -var yyDebug = 0 - -type yyLexer interface { - Lex(lval *yySymType) int - Error(s string) -} - -const yyFlag = -1000 - -func yyTokname(c int) string { - if c > 0 && c <= len(yyToknames) { - if yyToknames[c-1] != "" { - return yyToknames[c-1] - } - } - return fmt.Sprintf("tok-%v", c) -} - -func yyStatname(s int) string { - if s >= 0 && s < len(yyStatenames) { - if yyStatenames[s] != "" { - return yyStatenames[s] - } - } - return fmt.Sprintf("state-%v", s) -} - -func yylex1(lex yyLexer, lval *yySymType) int { - c := 0 - char := lex.Lex(lval) - if char <= 0 { - c = yyTok1[0] - goto out - } - if char < len(yyTok1) { - c = yyTok1[char] - goto out - } - if char >= yyPrivate { - if char < yyPrivate+len(yyTok2) { - c = yyTok2[char-yyPrivate] - goto out - } - } - for i := 0; i < len(yyTok3); i += 2 { - c = yyTok3[i+0] - if c == char { - c = yyTok3[i+1] - goto out - } - } - -out: - if c == 0 { - c = yyTok2[1] /* unknown char */ - } - if yyDebug >= 3 { - fmt.Printf("lex %U %s\n", uint(char), yyTokname(c)) - } - return c -} - -func yyParse(yylex yyLexer) int { - var yyn int - var yylval yySymType - var yyVAL yySymType - yyS := make([]yySymType, yyMaxDepth) - - Nerrs := 0 /* number of errors */ - Errflag := 0 /* error recovery flag */ - yystate := 0 - yychar := -1 - yyp := -1 - goto yystack - -ret0: - return 0 - -ret1: - return 1 - -yystack: - /* put a state and value onto the stack */ - if yyDebug >= 4 { - fmt.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) - } - - yyp++ - if yyp >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyS[yyp] = yyVAL - yyS[yyp].yys = yystate - -yynewstate: - yyn = yyPact[yystate] - if yyn <= yyFlag { - goto yydefault /* simple state */ - } - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - yyn += yychar - if yyn < 0 || yyn >= yyLast { - goto yydefault - } - yyn = yyAct[yyn] - if yyChk[yyn] == yychar { /* valid shift */ - yychar = -1 - yyVAL = yylval - yystate = yyn - if Errflag > 0 { - Errflag-- - } - goto yystack - } - -yydefault: - /* default state action */ - yyn = yyDef[yystate] - if yyn == -2 { - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - - /* look through exception table */ - xi := 0 - for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { - break - } - xi += 2 - } - for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] - if yyn < 0 || yyn == yychar { - break - } - } - yyn = yyExca[xi+1] - if yyn < 0 { - goto ret0 - } - } - if yyn == 0 { - /* error ... attempt to resume parsing */ - switch Errflag { - case 0: /* brand new error */ - yylex.Error("syntax error") - Nerrs++ - if yyDebug >= 1 { - fmt.Printf("%s", yyStatname(yystate)) - fmt.Printf("saw %s\n", yyTokname(yychar)) - } - fallthrough - - case 1, 2: /* incompletely recovered error ... try again */ - Errflag = 3 - - /* find a state where "error" is a legal shift action */ - for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode - if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { - goto yystack - } - } - - /* the current p has no shift on "error", pop stack */ - if yyDebug >= 2 { - fmt.Printf("error recovery pops state %d\n", yyS[yyp].yys) - } - yyp-- - } - /* there is no state on the stack with an error shift ... abort */ - goto ret1 - - case 3: /* no shift yet; clobber input char */ - if yyDebug >= 2 { - fmt.Printf("error recovery discards %s\n", yyTokname(yychar)) - } - if yychar == yyEofCode { - goto ret1 - } - yychar = -1 - goto yynewstate /* try again in the same state */ - } - } - - /* reduction by production yyn */ - if yyDebug >= 2 { - fmt.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) - } - - yynt := yyn - yypt := yyp - _ = yypt // guard against "declared and not used" - - yyp -= yyR2[yyn] - yyVAL = yyS[yyp+1] - - /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] - yyj := yyg + yyS[yyp].yys + 1 - - if yyj >= yyLast { - yystate = yyAct[yyg] - } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] - } - } - // dummy call; replaced with literal code - switch yynt { - - case 4: - //line parser.y:45 - { PopJob() } - case 7: - //line parser.y:53 - { parsedConfig.Global.SetOption(yyS[yypt-2].str, yyS[yypt-0].str) } - case 8: - //line parser.y:55 - { parsedConfig.Global.SetLabels(yyS[yypt-0].labelSet) } - case 9: - //line parser.y:57 - { parsedConfig.Global.AddRuleFiles(yyS[yypt-0].stringSlice) } - case 10: - //line parser.y:61 - { yyVAL.labelSet = yyS[yypt-1].labelSet } - case 11: - //line parser.y:63 - { yyVAL.labelSet = model.LabelSet{} } - case 12: - //line parser.y:67 - { yyVAL.labelSet = yyS[yypt-0].labelSet } - case 13: - //line parser.y:69 - { for k, v := range yyS[yypt-0].labelSet { yyVAL.labelSet[k] = v } } - case 14: - //line parser.y:73 - { yyVAL.labelSet = model.LabelSet{ model.LabelName(yyS[yypt-2].str): model.LabelValue(yyS[yypt-0].str) } } - case 15: - //line parser.y:77 - { yyVAL.stringSlice = yyS[yypt-0].stringSlice } - case 18: - //line parser.y:85 - { PushJobOption(yyS[yypt-2].str, yyS[yypt-0].str) } - case 19: - //line parser.y:87 - { PushJobTargets() } - case 22: - //line parser.y:95 - { PushTargetEndpoints(yyS[yypt-0].stringSlice) } - case 23: - //line parser.y:97 - { PushTargetLabels(yyS[yypt-0].labelSet) } - case 24: - //line parser.y:101 - { yyVAL.stringSlice = yyS[yypt-0].stringSlice } - case 25: - //line parser.y:105 - { yyVAL.stringSlice = yyS[yypt-1].stringSlice } - case 26: - //line parser.y:107 - { yyVAL.stringSlice = []string{} } - case 27: - //line parser.y:111 - { yyVAL.stringSlice = []string{yyS[yypt-0].str} } - case 28: - //line parser.y:113 - { yyVAL.stringSlice = append(yyVAL.stringSlice, yyS[yypt-0].str) } - } - goto yystack /* stack new state and value */ -} diff --git a/config/printer.go b/config/printer.go deleted file mode 100644 index c977d945bf..0000000000 --- a/config/printer.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2013 Prometheus Team -// 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. - -package config - -import ( - "fmt" - "github.com/prometheus/prometheus/model" - "github.com/prometheus/prometheus/utility" - "strings" -) - -func indentStr(indent int, str string, v ...interface{}) string { - indentStr := "" - for i := 0; i < indent; i++ { - indentStr += "\t" - } - return fmt.Sprintf(indentStr+str, v...) -} - -func (config *Config) ToString(indent int) string { - global := config.Global.ToString(indent) - jobs := []string{} - for _, job := range config.Jobs { - jobs = append(jobs, job.ToString(indent)) - } - return indentStr(indent, "%v\n%v", global, strings.Join(jobs, "\n")) -} - -func labelsToString(indent int, labels model.LabelSet) string { - str := indentStr(indent, "labels {\n") - labelStrings := []string{} - for label, value := range labels { - labelStrings = append(labelStrings, indentStr(indent+1, "%v = \"%v\"", label, value)) - } - str += strings.Join(labelStrings, ",\n") + "\n" - str += indentStr(indent, "}\n") - return str -} - -func stringListToString(indent int, list []string) string { - listString := []string{} - for _, item := range list { - listString = append(listString, indentStr(indent, "\"%v\"", item)) - } - return strings.Join(listString, ",\n") + "\n" -} - -func (global *GlobalConfig) ToString(indent int) string { - str := indentStr(indent, "global {\n") - str += indentStr(indent+1, "scrape_interval = \"%s\"\n", utility.DurationToString(global.ScrapeInterval)) - str += indentStr(indent+1, "evaluation_interval = \"%s\"\n", utility.DurationToString(global.EvaluationInterval)) - if len(global.Labels) > 0 { - str += labelsToString(indent+1, global.Labels) - } - str += indentStr(indent+1, "rule_files = [\n") - str += stringListToString(indent+2, global.RuleFiles) - str += indentStr(indent+1, "]\n") - str += indentStr(indent, "}\n") - return str -} - -func (job *JobConfig) ToString(indent int) string { - str := indentStr(indent, "job {\n") - str += indentStr(indent+1, "name = \"%v\"\n", job.Name) - str += indentStr(indent+1, "scrape_interval = \"%s\"\n", utility.DurationToString(job.ScrapeInterval)) - for _, targets := range job.Targets { - str += indentStr(indent+1, "targets {\n") - str += indentStr(indent+2, "endpoints = [\n") - str += stringListToString(indent+3, targets.Endpoints) - str += indentStr(indent+2, "]\n") - if len(targets.Labels) > 0 { - str += labelsToString(indent+2, targets.Labels) - } - str += indentStr(indent+1, "}\n") - } - str += indentStr(indent, "}\n") - return str -} diff --git a/main.go b/main.go index 2c6a310aaa..0404036fa2 100644 --- a/main.go +++ b/main.go @@ -107,7 +107,7 @@ func main() { ast.SetStorage(ts) - ruleManager := rules.NewRuleManager(ruleResults, conf.Global.EvaluationInterval) + ruleManager := rules.NewRuleManager(ruleResults, conf.EvaluationInterval()) err = ruleManager.AddRulesFromConfig(conf) if err != nil { log.Fatalf("Error loading rule files: %v", err) diff --git a/retrieval/targetmanager.go b/retrieval/targetmanager.go index 9ca7bb180d..38518c18db 100644 --- a/retrieval/targetmanager.go +++ b/retrieval/targetmanager.go @@ -24,10 +24,10 @@ import ( type TargetManager interface { acquire() release() - AddTarget(job *config.JobConfig, t Target, defaultScrapeInterval time.Duration) - ReplaceTargets(job *config.JobConfig, newTargets []Target, defaultScrapeInterval time.Duration) + AddTarget(job config.JobConfig, t Target, defaultScrapeInterval time.Duration) + ReplaceTargets(job config.JobConfig, newTargets []Target, defaultScrapeInterval time.Duration) Remove(t Target) - AddTargetsFromConfig(config *config.Config) + AddTargetsFromConfig(config config.Config) Pools() map[string]*TargetPool } @@ -53,30 +53,27 @@ func (m *targetManager) release() { <-m.requestAllowance } -func (m *targetManager) TargetPoolForJob(job *config.JobConfig, defaultScrapeInterval time.Duration) (targetPool *TargetPool) { - targetPool, ok := m.poolsByJob[job.Name] +func (m *targetManager) TargetPoolForJob(job config.JobConfig, defaultScrapeInterval time.Duration) (targetPool *TargetPool) { + targetPool, ok := m.poolsByJob[job.GetName()] if !ok { targetPool = NewTargetPool(m) - log.Printf("Pool for job %s does not exist; creating and starting...", job.Name) + log.Printf("Pool for job %s does not exist; creating and starting...", job.GetName()) - interval := job.ScrapeInterval - if interval == 0 { - interval = defaultScrapeInterval - } - m.poolsByJob[job.Name] = targetPool + interval := job.ScrapeInterval() + m.poolsByJob[job.GetName()] = targetPool go targetPool.Run(m.results, interval) } return } -func (m *targetManager) AddTarget(job *config.JobConfig, t Target, defaultScrapeInterval time.Duration) { +func (m *targetManager) AddTarget(job config.JobConfig, t Target, defaultScrapeInterval time.Duration) { targetPool := m.TargetPoolForJob(job, defaultScrapeInterval) targetPool.AddTarget(t) - m.poolsByJob[job.Name] = targetPool + m.poolsByJob[job.GetName()] = targetPool } -func (m *targetManager) ReplaceTargets(job *config.JobConfig, newTargets []Target, defaultScrapeInterval time.Duration) { +func (m *targetManager) ReplaceTargets(job config.JobConfig, newTargets []Target, defaultScrapeInterval time.Duration) { targetPool := m.TargetPoolForJob(job, defaultScrapeInterval) targetPool.replaceTargets(newTargets) } @@ -85,19 +82,21 @@ func (m targetManager) Remove(t Target) { panic("not implemented") } -func (m *targetManager) AddTargetsFromConfig(config *config.Config) { - for _, job := range config.Jobs { - for _, configTargets := range job.Targets { +func (m *targetManager) AddTargetsFromConfig(config config.Config) { + for _, job := range config.Jobs() { + for _, targetGroup := range job.TargetGroup { baseLabels := model.LabelSet{ - model.JobLabel: model.LabelValue(job.Name), + model.JobLabel: model.LabelValue(job.GetName()), } - for label, value := range configTargets.Labels { - baseLabels[label] = value + if targetGroup.Labels != nil { + for _, label := range targetGroup.Labels.Label { + baseLabels[model.LabelName(label.GetName())] = model.LabelValue(label.GetValue()) + } } - for _, endpoint := range configTargets.Endpoints { + for _, endpoint := range targetGroup.Target { target := NewTarget(endpoint, time.Second*5, baseLabels) - m.AddTarget(&job, target, config.Global.ScrapeInterval) + m.AddTarget(job, target, config.ScrapeInterval()) } } } diff --git a/retrieval/targetmanager_test.go b/retrieval/targetmanager_test.go index 709697a76b..fdd286e2dc 100644 --- a/retrieval/targetmanager_test.go +++ b/retrieval/targetmanager_test.go @@ -14,7 +14,9 @@ package retrieval import ( + "code.google.com/p/goprotobuf/proto" "github.com/prometheus/prometheus/config" + pb "github.com/prometheus/prometheus/config/generated" "github.com/prometheus/prometheus/model" "github.com/prometheus/prometheus/retrieval/format" "github.com/prometheus/prometheus/utility/test" @@ -67,11 +69,17 @@ func (t *fakeTarget) Merge(newTarget Target) {} func testTargetManager(t test.Tester) { results := make(chan format.Result, 5) targetManager := NewTargetManager(results, 3) - testJob1 := &config.JobConfig{ - Name: "test_job1", + testJob1 := config.JobConfig{ + JobConfig: pb.JobConfig{ + Name: proto.String("test_job1"), + ScrapeInterval: proto.String("1m"), + }, } - testJob2 := &config.JobConfig{ - Name: "test_job2", + testJob2 := config.JobConfig{ + JobConfig: pb.JobConfig{ + Name: proto.String("test_job2"), + ScrapeInterval: proto.String("1m"), + }, } target1GroupA := &fakeTarget{ diff --git a/rules/manager.go b/rules/manager.go index 9bb5065b4f..e74533fab4 100644 --- a/rules/manager.go +++ b/rules/manager.go @@ -27,7 +27,7 @@ type Result struct { } type RuleManager interface { - AddRulesFromConfig(config *config.Config) error + AddRulesFromConfig(config config.Config) error } type ruleManager struct { @@ -87,8 +87,8 @@ func (m *ruleManager) runIteration(results chan *Result) { wg.Wait() } -func (m *ruleManager) AddRulesFromConfig(config *config.Config) error { - for _, ruleFile := range config.Global.RuleFiles { +func (m *ruleManager) AddRulesFromConfig(config config.Config) error { + for _, ruleFile := range config.Global.RuleFile { newRules, err := LoadRulesFromFile(ruleFile) if err != nil { return err diff --git a/web/api/targets.go b/web/api/targets.go index 687ebfbbd7..a605270013 100644 --- a/web/api/targets.go +++ b/web/api/targets.go @@ -34,7 +34,7 @@ func (serv MetricsService) SetTargets(targetGroups []TargetGroup, jobName string for _, targetGroup := range targetGroups { // Do mandatory map type conversion due to Go shortcomings. baseLabels := model.LabelSet{ - model.JobLabel: model.LabelValue(job.Name), + model.JobLabel: model.LabelValue(job.GetName()), } for label, value := range targetGroup.BaseLabels { baseLabels[model.LabelName(label)] = model.LabelValue(value) @@ -45,6 +45,6 @@ func (serv MetricsService) SetTargets(targetGroups []TargetGroup, jobName string newTargets = append(newTargets, newTarget) } } - serv.appState.TargetManager.ReplaceTargets(job, newTargets, serv.appState.Config.Global.ScrapeInterval) + serv.appState.TargetManager.ReplaceTargets(*job, newTargets, serv.appState.Config.ScrapeInterval()) } } diff --git a/web/status.go b/web/status.go index ed428f75c4..dafb581b70 100644 --- a/web/status.go +++ b/web/status.go @@ -44,7 +44,7 @@ func (h *StatusHandler) Run() { }) h.PrometheusStatus = &PrometheusStatus{ - Config: h.appState.Config.ToString(0), + Config: h.appState.Config.String(), Rules: "TODO: list rules here", Status: "TODO: add status information here", TargetPools: h.appState.TargetManager.Pools(),