Update for prometheus-community

* Add prometheus-community boilerplate.
* Switch from external harness package to internal.
* Update imports to new locations.
* Cleanup old `gow` build.

Signed-off-by: Ben Kochie <superq@gmail.com>
This commit is contained in:
Ben Kochie 2020-04-17 08:24:27 +02:00
parent 51e3dc02a3
commit 61232ef8cf
No known key found for this signature in database
GPG Key ID: C646B23C9E3245F1
15 changed files with 629 additions and 27 deletions

81
.circleci/config.yml Normal file
View File

@ -0,0 +1,81 @@
---
version: 2.1
orbs:
prometheus: prometheus/prometheus@0.4.0
executors:
# This must match .promu.yml.
golang:
docker:
- image: circleci/golang:1.14
jobs:
test:
executor: golang
steps:
- prometheus/setup_environment
- run: make
- prometheus/store_artifact:
file: json-exporter
publish_master:
executor: golang
steps:
- prometheus/setup_build_environment
- prometheus/publish_images:
registry: docker.io
organization: prometheuscommunity
login_variable: DOCKER_LOGIN
password_variable: DOCKER_PASSWORD
publish_release:
executor: golang
steps:
- prometheus/setup_build_environment
- run: promu crossbuild tarballs
- run: promu checksum .tarballs
- run: promu release .tarballs
- store_artifacts:
path: .tarballs
destination: releases
- prometheus/publish_release_images:
registry: docker.io
organization: prometheuscommunity
login_variable: DOCKER_LOGIN
password_variable: DOCKER_PASSWORD
workflows:
version: 2
json-exporter:
jobs:
- test:
filters:
tags:
only: /.*/
- prometheus/build:
name: build
filters:
tags:
only: /.*/
- publish_master:
context: org-context
requires:
- test
- build
filters:
branches:
only: master
- publish_release:
context: org-context
requires:
- test
- build
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/

24
.promu.yml Normal file
View File

@ -0,0 +1,24 @@
go:
# Whenever the Go version is updated here, .travis.yml and
# .circle/config.yml should also be updated.
version: 1.14
repository:
path: github.com/superq/prometheus-json-exporter
build:
binaries:
- name: json_exporter
flags: -a -tags 'netgo static_build'
ldflags: |
-X github.com/prometheus/common/version.Version={{.Version}}
-X github.com/prometheus/common/version.Revision={{.Revision}}
-X github.com/prometheus/common/version.Branch={{.Branch}}
-X github.com/prometheus/common/version.BuildUser={{user}}@{{host}}
-X github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}}
tarball:
files:
- LICENSE
crossbuild:
platforms:
- linux/amd64
- linux/arm
- linux/arm64

9
Makefile Normal file
View File

@ -0,0 +1,9 @@
# Ensure that 'all' is the default target otherwise it will be the first target from Makefile.common.
all::
# Needs to be defined before including Makefile.common to auto-generate targets
DOCKER_ARCHS ?= amd64 armv7 arm64 ppc64le
include Makefile.common
DOCKER_IMAGE_NAME ?= json-exporter

277
Makefile.common Normal file
View File

