pax_global_header00006660000000000000000000000064133132043200014501gustar00rootroot0000000000000052 comment=18ab62da62295daebf01a5624be75078eb1e8edb prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/000077500000000000000000000000001331320432000224735ustar00rootroot00000000000000prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/.dockerignore000066400000000000000000000000501331320432000251420ustar00rootroot00000000000000.* vendor Dockerfile Makefile README.md prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/.gitignore000066400000000000000000000004351331320432000244650ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof nginx-vts-exporterprometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/.promu.yml000066400000000000000000000014061331320432000244370ustar00rootroot00000000000000repository: path: github.com/hnlq715/nginx-vts-exporter build: flags: -a -tags netgo ldflags: | -X {{repoPath}}/vendor/github.com/prometheus/common/version.Version={{.Version}} -X {{repoPath}}/vendor/github.com/prometheus/common/version.Revision={{.Revision}} -X {{repoPath}}/vendor/github.com/prometheus/common/version.Branch={{.Branch}} -X {{repoPath}}/vendor/github.com/prometheus/common/version.BuildUser={{user}}@{{host}} -X {{repoPath}}/vendor/github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}} tarball: files: - LICENSE crossbuild: platforms: - linux/amd64 - linux/386 - darwin/amd64 - darwin/386 - windows/amd64 - windows/386prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/.travis.yml000066400000000000000000000002661331320432000246100ustar00rootroot00000000000000sudo: required services: - docker language: go go: - 1.9.4 after_success: - make - make docker - make push - if [[ -n "$TRAVIS_TAG" ]]; then make crossbuild release; fiprometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/Dockerfile000066400000000000000000000005361331320432000244710ustar00rootroot00000000000000FROM quay.io/prometheus/busybox:latest MAINTAINER Sophos COPY nginx-vts-exporter /bin/nginx-vts-exporter COPY docker-entrypoint.sh /bin/docker-entrypoint.sh ENV NGINX_HOST "http://localhost" ENV METRICS_ENDPOINT "/metrics" ENV METRICS_ADDR ":9913" ENV DEFAULT_METRICS_NS "nginx" ENTRYPOINT [ "docker-entrypoint.sh" ]prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/LICENSE000066400000000000000000000020471331320432000235030ustar00rootroot00000000000000MIT License Copyright (c) 2016 Sophos Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/Makefile000066400000000000000000000037361331320432000241440ustar00rootroot00000000000000GO := GO15VENDOREXPERIMENT=1 go PROMU := $(GOPATH)/bin/promu pkgs = $(shell $(GO) list ./... | grep -v /vendor/) PREFIX ?= $(shell pwd) BIN_DIR ?= $(shell pwd) DOCKER_IMAGE_NAME ?= nginx-vts-exporter DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) TAG := $(shell echo `if [ "$(TRAVIS_BRANCH)" = "master" ] || [ "$(TRAVIS_BRANCH)" = "" ] ; then echo "latest"; else echo $(TRAVIS_BRANCH) ; fi`) all: format build test style: @echo ">> checking code style" @! gofmt -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^' test: @echo ">> running tests" @$(GO) test -short $(pkgs) format: @echo ">> formatting code" @$(GO) fmt $(pkgs) vet: @echo ">> vetting code" @$(GO) vet $(pkgs) build: promu @echo ">> building binaries" @$(PROMU) build --prefix $(PREFIX) crossbuild: promu @echo ">> crossbuilding binaries" @$(PROMU) crossbuild tarball: promu @echo ">> building release tarball" @$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) docker: @echo ">> building docker image" @docker build -t "$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" . push: @echo ">> pushing docker image, $(DOCKER_USER),$(DOCKER_IMAGE_NAME),$(TAG)" @echo $(DOCKER_PASS) | docker login -u "$(DOCKER_USER)" --password-stdin @docker tag "$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_USER)/$(DOCKER_IMAGE_NAME):$(TAG)" @docker push "$(DOCKER_USER)/$(DOCKER_IMAGE_NAME):$(TAG)" release: promu github-release @echo ">> pushing binary to github with ghr" @$(PROMU) crossbuild tarballs @$(PROMU) release .tarballs promu: @GOOS=$(shell uname -s | tr A-Z a-z) \ GOARCH=$(subst x86_64,amd64,$(patsubst i%86,386,$(shell uname -m))) \ $(GO) get -u github.com/prometheus/promu github-release: @GOOS=$(shell uname -s | tr A-Z a-z) \ GOARCH=$(subst x86_64,amd64,$(patsubst i%86,386,$(shell uname -m))) \ $(GO) get -u github.com/aktau/github-release .PHONY: all style format build test vet tarball docker promu prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/README.md000066400000000000000000000142041331320432000237530ustar00rootroot00000000000000# nginx-vts-exporter [![Build Status](https://travis-ci.org/hnlq715/nginx-vts-exporter.svg?branch=master)](https://travis-ci.org/hnlq715/nginx-vts-exporter) [![Docker Pulls](https://img.shields.io/docker/pulls/sophos/nginx-vts-exporter.svg)](https://hub.docker.com/r/sophos/nginx-vts-exporter) [![Github All Releases](https://img.shields.io/github/downloads/hnlq715/nginx-vts-exporter/total.svg)](https://github.com/hnlq715/nginx-vts-exporter) [![GitHub release](https://img.shields.io/github/release/hnlq715/nginx-vts-exporter.svg)](https://github.com/hnlq715/nginx-vts-exporter) [![Go Report Card](https://goreportcard.com/badge/github.com/hnlq715/nginx-vts-exporter)](https://goreportcard.com/report/github.com/hnlq715/nginx-vts-exporter) Simple server that scrapes Nginx [vts](https://github.com/vozlt/nginx-module-vts) stats and exports them via HTTP for Prometheus consumption To support time related histogram metrics, please refer to [hnlq715/nginx-prometheus-metrics](https://github.com/hnlq715/nginx-prometheus-metrics) or [#43](https://github.com/hnlq715/nginx-vts-exporter/issues/43). ## Table of Contents * [Dependency](#dependency) * [Download](#download) * [Compile](#compile) * [build binary](#build-binary) * [build docker image](#build-docker-image) * [Run](#run) * [run binary](#run-binary) * [run docker image](#run-docker-image) * [Environment variables](#environment-variables) * [Metrics](#metrics) * [Server main](#server-main) * [Server zones](#server-zones) * [Filter zones](#filter-zones) * [Upstreams](#upstreams) ## Dependency * [nginx-module-vts](https://github.com/vozlt/nginx-module-vts) * [Prometheus](https://prometheus.io/) * [Golang](https://golang.org/) ## Download Binary can be downloaded from [Releases](https://github.com/hnlq715/nginx-vts-exporter/releases) page. ## Compile ### build binary ``` shell make ``` ### build docker image ``` shell make docker ``` ## Docker Hub Image ``` shell docker pull sophos/nginx-vts-exporter:latest ``` It can be used directly instead of having to build the image yourself. ([Docker Hub sophos/nginx-vts-exporter](https://hub.docker.com/r/sophos/nginx-vts-exporter/)) ## Run ### run binary ``` shell nohup /bin/nginx-vts-exporter -nginx.scrape_uri=http://localhost/status/format/json ``` ### run docker ``` docker run -ti --rm --env NGINX_STATUS="http://localhost/status/format/json" sophos/nginx-vts-exporter ``` ## Environment variables This image is configurable using different env variables Variable name | Default | Description ------------- | ----------- | -------------- NGINX_STATUS | http://localhost/status/format/json | Nginx JSON format status page METRICS_ENDPOINT | /metrics | Metrics endpoint exportation URI METRICS_ADDR | :9913 | Metrics exportation address:port METRICS_NS | nginx | Prometheus metrics Namespaces ## Metrics Documents about exposed Prometheus metrics. For details on the underlying metrics please see [nginx-module-vts](https://github.com/vozlt/nginx-module-vts#json-used-by-status) For grafana dashboard please see [nginx-vts-exporter dashboard](https://grafana.com/dashboards/2949) ### Server main **Metrics details** Nginx data | Name | Exposed informations ------------------ | ------------------------------- | ------------------------ **Info** | `{NAMESPACE}_server_info` | hostName, nginxVersion, uptimeSec | **Connections** | `{NAMESPACE}_server_connections`| status [active, reading, writing, waiting, accepted, handled] **Metrics output example** ``` txt # Server Info nginx_server_info{hostName="localhost", nginxVersion="1.11.1"} 9527 # Server Connections nginx_server_connections{status="accepted"} 70606 ``` ### Server zones **Metrics details** Nginx data | Name | Exposed informations ------------------ | ------------------------------- | ------------------------ **Requests** | `{NAMESPACE}_server_requests` | code [2xx, 3xx, 4xx, 5xx, total], host _(or domain name)_ **Bytes** | `{NAMESPACE}_server_bytes` | direction [in, out], host _(or domain name)_ **Cache** | `{NAMESPACE}_server_cache` | status [bypass, expired, hit, miss, revalidated, scarce, stale, updating], host _(or domain name)_ **Metrics output example** ``` txt # Server Requests nginx_server_requests{code="1xx",host="test.domain.com"} 0 # Server Bytes nginx_server_bytes{direction="in",host="test.domain.com"} 21 # Server Cache nginx_server_cache{host="test.domain.com",status="bypass"} 2 ``` ### Filter zones **Metrics details** Nginx data | Name | Exposed informations ------------------ | --------------------------------- | ------------------------ **Requests** | `{NAMESPACE}_filter_requests` | code [2xx, 3xx, 4xx, 5xx and total], filter, filter name **Bytes** | `{NAMESPACE}_filter_bytes` | direction [in, out], filter, filter name **Response time** | `{NAMESPACE}_filter_responseMsec` | filter, filter name **Metrics output example** ``` txt # Filter Requests nginx_upstream_requests{code="1xx", filter="country", filterName="BY"} 0 # Filter Bytes nginx_upstream_bytes{direction="in", filter="country", filterName="BY"} 0 # Filter Response time nginx_upstream_responseMsec{filter="country", filterName="BY"} 99 ``` ### Upstreams **Metrics details** Nginx data | Name | Exposed informations ------------------ | ----------------------------------- | ------------------------ **Requests** | `{NAMESPACE}_upstream_requests` | code [2xx, 3xx, 4xx, 5xx and total], upstream _(or upstream name)_ **Bytes** | `{NAMESPACE}_upstream_bytes` | direction [in, out], upstream _(or upstream name)_ **Response time** | `{NAMESPACE}_upstream_responseMsec` | backend (or server), in_bytes, out_bytes, upstream _(or upstream name)_ **Metrics output example** ``` txt # Upstream Requests nginx_upstream_requests{code="1xx",upstream="XXX-XXXXX-3000"} 0 # Upstream Bytes nginx_upstream_bytes{direction="in",upstream="XXX-XXXXX-3000"} 0 # Upstream Response time nginx_upstream_responseMsec{backend="10.2.15.10:3000",upstream="XXX-XXXXX-3000"} 99 ``` prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/VERSION000066400000000000000000000000071331320432000235400ustar00rootroot000000000000000.10.3 prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/_config.yml000066400000000000000000000000321331320432000246150ustar00rootroot00000000000000theme: jekyll-theme-caymanprometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/dashboard/000077500000000000000000000000001331320432000244225ustar00rootroot00000000000000prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/dashboard/nginx-vts-exporter.json000066400000000000000000000450401331320432000311230ustar00rootroot00000000000000{ "__inputs": [ { "name": "DS_PROMETHEUS", "label": "prometheus", "description": "", "type": "datasource", "pluginId": "prometheus", "pluginName": "Prometheus" } ], "__requires": [ { "type": "panel", "id": "graph", "name": "Graph", "version": "" }, { "type": "grafana", "id": "grafana", "name": "Grafana", "version": "4.0.2" }, { "type": "datasource", "id": "prometheus", "name": "Prometheus", "version": "1.0.0" } ], "description": "Show stats from the hnlq715/nginx-vts-exporter.", "editable": true, "gnetId": 2949, "graphTooltip": 0, "hideControls": false, "id": null, "links": [], "rows": [ { "collapse": false, "height": "250px", "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "${DS_PROMETHEUS}", "fill": 1, "id": 1, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "expr": "nginx_server_connections{instance=~\"$Instance\", status=~\"active|writing|reading|waiting\"}", "format": "time_series", "intervalFactor": 2, "legendFormat": "{{status}}", "refId": "B" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Server Connections", "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "${DS_PROMETHEUS}", "fill": 1, "id": 4, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "expr": "sum(irate(nginx_server_cache{instance=~\"$Instance\", host=~\"^$Host$\"}[5m])) by (status)", "format": "time_series", "interval": "", "intervalFactor": 2, "legendFormat": "{{ status }}", "metric": "nginx_server_cache", "refId": "A", "step": 240 } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Server Cache", "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ] } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "Dashboard Row", "titleSize": "h6" }, { "collapse": false, "height": 250, "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "${DS_PROMETHEUS}", "fill": 1, "id": 3, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "expr": "sum(irate(nginx_server_requests{instance=~\"$Instance\", code!=\"total\"}[5m])) by (code)", "format": "time_series", "interval": "", "intervalFactor": 2, "legendFormat": "{{ code }}", "metric": "nginx_server_requests", "refId": "A", "step": 240 } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Server Requests", "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "${DS_PROMETHEUS}", "fill": 1, "id": 2, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "expr": "sum(irate(nginx_server_bytes{instance=~\"$Instance\", host=~\"^$Host$\"}[5m])) by (direction)", "format": "time_series", "intervalFactor": 2, "legendFormat": "{{ direction }}", "metric": "nginx_server_bytes", "refId": "A", "step": 240 } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Server Bytes", "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ] } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "Dashboard Row", "titleSize": "h6" }, { "collapse": false, "height": 250, "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "${DS_PROMETHEUS}", "description": "This one is providing aggregated error codes, but it's still possible to graph these per upstream.", "fill": 1, "id": 6, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "expr": "sum(irate(nginx_upstream_requests{instance=~\"$Instance\", upstream=~\"^$Upstream$\",code!=\"total\"}[5m])) by (code)", "format": "time_series", "interval": "", "intervalFactor": 2, "legendFormat": "{{ code }}", "metric": "nginx_upstream_requests", "refId": "A", "step": 240 } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Upstream Requests", "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ] }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "${DS_PROMETHEUS}", "fill": 1, "id": 5, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 6, "stack": false, "steppedLine": false, "targets": [ { "expr": "sum(irate(nginx_upstream_bytes{instance=~\"$Instance\", upstream=~\"^$Upstream$\"}[5m])) by (direction)", "format": "time_series", "interval": "", "intervalFactor": 2, "legendFormat": "{{ direction }}", "metric": "nginx_upstream_bytes", "refId": "A", "step": 240 } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Upstream Bytes", "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ] } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "Dashboard Row", "titleSize": "h6" }, { "collapse": false, "height": 250, "panels": [ { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "${DS_PROMETHEUS}", "fill": 1, "id": 7, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "span": 12, "stack": false, "steppedLine": false, "targets": [ { "expr": "sum(nginx_upstream_responseMsec{instance=~\"$Instance\", upstream=~\"^$Upstream$\"}) by (backend)", "format": "time_series", "interval": "", "intervalFactor": 2, "legendFormat": "{{ backend }}", "metric": "nginx_upstream_response", "refId": "A", "step": 120 } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Upstream Backend Response", "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ] } ], "repeat": null, "repeatIteration": null, "repeatRowId": null, "showTitle": false, "title": "Dashboard Row", "titleSize": "h6" } ], "schemaVersion": 14, "style": "dark", "tags": [ "prometheus", "nginx" ], "templating": { "list": [ { "allValue": null, "current": {}, "datasource": "${DS_PROMETHEUS}", "hide": 0, "includeAll": true, "label": null, "multi": false, "name": "Instance", "options": [], "query": "label_values(nginx_server_bytes, instance)", "refresh": 1, "regex": "", "sort": 0, "tagValuesQuery": "", "tags": [], "tagsQuery": "", "type": "query", "useTags": false }, { "allValue": null, "current": {}, "datasource": "${DS_PROMETHEUS}", "hide": 0, "includeAll": true, "label": null, "multi": false, "name": "Host", "options": [], "query": "label_values(nginx_server_bytes{instance=~\"$Instance\"}, host)", "refresh": 1, "regex": "", "sort": 0, "tagValuesQuery": "", "tags": [], "tagsQuery": "", "type": "query", "useTags": false }, { "allValue": ".*", "current": {}, "datasource": "${DS_PROMETHEUS}", "hide": 0, "includeAll": true, "label": null, "multi": false, "name": "Upstream", "options": [], "query": "label_values(nginx_upstream_bytes{instance=~\"$Instance\"}, upstream)", "refresh": 1, "regex": "", "sort": 0, "tagValuesQuery": "", "tags": [], "tagsQuery": "", "type": "query", "useTags": false } ] }, "time": { "from": "now-3h", "to": "now" }, "timepicker": { "refresh_intervals": [ "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d" ], "time_options": [ "5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d" ] }, "timezone": "browser", "title": "Nginx VTS Stats", "version": 9 } prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/docker-entrypoint.sh000077500000000000000000000013571331320432000265200ustar00rootroot00000000000000#!/bin/sh set -eo pipefail default_status="$NGINX_HOST/status/format/json" NGINX_STATUS=${NGINX_STATUS:-$default_status} METRICS_NS=${METRICS_NS:-$DEFAULT_METRICS_NS} # If there are any arguments then we want to run those instead #if [[ "$1" == "$binary" || -z $1 ]]; then # exec "$@" #else # echo "Running the default" #echo "[$0] - Nginx scrape host --> [$NGINX_STATUS]" #echo "[$0] - Metrics Address --> [$METRICS_ADDR]" #echo "[$0] - Metrics Endpoint --> [$METRICS_ENDPOINT]" #echo "[$0] - Metrics Namespace --> [$METRICS_NS]" #echo "[$0] - Running metrics nginx-vts-exporter" exec nginx-vts-exporter -nginx.scrape_uri=$NGINX_STATUS -telemetry.address $METRICS_ADDR -telemetry.endpoint $METRICS_ENDPOINT -metrics.namespace $METRICS_NS #fi prometheus-nginx-vts-exporter-0.10.3+git20180501.43b4556+ds/nginx_vts_exporter.go000066400000000000000000000450021331320432000267720ustar00rootroot00000000000000package main import ( "crypto/tls" "encoding/json" "flag" "fmt" "io" "io/ioutil" "log" "net/http" "os" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/version" ) type NginxVts struct { HostName string `json:"hostName"` NginxVersion string `json:"nginxVersion"` LoadMsec int64 `json:"loadMsec"` NowMsec int64 `json:"nowMsec"` Connections struct { Active uint64 `json:"active"` Reading uint64 `json:"reading"` Writing uint64 `json:"writing"` Waiting uint64 `json:"waiting"` Accepted uint64 `json:"accepted"` Handled uint64 `json:"handled"` Requests uint64 `json:"requests"` } `json:"connections"` ServerZones map[string]Server `json:"serverZones"` UpstreamZones map[string][]Upstream `json:"upstreamZones"` FilterZones map[string]map[string]Upstream `json:"filterZones"` CacheZones map[string]Cache `json:"cacheZones"` } type Server struct { RequestCounter uint64 `json:"requestCounter"` InBytes uint64 `json:"inBytes"` OutBytes uint64 `json:"outBytes"` RequestMsec uint64 `json:"requestMsec"` Responses struct { OneXx uint64 `json:"1xx"` TwoXx uint64 `json:"2xx"` ThreeXx uint64 `json:"3xx"` FourXx uint64 `json:"4xx"` FiveXx uint64 `json:"5xx"` Miss uint64 `json:"miss"` Bypass uint64 `json:"bypass"` Expired uint64 `json:"expired"` Stale uint64 `json:"stale"` Updating uint64 `json:"updating"` Revalidated uint64 `json:"revalidated"` Hit uint64 `json:"hit"` Scarce uint64 `json:"scarce"` } `json:"responses"` OverCounts struct { MaxIntegerSize float64 `json:"maxIntegerSize"` RequestCounter uint64 `json:"requestCounter"` InBytes uint64 `json:"inBytes"` OutBytes uint64 `json:"outBytes"` OneXx uint64 `json:"1xx"` TwoXx uint64 `json:"2xx"` ThreeXx uint64 `json:"3xx"` FourXx uint64 `json:"4xx"` FiveXx uint64 `json:"5xx"` Miss uint64 `json:"miss"` Bypass uint64 `json:"bypass"` Expired uint64 `json:"expired"` Stale uint64 `json:"stale"` Updating uint64 `json:"updating"` Revalidated uint64 `json:"revalidated"` Hit uint64 `json:"hit"` Scarce uint64 `json:"scarce"` } `json:"overCounts"` } type Upstream struct { Server string `json:"server"` RequestCounter uint64 `json:"requestCounter"` InBytes uint64 `json:"inBytes"` OutBytes uint64 `json:"outBytes"` Responses struct { OneXx uint64 `json:"1xx"` TwoXx uint64 `json:"2xx"` ThreeXx uint64 `json:"3xx"` FourXx uint64 `json:"4xx"` FiveXx uint64 `json:"5xx"` } `json:"responses"` ResponseMsec uint64 `json:"responseMsec"` RequestMsec uint64 `json:"requestMsec"` Weight uint64 `json:"weight"` MaxFails uint64 `json:"maxFails"` FailTimeout uint64 `json:"failTimeout"` Backup bool `json:"backup"` Down bool `json:"down"` OverCounts struct { MaxIntegerSize float64 `json:"maxIntegerSize"` RequestCounter uint64 `json:"requestCounter"` InBytes uint64 `json:"inBytes"` OutBytes uint64 `json:"outBytes"` OneXx uint64 `json:"1xx"` TwoXx uint64 `json:"2xx"` ThreeXx uint64 `json:"3xx"` FourXx uint64 `json:"4xx"` FiveXx uint64 `json:"5xx"` } `json:"overCounts"` } type Cache struct { MaxSize uint64 `json:"maxSize"` UsedSize uint64 `json:"usedSize"` InBytes uint64 `json:"inBytes"` OutBytes uint64 `json:"outBytes"` Responses struct { Miss uint64 `json:"miss"` Bypass uint64 `json:"bypass"` Expired uint64 `json:"expired"` Stale uint64 `json:"stale"` Updating uint64 `json:"updating"` Revalidated uint64 `json:"revalidated"` Hit uint64 `json:"hit"` Scarce uint64 `json:"scarce"` } `json:"responses"` OverCounts struct { MaxIntegerSize float64 `json:"maxIntegerSize"` InBytes uint64 `json:"inBytes"` OutBytes uint64 `json:"outBytes"` Miss uint64 `json:"miss"` Bypass uint64 `json:"bypass"` Expired uint64 `json:"expired"` Stale uint64 `json:"stale"` Updating uint64 `json:"updating"` Revalidated uint64 `json:"revalidated"` Hit uint64 `json:"hit"` Scarce uint64 `json:"scarce"` } `json:"overCounts"` } type Exporter struct { URI string infoMetric *prometheus.Desc serverMetrics, upstreamMetrics, filterMetrics, cacheMetrics map[string]*prometheus.Desc } func newServerMetric(metricName string, docString string, labels []string) *prometheus.Desc { return prometheus.NewDesc( prometheus.BuildFQName(*metricsNamespace, "server", metricName), docString, labels, nil, ) } func newUpstreamMetric(metricName string, docString string, labels []string) *prometheus.Desc { return prometheus.NewDesc( prometheus.BuildFQName(*metricsNamespace, "upstream", metricName), docString, labels, nil, ) } func newFilterMetric(metricName string, docString string, labels []string) *prometheus.Desc { return prometheus.NewDesc( prometheus.BuildFQName(*metricsNamespace, "filter", metricName), docString, labels, nil, ) } func newCacheMetric(metricName string, docString string, labels []string) *prometheus.Desc { return prometheus.NewDesc( prometheus.BuildFQName(*metricsNamespace, "cache", metricName), docString, labels, nil, ) } func NewExporter(uri string) *Exporter { return &Exporter{ URI: uri, infoMetric: newServerMetric("info", "nginx info", []string{"hostName", "nginxVersion"}), serverMetrics: map[string]*prometheus.Desc{ "connections": newServerMetric("connections", "nginx connections", []string{"status"}), "requests": newServerMetric("requests", "requests counter", []string{"host", "code"}), "bytes": newServerMetric("bytes", "request/response bytes", []string{"host", "direction"}), "cache": newServerMetric("cache", "cache counter", []string{"host", "status"}), "requestMsec": newServerMetric("requestMsec", "average of request processing times in milliseconds", []string{"host"}), }, upstreamMetrics: map[string]*prometheus.Desc{ "requests": newUpstreamMetric("requests", "requests counter", []string{"upstream", "code", "backend"}), "bytes": newUpstreamMetric("bytes", "request/response bytes", []string{"upstream", "direction", "backend"}), "responseMsec": newUpstreamMetric("responseMsec", "average of only upstream/backend response processing times in milliseconds", []string{"upstream", "backend"}), "requestMsec": newUpstreamMetric("requestMsec", "average of request processing times in milliseconds", []string{"upstream", "backend"}), }, filterMetrics: map[string]*prometheus.Desc{ "requests": newFilterMetric("requests", "requests counter", []string{"filter", "filterName", "code"}), "bytes": newFilterMetric("bytes", "request/response bytes", []string{"filter", "filterName", "direction"}), "responseMsec": newFilterMetric("responseMsec", "average of only upstream/backend response processing times in milliseconds", []string{"filter", "filterName"}), "requestMsec": newFilterMetric("requestMsec", "average of request processing times in milliseconds", []string{"filter", "filterName"}), }, cacheMetrics: map[string]*prometheus.Desc{ "requests": newCacheMetric("requests", "cache requests counter", []string{"zone", "status"}), "bytes": newCacheMetric("bytes", "cache request/response bytes", []string{"zone", "direction"}), }, } } func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { for _, m := range e.serverMetrics { ch <- m } for _, m := range e.upstreamMetrics { ch <- m } for _, m := range e.filterMetrics { ch <- m } for _, m := range e.cacheMetrics { ch <- m } } func (e *Exporter) Collect(ch chan<- prometheus.Metric) { body, err := fetchHTTP(e.URI, time.Duration(*nginxScrapeTimeout)*time.Second)() if err != nil { log.Println("fetchHTTP failed", err) return } defer body.Close() data, err := ioutil.ReadAll(body) if err != nil { log.Println("ioutil.ReadAll failed", err) return } var nginxVtx NginxVts err = json.Unmarshal(data, &nginxVtx) if err != nil { log.Println("json.Unmarshal failed", err) return } // info uptime := (nginxVtx.NowMsec - nginxVtx.LoadMsec) / 1000 ch <- prometheus.MustNewConstMetric(e.infoMetric, prometheus.GaugeValue, float64(uptime), nginxVtx.HostName, nginxVtx.NginxVersion) // connections ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Active), "active") ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Reading), "reading") ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Waiting), "waiting") ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Writing), "writing") ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Accepted), "accepted") ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Handled), "handled") ch <- prometheus.MustNewConstMetric(e.serverMetrics["connections"], prometheus.GaugeValue, float64(nginxVtx.Connections.Requests), "requests") // ServerZones for host, s := range nginxVtx.ServerZones { ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.RequestCounter), host, "total") ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.OneXx), host, "1xx") ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.TwoXx), host, "2xx") ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.ThreeXx), host, "3xx") ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.FourXx), host, "4xx") ch <- prometheus.MustNewConstMetric(e.serverMetrics["requests"], prometheus.CounterValue, float64(s.Responses.FiveXx), host, "5xx") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Bypass), host, "bypass") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Expired), host, "expired") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Hit), host, "hit") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Miss), host, "miss") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Revalidated), host, "revalidated") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Scarce), host, "scarce") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Stale), host, "stale") ch <- prometheus.MustNewConstMetric(e.serverMetrics["cache"], prometheus.CounterValue, float64(s.Responses.Updating), host, "updating") ch <- prometheus.MustNewConstMetric(e.serverMetrics["bytes"], prometheus.CounterValue, float64(s.InBytes), host, "in") ch <- prometheus.MustNewConstMetric(e.serverMetrics["bytes"], prometheus.CounterValue, float64(s.OutBytes), host, "out") ch <- prometheus.MustNewConstMetric(e.serverMetrics["requestMsec"], prometheus.GaugeValue, float64(s.RequestMsec), host) } // UpstreamZones for name, upstreamList := range nginxVtx.UpstreamZones { for _, s := range upstreamList { ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["responseMsec"], prometheus.GaugeValue, float64(s.ResponseMsec), name, s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requestMsec"], prometheus.GaugeValue, float64(s.RequestMsec), name, s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, float64(s.RequestCounter), name, "total", s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, float64(s.Responses.OneXx), name, "1xx", s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, float64(s.Responses.TwoXx), name, "2xx", s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, float64(s.Responses.ThreeXx), name, "3xx", s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, float64(s.Responses.FourXx), name, "4xx", s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["requests"], prometheus.CounterValue, float64(s.Responses.FiveXx), name, "5xx", s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["bytes"], prometheus.CounterValue, float64(s.InBytes), name, "in", s.Server) ch <- prometheus.MustNewConstMetric(e.upstreamMetrics["bytes"], prometheus.CounterValue, float64(s.OutBytes), name, "out", s.Server) } } // FilterZones for filter, values := range nginxVtx.FilterZones { for name, stat := range values { ch <- prometheus.MustNewConstMetric(e.filterMetrics["responseMsec"], prometheus.GaugeValue, float64(stat.ResponseMsec), filter, name) ch <- prometheus.MustNewConstMetric(e.filterMetrics["requestMsec"], prometheus.GaugeValue, float64(stat.RequestMsec), filter, name) ch <- prometheus.MustNewConstMetric(e.filterMetrics["requests"], prometheus.CounterValue, float64(stat.RequestCounter), filter, name, "total") ch <- prometheus.MustNewConstMetric(e.filterMetrics["requests"], prometheus.CounterValue, float64(stat.Responses.OneXx), filter, name, "1xx") ch <- prometheus.MustNewConstMetric(e.filterMetrics["requests"], prometheus.CounterValue, float64(stat.Responses.TwoXx), filter, name, "2xx") ch <- prometheus.MustNewConstMetric(e.filterMetrics["requests"], prometheus.CounterValue, float64(stat.Responses.ThreeXx), filter, name, "3xx") ch <- prometheus.MustNewConstMetric(e.filterMetrics["requests"], prometheus.CounterValue, float64(stat.Responses.FourXx), filter, name, "4xx") ch <- prometheus.MustNewConstMetric(e.filterMetrics["requests"], prometheus.CounterValue, float64(stat.Responses.FiveXx), filter, name, "5xx") ch <- prometheus.MustNewConstMetric(e.filterMetrics["bytes"], prometheus.CounterValue, float64(stat.InBytes), filter, name, "in") ch <- prometheus.MustNewConstMetric(e.filterMetrics["bytes"], prometheus.CounterValue, float64(stat.OutBytes), filter, name, "out") } } // CacheZones for zone, s := range nginxVtx.CacheZones { ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Bypass), zone, "bypass") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Expired), zone, "expired") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Hit), zone, "hit") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Miss), zone, "miss") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Revalidated), zone, "revalidated") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Scarce), zone, "scarce") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Stale), zone, "stale") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["requests"], prometheus.CounterValue, float64(s.Responses.Updating), zone, "updating") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["bytes"], prometheus.CounterValue, float64(s.InBytes), zone, "in") ch <- prometheus.MustNewConstMetric(e.cacheMetrics["bytes"], prometheus.CounterValue, float64(s.OutBytes), zone, "out") } } func fetchHTTP(uri string, timeout time.Duration) func() (io.ReadCloser, error) { http.DefaultClient.Timeout = timeout http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: *insecure} return func() (io.ReadCloser, error) { resp, err := http.DefaultClient.Get(uri) if err != nil { return nil, err } if !(resp.StatusCode >= 200 && resp.StatusCode < 300) { resp.Body.Close() return nil, fmt.Errorf("HTTP status %d", resp.StatusCode) } return resp.Body, nil } } var ( showVersion = flag.Bool("version", false, "Print version information.") listenAddress = flag.String("telemetry.address", ":9913", "Address on which to expose metrics.") metricsEndpoint = flag.String("telemetry.endpoint", "/metrics", "Path under which to expose metrics.") metricsNamespace = flag.String("metrics.namespace", "nginx", "Prometheus metrics namespace.") nginxScrapeURI = flag.String("nginx.scrape_uri", "http://localhost/status", "URI to nginx stub status page") insecure = flag.Bool("insecure", true, "Ignore server certificate if using https") nginxScrapeTimeout = flag.Int("nginx.scrape_timeout", 2, "The number of seconds to wait for an HTTP response from the nginx.scrape_uri") ) func init() { prometheus.MustRegister(version.NewCollector("nginx_vts_exporter")) } func main() { flag.Parse() if *showVersion { fmt.Fprintln(os.Stdout, version.Print("nginx_vts_exporter")) os.Exit(0) } log.Printf("Starting nginx_vts_exporter %s", version.Info()) log.Printf("Build context %s", version.BuildContext()) exporter := NewExporter(*nginxScrapeURI) prometheus.MustRegister(exporter) prometheus.Unregister(prometheus.NewProcessCollector(os.Getpid(), "")) prometheus.Unregister(prometheus.NewGoCollector()) http.Handle(*metricsEndpoint, promhttp.Handler()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(` Nginx Exporter

Nginx Exporter

Metrics

`)) }) log.Printf("Starting Server at : %s", *listenAddress) log.Printf("Metrics endpoint: %s", *metricsEndpoint) log.Printf("Metrics namespace: %s", *metricsNamespace) log.Printf("Scraping information from : %s", *nginxScrapeURI) log.Fatal(http.ListenAndServe(*listenAddress, nil)) }