Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:

test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
- name: run tests
run: make test

build:
name: Build Package
runs-on: ubuntu-latest
needs:
- test
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Build
run: make build
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,4 @@ src
# keys
*.pem

# module files
vendor
.cache/
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 1.1
* pull vendoring into local repo
* build against Go 1.17
* better linting/testing in build
* pull in gometric statsd client
* make JSON input values consistent (no `n` vs. `value` vs. `dur`) so clients can more easily send data

## 1.0-stable
* use `alexcesaro/statsd`
* adapt the stats interface
Expand Down
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM debian:stable-slim

COPY statsd-http-proxy /usr/local/bin/
RUN apt-get update -qq \
&& apt-get install -y -qq --no-install-recommends curl \
&& apt-get clean \
&& apt-get autoremove -y \
&& chmod +x /usr/local/bin/statsd-http-proxy

# start service
EXPOSE 80
ENTRYPOINT ["/usr/local/bin/statsd-http-proxy", "--http-host="]
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ MIT License

Copyright (c) 2017 Dmytro Sokil
Copyright (c) 2020 InjectiveLabs
Copyright (c) 2022 John Seekins

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
58 changes: 55 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,56 @@
all:
.PHONY: help all test fmt lint vendor-update build clean

install:
go install github.com/InjectiveLabs/statsd-http-proxy
GH_ADDR := $(shell grep -A1 '\[remote "origin"\]' .git/config | grep url | cut -d"=" -f2- | grep -o "github.com[/:].*/" | tr -d "/" | sed 's|:|/|g')
DOCKER_USER := $(shell grep -A1 '\[remote "origin"\]' .git/config | grep url | cut -d"=" -f2- | grep -o "github.com[/:].*/" | tr -d "/" | sed 's|:|/|g' | cut -d"/" -f2)
NAME := statsd-http-proxy
GO_VER := 1.17.9
CURRENT_UID := $(shell id -u)
CURRENT_GID := $(shell id -g)
BUILDTIME ?= $(shell date)
BUILDUSER ?= $(shell id -u -n)
PKG_TAG ?= $(shell git tag -l --points-at HEAD)
ifeq ($(PKG_TAG),)
PKG_TAG := $(shell echo $$(git describe --long --all | tr '/' '-')$$(git diff-index --quiet HEAD -- || echo '-dirty-'$$(git diff-index -u HEAD | openssl sha1 | cut -c 10-17)))
endif

all: setup test build ## format, lint, and build the package

help:
@echo "Makefile targets:"
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' Makefile \
| sed -n 's/^\(.*\): \(.*\)##\(.*\)/ \1 :: \3/p' \
| column -t -c 1 -s '::'

setup: envsetup
docker pull golang:$(GO_VER)
docker pull golangci/golangci-lint:latest

envsetup:
mkdir -p $(CURDIR)/.cache/

test: envsetup fmt lint ## run tests
docker run --rm --user $(CURRENT_UID):$(CURRENT_GID) -v $(CURDIR)/.cache/:/.cache/ -v $(CURDIR):/app:z -w /app golang:$(GO_VER) go test -mod=vendor ./...

fmt: envsetup ## only run gofmt
docker run --rm --user $(CURRENT_UID):$(CURRENT_GID) -v $(CURDIR)/.cache/:/.cache/ -v $(CURDIR):/app:z -w /app golang:$(GO_VER) gofmt -l -w -s *.go

lint: envsetup ## run all linting steps
docker run --rm --user $(CURRENT_UID):$(CURRENT_GID) -v $(CURDIR)/.cache/:/.cache/ -v $(CURDIR):/app:z -w /app golangci/golangci-lint:latest golangci-lint run

vendor-update: envsetup ## update vendor dependencies
rm -rf go.mod go.sum vendor/
docker run --rm --user $(CURRENT_UID):$(CURRENT_GID) -v $(CURDIR)/.cache/:/.cache/ -v $(CURDIR):/app:z -w /app golang:$(GO_VER) go mod init $(GH_ADDR)/$(NAME)
docker run --rm --user $(CURRENT_UID):$(CURRENT_GID) -v $(CURDIR)/.cache/:/.cache/ -v $(CURDIR):/app:z -w /app golang:$(GO_VER) go mod tidy -compat=1.17
docker run --rm --user $(CURRENT_UID):$(CURRENT_GID) -v $(CURDIR)/.cache/:/.cache/ -v $(CURDIR):/app:z -w /app golang:$(GO_VER) go mod vendor

build: envsetup ## actually build package
docker run --rm -v $(CURDIR)/.cache/:/.cache/ --user $(CURRENT_UID):$(CURRENT_GID) -v $(CURDIR):/app:z -w /app golang:$(GO_VER) go build -tags static,netgo -mod=vendor -ldflags="-X 'main.Version=$(PKG_TAG)' -X 'main.BuildUser=$(BUILDUSER)' -X 'main.BuildTime=$(BUILDTIME)'" -o $(NAME) .

docker:
docker build . --tag $(DOCKER_USER)/$(NAME):$(PKG_TAG)
docker tag $(DOCKER_USER)/$(NAME):$(PKG_TAG) $(DOCKER_USER)/$(NAME):latest
docker push $(DOCKER_USER)/$(NAME):$(PKG_TAG)
docker push $(DOCKER_USER)/$(NAME):latest

clean: ## remove build artifacts
rm -f $(NAME)
129 changes: 119 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,119 @@
# StatsD HTTP Proxy
# StatsD Rest Proxy