@ -0,0 +1,277 @@
# Copyright 2018 The Prometheus Authors
# 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.
# A common Makefile that includes rules to be reused in different prometheus projects.
# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository!
# Example usage :
# Create the main Makefile in the root project directory.
# include Makefile.common
# customTarget:
# @echo ">> Running customTarget"
#
# Ensure GOBIN is not set during build so that promu is installed to the correct path
unexport GOBIN
GO ?= go
GOFMT ?= $(GO)fmt
FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
GOOPTS ?=
GOHOSTOS ?= $(shell $(GO) env GOHOSTOS)
GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH)
GO_VERSION ?= $(shell $(GO) version)
GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
GOVENDOR :=
GO111MODULE :=
ifeq (, $(PRE_GO_111))
ifneq (,$(wildcard go.mod))
# Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI).
GO111MODULE := on
ifneq (,$(wildcard vendor))
# Always use the local vendor/ directory to satisfy the dependencies.
GOOPTS := $(GOOPTS) -mod=vendor
endif
endif
else
ifneq (,$(wildcard go.mod))
ifneq (,$(wildcard vendor))
$(warning This repository requires Go >= 1.11 because of Go modules)
$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)')
endif
else
# This repository isn't using Go modules (yet).
GOVENDOR := $(FIRST_GOPATH)/bin/govendor
endif
endif
PROMU := $(FIRST_GOPATH)/bin/promu
pkgs = ./...
ifeq (arm, $(GOHOSTARCH))
GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM)
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM)
else
GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
endif
PROMU_VERSION ?= 0.5.0
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?=
GOLANGCI_LINT_VERSION ?= v1.18.0
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
endif
endif
PREFIX ?= $(shell pwd)
BIN_DIR ?= $(shell pwd)
DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
DOCKERFILE_PATH ?= ./Dockerfile
DOCKERBUILD_CONTEXT ?= ./
DOCKER_REPO ?= prom
DOCKER_ARCHS ?= amd64
BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS))
PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS))
TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS))
ifeq ($(GOHOSTARCH),amd64)
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows))
# Only supported on amd64
test-flags := -race
endif
endif
# This rule is used to forward a target like "build" to "common-build". This
# allows a new "build" target to be defined in a Makefile which includes this
# one and override "common-build" without override warnings.
%: common-% ;
.PHONY: common-all
common-all: precheck style check_license lint unused build test
.PHONY: common-style
common-style:
@echo ">> checking code style"
@fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \
if [ -n "$${fmtRes}" ]; then \
echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \
echo "Please ensure you are using $$($(GO) version) for formatting code."; \
exit 1; \
fi
.PHONY: common-check_license
common-check_license:
@echo ">> checking license header"
@licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \
awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \
done); \
if [ -n "$${licRes}" ]; then \
echo "license header checking failed:"; echo "$${licRes}"; \
exit 1; \
fi
.PHONY: common-deps
common-deps:
@echo ">> getting dependencies"
ifdef GO111MODULE
GO111MODULE=$(GO111MODULE) $(GO) mod download
else
$(GO) get $(GOOPTS) -t ./...
endif
.PHONY: common-test-short
common-test-short:
@echo ">> running short tests"
GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs)
.PHONY: common-test
common-test:
@echo ">> running all tests"
GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
.PHONY: common-format
common-format:
@echo ">> formatting code"
GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs)
.PHONY: common-vet
common-vet:
@echo ">> vetting code"
GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs)
.PHONY: common-lint
common-lint: $(GOLANGCI_LINT)
ifdef GOLANGCI_LINT
@echo ">> running golangci-lint"
ifdef GO111MODULE
# 'go list' needs to be executed before staticcheck to prepopulate the modules cache.
# Otherwise staticcheck might fail randomly for some reason not yet explained.
GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null
GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs)
else
$(GOLANGCI_LINT) run $(pkgs)
endif
endif
# For backward-compatibility.
.PHONY: common-staticcheck
common-staticcheck: lint
.PHONY: common-unused
common-unused: $(GOVENDOR)
ifdef GOVENDOR
@echo ">> running check for unused packages"
@$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages'
else
ifdef GO111MODULE
@echo ">> running check for unused/missing packages in go.mod"
GO111MODULE=$(GO111MODULE) $(GO) mod tidy
ifeq (,$(wildcard vendor))
@git diff --exit-code -- go.sum go.mod
else
@echo ">> running check for unused packages in vendor/"
GO111MODULE=$(GO111MODULE) $(GO) mod vendor
@git diff --exit-code -- go.sum go.mod vendor/
endif
endif
endif
.PHONY: common-build
common-build: promu
@echo ">> building binaries"
GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES)
.PHONY: common-tarball
common-tarball: promu
@echo ">> building release tarball"
$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
.PHONY: common-docker $(BUILD_DOCKER_ARCHS)
common-docker: $(BUILD_DOCKER_ARCHS)
$(BUILD_DOCKER_ARCHS): common-docker-%:
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \
-f $(DOCKERFILE_PATH) \
--build-arg ARCH="$*" \
--build-arg OS="linux" \
$(DOCKERBUILD_CONTEXT)
.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
.PHONY: common-docker-manifest
common-docker-manifest:
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG))
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)"
.PHONY: promu
promu: $(PROMU)
$(PROMU):
$(eval PROMU_TMP := $(shell mktemp -d))
curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP)
mkdir -p $(FIRST_GOPATH)/bin
cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
rm -r $(PROMU_TMP)
.PHONY: proto
proto:
@echo ">> generating code from proto files"
@./scripts/genproto.sh
ifdef GOLANGCI_LINT
$(GOLANGCI_LINT):
mkdir -p $(FIRST_GOPATH)/bin
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh \
| sed -e '/install -d/d' \
| sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
endif
ifdef GOVENDOR
.PHONY: $(GOVENDOR)
$(GOVENDOR):
GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor
endif
.PHONY: precheck
precheck::
define PRECHECK_COMMAND_template =
precheck:: $(1)_precheck
PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1)))
.PHONY: $(1)_precheck
$(1)_precheck:
@if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \
echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \
exit 1; \
fi
endef

