Skip to content

Commit

Permalink
Added interactive tutorial [kubeCon]
Browse files Browse the repository at this point in the history
Signed-off-by: bwplotka <bwplotka@gmail.com>
  • Loading branch information
bwplotka committed Apr 21, 2023
1 parent e3b6de8 commit 5c46b2f
Show file tree
Hide file tree
Showing 11 changed files with 1,300 additions and 0 deletions.
2 changes: 2 additions & 0 deletions tutorial/whatsup/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
internal/e2e_*
whatsup.yaml
Binary file added tutorial/whatsup/ContribFest.pdf
Binary file not shown.
29 changes: 29 additions & 0 deletions tutorial/whatsup/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

.PHONY: help
help: ## Displays help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n\nTargets:\n"} /^[a-z0-9A-Z_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)

.PHONY: init
init: ## init
$(MAKE) stop
go test -count 1 -v -run ^TestPlayground ./internal & # count 1 is to avoid cache.

.PHONY: stop
stop: ## stop init
@curl -s http://localhost:19920 || true

.PHONY: run
run: ## run whatsup
@go run main.go -config-file=./whatsup.yaml -address=:99

.PHONY: metrics
metrics: ## get metrics from whatsup
@curl -H 'Accept: application/openmetrics-text' localhost:99/metrics

.PHONY: whatsup
whatsup: ## ask what's up
@curl localhost:99/whatsup

.PHONY: test
test: ## run acceptance tests
go test -count 1 -v -run ^TestAcceptance ./internal & # count 1 is to avoid cache.
3 changes: 3 additions & 0 deletions tutorial/whatsup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# client_golang Tutorial: "WhatsUp"

See [slides](./ContribFest.pdf)
55 changes: 55 additions & 0 deletions tutorial/whatsup/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module github.com/prometheus/client_golang/tutorial

go 1.20

require (
github.com/bwplotka/tracing-go v0.0.0-20230421061608-abdf862ceccd
github.com/efficientgo/core v1.0.0-rc.2
github.com/efficientgo/e2e v0.14.1-0.20230421070206-d72d43f3b937
github.com/oklog/run v1.1.0
github.com/prometheus/client_golang v1.15.1-0.20230416215738-0963f595c689
github.com/prometheus/common v0.42.0
gopkg.in/yaml.v2 v2.4.0
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3 // indirect
go.opentelemetry.io/otel/metric v0.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.6.3 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.opentelemetry.io/proto/otlp v0.15.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/oauth2 v0.5.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
)
527 changes: 527 additions & 0 deletions tutorial/whatsup/go.sum

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions tutorial/whatsup/internal/acceptance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package internal

import (
"fmt"
"io"
"net/http"
"strings"
"testing"

"github.com/efficientgo/core/testutil"
)

func TestAcceptance(t *testing.T) {
resp, err := http.Get(fmt.Sprintf("http://localhost:%v/metrics", WhatsupPort))
testutil.Ok(t, err)
defer resp.Body.Close()

b, err := io.ReadAll(resp.Body)
testutil.Ok(t, err)

metrics := string(b)

gotErr := false
for _, tcase := range []struct {
expectMetricName string
expectMetricType string
expectExemplar bool // TODO
}{
{
expectMetricName: "whatsup_queries_handled_total",
expectMetricType: "counter",
},
{
expectMetricName: "whatsup_last_response_elements",
expectMetricType: "gauge",
},
{
expectMetricName: "build_info",
expectMetricType: "gauge",
},
{
expectMetricName: "whatsup_queries_duration_seconds",
expectMetricType: "histogram",
},
} {
if !t.Run(fmt.Sprintf("Metric %v type %v with exemplar %v", tcase.expectMetricName, tcase.expectMetricType, tcase.expectExemplar), func(t *testing.T) {
// Yolo.
expLine := fmt.Sprintf("# TYPE %v %v", tcase.expectMetricName, tcase.expectMetricType)
if strings.Index(metrics, expLine) == -1 {
t.Error(expLine, "not found!")
}
// TODO(bwplotka): Check all properly.
}) {
gotErr = true
}
}

if gotErr {
fmt.Println("Got this response from ", fmt.Sprintf("http://localhost:%v", WhatsupPort), ":", metrics)
}

}
54 changes: 54 additions & 0 deletions tutorial/whatsup/internal/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package internal

import (
"flag"
"os"

"gopkg.in/yaml.v2"
)

const WhatsupPort = "99"

var (
WhatsAppFlags = flag.NewFlagSet("whatsapp", flag.ExitOnError)

prometheusAddr = WhatsAppFlags.String("prometheus-address", "", "The address of Prometheus to query.")
traceEndpoint = WhatsAppFlags.String("trace-endpoint", "", "Optional GRPC OTLP endpoint for tracing backend. Set it to 'stdout' to print traces to the output instead.")
traceSamplingRatio = WhatsAppFlags.Float64("trace-sampling-ratio", 1.0, "Sampling ratio. Currently 1.0 is the best value to use with exemplars.")
configFile = WhatsAppFlags.String("config-file", "./whatsup.yaml", "YAML configuration with same options as flags here. Flags override the configuration items.")
)