StatsD HTTP proxy with REST interface for using in browsers.
StatsD uses UDP connections, and can not be used directly from browser. This server is a HTTP proxy to StatsD, useful for sending metrics to StatsD from frontend by AJAX.

Requests may be optionally authenticated using JWT tokens.

## Table of contents

* [Installation](#installation)
* [Nginx config](#nginx-config)
* [Usage](#usage)
* [Client Interactions](#client-interactions)

## Installation

```
# clone repo
make
```

Also available [Docker image](https://hub.docker.com/r/johnseekins/statsd-http-proxy/):

[![docker](https://img.shields.io/docker/pulls/johnseekins/statsd-http-proxy.svg?style=flat)](https://hub.docker.com/r/johnseekins/statsd-http-proxy/)

```
docker run -p 80:80 johnseekins/statsd-http-proxy:latest --verbose
```

Secure connection:

```
docker run -p 4433:4433 -v "$(pwd)":/certs/ johnseekins/statsd-http-proxy:latest --verbose --http-port=4433 --tls-cert=/certs/cert.pem --tls-key=/certs/key.pem
```

## Nginx config

Configuration of Nginx balancer:

```
server {
listen 443 http2;
server_name statsd-proxy.example.com;
ssl on;
ssl_certificate /etc/pki/nginx/ssl.crt;
ssl_certificate_key /etc/pki/nginx/ssl.key;
upstream statsd_proxy {
keepalive 100;
server statsd-proxy-1:8825 max_fails=0;
server statsd-proxy-2:8825 max_fails=0;
}

location / {
proxy_pass http://statsd_proxy;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
}
}
```


## Usage

* Run server (HTTP):

```bash
statsd-http-proxy \
--verbose \
--http-host=127.0.0.1 \
--http-port=8080 \
--statsd-host=127.0.0.1 \
--statsd-port=8125 \
--jwt-secret=somesecret \
--metric-prefix=prefix.subprefix
```

* Run server (HTTPS):

```bash
statsd-http-proxy \
--verbose \
--http-host=127.0.0.1 \
--http-port=433 \
--tls-cert=cert.pem \
--tls-key=key.pem \
--statsd-host=127.0.0.1 \
--statsd-port=8125 \
--jwt-secret=somesecret \
--metric-prefix=prefix.subprefix
```

Print server version and exit:

```bash
statsd-http-proxy --version
```

Command line arguments:

| Parameter | Description | Default value |
|-----------------|--------------------------------------|-----------------------------------------------------------------------------------|
| verbose | Print debug info to stderr | Optional. Default false |
| http-host | Host of HTTP server | Optional. Default 127.0.0.1. To accept connections on any interface, set to "" |
| http-port | Port of HTTP server | Optional. Default 80 |
| http-timeout-read | The maximum duration in seconds for reading the entire request, including the body | Optional. Defaults to 1 second |
| http-timeout-write | The maximum duration in seconds before timing out writes of the respons | Optional. Defaults to 1 second |
| http-timeout-idle | The maximum amount of time in seconds to wait for the next request when keep-alives are enabled | Optional. Defaults to 1 second |
| tls-cert | TLS certificate for the HTTPS | Optional. Default "" to use HTTP. If both tls-cert and tls-key set, HTTPS is used |
| tls-key | TLS private key for the HTTPS | Optional. Default "" to use HTTP. If both tls-cert and tls-key set, HTTPS is used |
| statsd-host | Host of StatsD instance | Optional. Default 127.0.0.1 |
| statsd-port | Port of StatsD instance | Optional. Default 8125 |
| jwt-secret | JWT token secret | Optional. If not set, server accepts all connections |
| metric-prefix | Prefix, added to any metric name | Optional. If not set, do not add prefix |
| version | Print version of server and exit | Optional |

## Client Interactions

Sample code to send metric in browser with JWT token in header:

Expand All @@ -11,6 +123,7 @@ $.ajax({
method: 'POST',
headers: {
'X-JWT-Token': 'some-jwt-token'
'Content-Type': 'application/json'
},
data: {
value: 100500
Expand All @@ -32,20 +145,16 @@ data: {

### `count`

Adds count to the bucket. Expected `n` as integer. By default `n` is 0.

### `incr`

Increments the given bucket. It is equivalent to count with `n` default to 1.
Adds count to the bucket. Expected `value` as integer. By default `value` is 0.

### `gauge`

Sets the gauge metric. Expected `value` as integer. Before setting negative gauge, it needs to be set to `0`.

### `timing`

Adds timing to the bucket. Expected `dur` as milliseconds integer. Default is `0`.
Adds timing to the bucket. Expected `value` as milliseconds integer. Default is `0`.

### `uniq`
### `set`

Adds unique value in a set bucket. Expected `value` as string. Sets are a relatively new concept in recent versions of StatsD. Sets track the number of unique elements belonging to a group. At each flush interval, the statsd backend will push the number of unique elements in the set as a single gauge value.
Adds value in a set bucket. Expected `value` as string. Sets are a relatively new concept in recent versions of StatsD. Sets track the number of unique elements belonging to a group. At each flush interval, the statsd backend will push the number of unique elements in the set as a single gauge value.
16 changes: 12 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
module github.com/InjectiveLabs/statsd-http-proxy
module github.com/johnseekins/statsd-http-proxy

go 1.14
go 1.17

require (
github.com/alexcesaro/statsd v2.0.0+incompatible
github.com/GoMetric/go-statsd-client v1.1.2
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/julienschmidt/httprouter v1.3.0
github.com/stretchr/testify v1.4.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
12 changes: 0 additions & 12 deletions go.sum

This file was deleted.

Loading