1
VERSION Normal file
View File

@ -0,0 +1 @@
0.1.0

20
gow
View File

@ -1,20 +0,0 @@
#!/bin/bash
set -e
GO=go
PACKAGE_LOCATION_GIT_REMOTE=origin
PACKAGE_LOCATION=$(git config --get "remote.$PACKAGE_LOCATION_GIT_REMOTE.url" | sed 's/^[^@]*@//' | sed 's/^.*:\/\///' | sed 's/\.git$//')
PROJECT_ROOT_DIR=$(cd $(dirname $0); pwd)
GOPATH=$PROJECT_ROOT_DIR/build
LOCAL_PACKAGE_PATH=$GOPATH/src/$(echo "$PACKAGE_LOCATION" | tr ':' '/')
LOCAL_PACKAGE_DIR=$(dirname $LOCAL_PACKAGE_PATH)
mkdir -p $LOCAL_PACKAGE_DIR
ln -sfn $PROJECT_ROOT_DIR $LOCAL_PACKAGE_PATH
export GOBIN="$GOPATH/bin"
export GOPATH
exec $GO "$@"

5
harness/collector.go Normal file
View File

@ -0,0 +1,5 @@
package harness
type Collector interface {
Collect(*MetricRegistry)
}

92
harness/exporter.go Normal file
View File

@ -0,0 +1,92 @@
package harness
import (
"fmt"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
const DefaultMetricsPath = "/metrics"
type ExporterOpts struct {
// The representative name of exporter
Name string
// The version of exporter
Version string
// The HTTP endpoint path which used to provide metrics
MetricsPath string
// Whether to call Collect() of collector periodically
Tick bool
// Whether to reset all metrics per tick
ResetOnTick bool
// Command line usage
Usage string
// Additional command line flags which can be accepted
Flags []cli.Flag
// Function to instantiate collector
Init func(*cli.Context, *MetricRegistry) (Collector, error)
}
func NewExporterOpts(name string, version string) *ExporterOpts {
return &ExporterOpts{
Name: name,
Version: version,
MetricsPath: DefaultMetricsPath,
Tick: true,
ResetOnTick: true,
Usage: "",
}
}
type exporter struct {
*ExporterOpts
}
func setupLogging(c *cli.Context) {
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
})
levelString := c.String("log-level")
level, err := log.ParseLevel(levelString)
if err != nil {
log.Fatalf("could not set log level to '%s';err:<%s>", levelString, err)
}
log.SetLevel(level)
}
func (exp *exporter) main(c *cli.Context) {
setupLogging(c)
registry := newRegistry()
collector, err := exp.Init(c, registry)
if err != nil {
log.Fatal(err)
}
if exp.Tick {
collector.Collect(registry)
interval := c.Int("interval")
go func() {
for _ = range time.Tick(time.Duration(interval) * time.Second) {
if exp.ResetOnTick {
registry.Reset()
}
collector.Collect(registry)
}
}()
}
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Location", exp.MetricsPath)
w.WriteHeader(http.StatusFound)
})
http.Handle(exp.MetricsPath, promhttp.Handler())
if err := http.ListenAndServe(fmt.Sprintf(":%d", c.Int("port")), nil); err != nil {
log.Fatal(err)
}
}

70
harness/main.go Normal file
View File

