Skip to content

Commit

Permalink
Merge pull request #7 from pb82/v1.1.0
Browse files Browse the repository at this point in the history
V1.1.0
  • Loading branch information
pb82 authored Apr 2, 2023
2 parents f679efd + e219071 commit 91c3175
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 27 deletions.
44 changes: 33 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ It allows you to define time series and values and send them directly to Prometh

I found this very useful for testing PromQL queries and alerts.
Sometimes you don't have the right data in Prometheus or simply no access.
This tool let's you simulate the data you need and test your queries against it.
This tool lets you simulate the data you need and test your queries against it.

## Installation

Expand All @@ -19,6 +19,16 @@ A specific version:

`GOPROXY=direct go install github.com/pb82/prometheus-toolbox@<version>`

*NOTE*: [Go](https://go.dev/) must be installed

### Building locally

Build directly for your platform with go:

```shell
$ go build
```

## Starting a local development environment

To start a local development environment including Prometheus and Grafana use the built-in `--environment` command.
Expand Down Expand Up @@ -46,6 +56,17 @@ The Prometheus and Grafana images can be overridden by exporting the `PROMETHEUS
$ export GRAFANA_IMAGE=docker.io/grafana/grafana-oss:8.5.15 && ./prometheus-toolbox --environment | bash
```

### Importing Prometheus rules into the local development environment

The environment script checks for the presence of a file with the name `rules.yml` in the directory it's running.
If present, Prometheus is configured to import [alerting](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) and [recording](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) rules from it.

A sample rules file can be generated with the following command:

```shell
$ prometheus-toolbox --rules > rules.yml
```

# Flags

The following flags are accepted:
Expand All @@ -59,6 +80,7 @@ The following flags are accepted:
* `--proxy.listen.port` Port to receive remote write requests, defaults to 3241
* `--environment` Print environment setup script and exit
* `--init` Print sample config file and exit
* `--rules` Print sample alerting rules file and exit
* `--oidc.enabled` Enable authenticated requests
* `--oidc.issuer` OIDC auth token issuer URL
* `--oidc.clientId` OIDC client id
Expand All @@ -72,16 +94,16 @@ This tool reads from a config file where the simulated time series and values ar
The format is:

```yaml
interval: "10s" # Interval between samples, in this case 10 seconds
time_series: # List of time series to simulate
- series: metric_a{label="a"} # Time series (metric name and label list)
values: 1+1x100 # Precalculated samples
- series: metric_a{label="a"} # Another time series
stream: 1+0 # Realtime samples
- series: metric_b{label="a"} #
values: 1+1x50 50+0x50 # Multiple value sequences are possible
- series: metric_c{label="a"} #
values: _x50 1+0x50 # The underscore represents an empty value (no data received). Time still advances.
interval: "10s" # Interval between samples, in this case 10 seconds
time_series: # List of time series to simulate
- series: metric_a{label="a"} # Time series (metric name and label list)
values: 1+1x100 # Precalculated samples
- series: metric_a{label="a"} # Another time series
stream: 1+0 # Realtime samples
- series: metric_b{label="a"} #
values: 1+1x50 50+0x50 # Multiple value sequences are possible
- series: metric_c{l1="a",l2="b"} # Multiple labels are possible
values: _x50 1+0x50 # The underscore represents an empty value (no data received). Time still advances.
```
The format for precalculated samples is:
Expand Down
32 changes: 23 additions & 9 deletions environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ PROMETHEUS_NAME="prometheus_toolbox_prometheus"
PROMETHEUS_PORT=9090

GRAFANA_NAME="prometheus_toolbox_grafana"

: "${GRAFANA_IMAGE:="docker.io/grafana/grafana-oss:latest"}"
GRAFANA_PORT=3000

Expand All @@ -26,16 +25,31 @@ fi

echo "detected runtime is $RUNTIME, starting containers. this can take some time..."

# Creata a basic prometheus config file
cat > prometheus.yml <<- EOF
global:
scrape_interval: 10s
evaluation_interval: 30s
if [ -f ./rules.yml ]; then
echo "prometheus rules file found, importing alerts"
echo "starting prometheus container from image $PROMETHEUS_IMAGE"
# Create a basic prometheus config file with alerting
cat > prometheus.yml <<- EOF
global:
scrape_interval: 10s
evaluation_interval: 30s
rule_files:
- ./rules.yml
EOF
# start the prometheus container with mounted rules
echo "starting prometheus container from image $PROMETHEUS_IMAGE"
$RUNTIME run -d --rm --name $PROMETHEUS_NAME -p 9090:9090 $OPTS -v $(pwd)/rules.yml:/etc/prometheus/rules.yml -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml $PROMETHEUS_IMAGE --web.enable-remote-write-receiver --config.file=/etc/prometheus/prometheus.yml &> /dev/null
else
cat > prometheus.yml <<- EOF
global:
scrape_interval: 10s
evaluation_interval: 30s
EOF
# start the prometheus container
echo "starting prometheus container from image $PROMETHEUS_IMAGE"
$RUNTIME run -d --rm --name $PROMETHEUS_NAME -p 9090:9090 $OPTS -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml $PROMETHEUS_IMAGE --web.enable-remote-write-receiver --config.file=/etc/prometheus/prometheus.yml &> /dev/null
fi

# start the prometheus container
echo "starting prometheus container from image $PROMETHEUS_IMAGE"
$RUNTIME run -d --rm --name $PROMETHEUS_NAME -p 9090:9090 $OPTS -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml $PROMETHEUS_IMAGE --web.enable-remote-write-receiver --config.file=/etc/prometheus/prometheus.yml &> /dev/null
PROMETHEUS_CONTAINER=`$RUNTIME ps -f name=$PROMETHEUS_NAME --format "{{.ID}}"`

# start the grafana container
Expand Down
18 changes: 14 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var (
oidcAudience *string
oidcEnabled *bool
remoteWriteSuffix *string
rules *bool
)

var (
Expand All @@ -51,27 +52,35 @@ var (

//go:embed config.yml
exampleConfig string

//go:embed rules.yml
exampleRules string
)

func main() {
flag.Parse()

if printVersion != nil && *printVersion {
if *printVersion {
fmt.Printf("Prometheus toolbox v%v", version.Version)
fmt.Println()
os.Exit(0)
}

if environment != nil && *environment {
if *environment {
fmt.Println(environmentSetupScript)
os.Exit(0)
}

if initialize != nil && *initialize {
if *initialize {
fmt.Println(exampleConfig)
os.Exit(0)
}

if *rules {
fmt.Println(exampleRules)
os.Exit(0)
}

bytes, err := os.ReadFile(*configFile)
if err != nil {
fmt.Println(fmt.Sprintf("error reading config file: %v", err.Error()))
Expand All @@ -84,7 +93,7 @@ func main() {
os.Exit(1)
}

if prometheusUrl == nil || *prometheusUrl == "" {
if *prometheusUrl == "" {
fmt.Println("missing prometheus base url, make sure to set --prometheus.url")
os.Exit(1)
}
Expand Down Expand Up @@ -167,4 +176,5 @@ func init() {
oidcAudience = flag.String("oidc.audience", "", "oidc audience")
oidcEnabled = flag.Bool("oidc.enabled", false, "enable oidc token authentication")
remoteWriteSuffix = flag.String("prometheus.url.suffix", DefaultRemoteWriteEndpoint, "allows alternate remote write endpoints")
rules = flag.Bool("rules", false, "print sample alerting rules file and exit")
}
7 changes: 5 additions & 2 deletions pkg/remotewrite/remotewrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,12 @@ func (s *RemoteWriter) SendWriteRequest(wr *prometheus.WriteRequest) error {
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return errors.New(fmt.Sprintf("unexpected remote write status code %v", resp.StatusCode))
return errors.New(fmt.Sprintf("unexpected remote write status code, error reading response body %v", resp.StatusCode))
}
return errors.New(fmt.Sprintf("invalid remote write request, status code: %v, ressponse: %v", resp.StatusCode, string(bytes)))
if len(bytes) > 0 {
return errors.New(fmt.Sprintf("invalid remote write request, status code: %v, response: %v", resp.StatusCode, string(bytes)))
}
return errors.New(fmt.Sprintf("invalid remote write request, status code: %v", resp.StatusCode))
}

return nil
Expand Down
10 changes: 10 additions & 0 deletions rules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
groups:
- name: prometheus-toolbox-alerts
rules:
- alert: DeadMansSwitch
expr: vector(1)
labels:
severity: none
annotations:
summary: A Dead Man's Switch to ensure that alerting works
# Add your own alerting rules below
2 changes: 1 addition & 1 deletion version/version.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package version

var (
Version = "1.0.1"
Version = "1.1.0"
)

0 comments on commit 91c3175

Please sign in to comment.