type Config struct {
PrometheusAddr string `yaml:"PrometheusAddress,omitempty"`
TraceEndpoint string `yaml:"TraceEndpoint,omitempty"`
TraceSamplingRatio float64 `yaml:"TraceSamplingRatio,omitempty"`
}

func ParseOptions(args []string) (Config, error) {
c := Config{}

if err := WhatsAppFlags.Parse(args); err != nil {
return c, err
}

if *configFile != "" {
b, err := os.ReadFile(*configFile)
if err != nil {
return c, err
}
if err := yaml.Unmarshal(b, &c); err != nil {
return c, err
}
}

if *prometheusAddr != "" {
c.PrometheusAddr = *prometheusAddr
}
if *traceEndpoint != "" {
c.TraceEndpoint = *traceEndpoint
}
if *traceSamplingRatio > 0 {
c.TraceSamplingRatio = *traceSamplingRatio
}
return c, nil
}
93 changes: 93 additions & 0 deletions tutorial/whatsup/internal/playground_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package internal

import (
"fmt"
"os"
"testing"
"time"

"github.com/efficientgo/core/testutil"
"github.com/efficientgo/e2e"
e2edb "github.com/efficientgo/e2e/db"
e2einteractive "github.com/efficientgo/e2e/interactive"
e2emon "github.com/efficientgo/e2e/monitoring"
"github.com/efficientgo/e2e/monitoring/promconfig"
sdconfig "github.com/efficientgo/e2e/monitoring/promconfig/discovery/config"
"github.com/efficientgo/e2e/monitoring/promconfig/discovery/targetgroup"
"github.com/prometheus/common/model"
"gopkg.in/yaml.v2"
)

func TestPlayground(t *testing.T) {
// NOTE: Only one run at the time will work due to statics ports used.

e, err := e2e.New(e2e.WithVerbose())
testutil.Ok(t, err)
t.Cleanup(e.Close)

// Setup in-memory Jaeger as our tracing backend.
jaeger := e2emon.AsInstrumented(e.Runnable("tracing").
WithPorts(
map[string]int{
"http.front": 16686,
"grpc.otlp": 4317,
"http.metrics": 14269,
}).
Init(e2e.StartOptions{
Image: "jaegertracing/all-in-one:1.35",
EnvVars: map[string]string{"COLLECTOR_OTLP_ENABLED": "true"},
}), "http.metrics")
testutil.Ok(t, e2e.StartAndWaitReady(jaeger))

prom := e2edb.NewPrometheus(e, "prometheus", e2edb.WithImage("prom/prometheus:v2.43.0-stringlabels"))
testutil.Ok(t, e2e.StartAndWaitReady(prom))

// Write config file for whatsup app.
c := Config{
PrometheusAddr: "http://" + prom.Endpoint("http"),
TraceEndpoint: jaeger.Endpoint("grpc.otlp"),
TraceSamplingRatio: 1,
}
b, err := yaml.Marshal(c)
testutil.Ok(t, err)
testutil.Ok(t, os.WriteFile("../whatsup.yaml", b, os.ModePerm))

testutil.Ok(t, prom.SetConfig(prometheusConfig(map[string]string{
"prometheus": prom.InternalEndpoint("http"),
"jaeger": jaeger.InternalEndpoint("http.metrics"),
"whatsup": fmt.Sprintf("host.docker.internal:%v", WhatsupPort),
})))
// Due to VM based docker setups (e.g. MacOS), file sharing can be slower - do more sighups just in case (noops if all good)
prom.Exec(e2e.NewCommand("kill", "-SIGHUP", "1"))
prom.Exec(e2e.NewCommand("kill", "-SIGHUP", "1"))

testutil.Ok(t, e2einteractive.OpenInBrowser("http://"+jaeger.Endpoint("http.front")))
testutil.Ok(t, e2einteractive.OpenInBrowser("http://"+prom.Endpoint("http")))
testutil.Ok(t, e2einteractive.RunUntilEndpointHitWithPort(19920))
}

func prometheusConfig(jobToScrapeTargetAddress map[string]string) promconfig.Config {
h, _ := os.Hostname()
cfg := promconfig.Config{
GlobalConfig: promconfig.GlobalConfig{
ExternalLabels: map[model.LabelName]model.LabelValue{"prometheus": model.LabelValue(h)},
ScrapeInterval: model.Duration(15 * time.Second),
},
}

for job, s := range jobToScrapeTargetAddress {
scfg := &promconfig.ScrapeConfig{
JobName: job,
ServiceDiscoveryConfig: sdconfig.ServiceDiscoveryConfig{},
}

g := &targetgroup.Group{
Targets: []model.LabelSet{map[model.LabelName]model.LabelValue{
model.AddressLabel: model.LabelValue(s),
}},
}
scfg.ServiceDiscoveryConfig.StaticConfigs = append(scfg.ServiceDiscoveryConfig.StaticConfigs, g)
cfg.ScrapeConfigs = append(cfg.ScrapeConfigs, scfg)
}
return cfg
}

0 comments on commit 5c46b2f

Please sign in to comment.