@ -0,0 +1,70 @@
package harness
import (
"github.com/urfave/cli"
"os"
)
var (
defaultOpts = []cli.Flag{
cli.IntFlag{
Name: "port",
Usage: "The port number used to expose metrics via http",
Value: 7979,
},
cli.StringFlag{
Name: "log-level",
Usage: "Set Logging level",
Value: "info",
},
}
defaultTickOpt = cli.IntFlag{
Name: "interval",
Usage: "Interval to fetch metrics from the endpoint in second",
Value: 60,
}
)
func MakeApp(opts *ExporterOpts) *cli.App {
exp := &exporter{opts}
app := cli.NewApp()
app.Name = opts.Name
app.Version = opts.Version
app.Usage = "A prometheus " + opts.Name
app.UsageText = opts.Usage
app.Action = exp.main
app.Flags = buildOptsWithDefault(opts.Flags, defaultOpts)
if opts.Tick && !contains(app.Flags, defaultTickOpt) {
app.Flags = append(app.Flags, defaultTickOpt)
}
return app
}
func buildOptsWithDefault(opts []cli.Flag, defaultOpts []cli.Flag) []cli.Flag {
for _, opt := range defaultOpts {
if !contains(opts, opt) {
opts = append(opts, opt)
}
}
return opts
}
func contains(opts []cli.Flag, opt cli.Flag) bool {
for _, o := range opts {
if o.GetName() == opt.GetName() {
return true
}
}
return false
}
func Main(opts *ExporterOpts) {
err := MakeApp(opts).Run(os.Args)
if err != nil {
os.Exit(1)
}
}

49
harness/registry.go Normal file
View File

@ -0,0 +1,49 @@
package harness
import (
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
)
type MetricRegistry struct {
metrics map[string]prometheus.Collector
}
func newRegistry() *MetricRegistry {
return &MetricRegistry{
metrics: make(map[string]prometheus.Collector),
}
}
func (reg *MetricRegistry) Register(name string, metric prometheus.Collector) {
log.Infof("metric registered;name:<%s>", name)
reg.metrics[name] = metric
prometheus.MustRegister(metric)
}
func (reg *MetricRegistry) Unregister(name string) {
if metric := reg.metrics[name]; metric != nil {
log.Infof("metric unregistered;name:<%s>", name)
prometheus.Unregister(metric)
delete(reg.metrics, name)
}
}
func (reg *MetricRegistry) Get(name string) prometheus.Collector {
return reg.metrics[name]
}
// Since prometheus.MetricVec is a struct but not interface,
// need to intrduce an interface to check if we can call Reset() on a metric.
type resettable interface {
Reset()
}
func (reg *MetricRegistry) Reset() {
for name, metric := range reg.metrics {
if vec, ok := metric.(resettable); ok {
log.Debugf("resetting metric;name:<%s>", name)
vec.Reset()
}
}
}

9
harness/util.go Normal file
View File

@ -0,0 +1,9 @@
package harness
import (
"strings"
)
func MakeMetricName(parts ...string) string {
return strings.Join(parts, "_")
}

3
harness/version.go Normal file
View File

@ -0,0 +1,3 @@
package harness
const Version = "0.0.1"

View File

@ -2,11 +2,12 @@ package jsonexporter
import (
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/kawamuray/jsonpath" // Originally: "github.com/NickSardo/jsonpath"
"github.com/kawamuray/prometheus-exporter-harness/harness"
"io/ioutil"
"net/http"
"github.com/kawamuray/jsonpath" // Originally: "github.com/NickSardo/jsonpath"
log "github.com/sirupsen/logrus"
"github.com/prometheus-community/json-exporter/harness"
)
type Collector struct {

View File

@ -2,9 +2,10 @@ package jsonexporter
import (
"fmt"
"github.com/urfave/cli"
"github.com/kawamuray/prometheus-exporter-harness/harness"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus-community/json-exporter/harness"
"github.com/urfave/cli"
)
type ScrapeType struct {

View File

@ -5,10 +5,10 @@ import (
"math"
"strconv"
log "github.com/Sirupsen/logrus"
"github.com/kawamuray/jsonpath" // Originally: "github.com/NickSardo/jsonpath"
"github.com/kawamuray/prometheus-exporter-harness/harness"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"github.com/prometheus-community/json-exporter/harness"
)
type JsonScraper interface {