Categorygithub.com/GoMetric/statsd-http-proxy
modulepackage
0.0.0-20240103094817-2dcd8acbe936
Repository: https://github.com/gometric/statsd-http-proxy.git
Documentation: pkg.go.dev

# README

Stand With Ukraine 🇺🇦

SWUbanner

StatsD HTTP Proxy

StatsD HTTP proxy with REST interface for using in browsers

Go Report Card Build Status Code Climate Coverage Status

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

Build from sources

git clone [email protected]:GoMetric/statsd-http-proxy.git
make build

Build docker image

Build your own docker image: https://github.com/GoMetric/statsd-http-proxy-docker

Official docker image

Use Docker image:

docker

Run by Docker with insecure connection:

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

Run by Docker with secure connection:

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

Requirements

Proxy client for browser

Basic implementation of proxy client may be found at https://github.com/GoMetric/statsd-http-proxy-client.

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):
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):
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:

statsd-http-proxy --version

Command line arguments:

ParameterDescriptionDefault value
verbosePrint debug info to stderrOptional. Default false
http-hostHost of HTTP serverOptional. Default 127.0.0.1. To accept connections on any interface, set to ""
http-portPort of HTTP serverOptional. Default 80
http-timeout-readThe maximum duration in seconds for reading the entire request, including the bodyOptional. Defaults to 1 second
http-timeout-writeThe maximum duration in seconds before timing out writes of the responsOptional. Defaults to 1 second
http-timeout-idleThe maximum amount of time in seconds to wait for the next request when keep-alives are enabledOptional. Defaults to 1 second
tls-certTLS certificate for the HTTPSOptional. Default "" to use HTTP. If both tls-cert and tls-key set, HTTPS is used
tls-keyTLS private key for the HTTPSOptional. Default "" to use HTTP. If both tls-cert and tls-key set, HTTPS is used
statsd-hostHost of StatsD instanceOptional. Default 127.0.0.1
statsd-portPort of StatsD instanceOptional. Default 8125
jwt-secretJWT token secretOptional. If not set, server accepts all connections
metric-prefixPrefix, added to any metric nameOptional. If not set, do not add prefix
versionPrint version of server and exitOptional

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

$.ajax({
    url: 'http://127.0.0.1:8080/count/some.key.name',
    method: 'POST',
    headers: {
        'X-JWT-Token': 'some-jwt-token'
    },
    data: {
        value: 100500
    }
});

Authentication

Authentication is optional. It based on passing JWT token to server, encrypted with secret, specified in jwt-secret command line argument. If secret not configured in jwt-secret, then requests to server accepted without authentication. Token sends to server in X-JWT-Token header or in token query parameter.

We recommend to use JWT tokens to prevent flood requests: you need to setup JWT token expiration time, and update JWT token in browser each time you get 403 in response.

Rest resources

See statsd ductmentation about supported types.

Heartbeat

GET /heartbeat

If server working, it responds with OK

Count

POST /count/{key}
X-JWT-Token: {tokenString}
value=1&sampleRate=1
ParameterDescriptionDefault value
valueValue. Negative to decreaseOptional. Default 1
sampleRateSample rate to skip metricsOptional. Default to 1: accept all

Gauge

Gauge is an arbitrary value. Only the last value during a flush interval is flushed to the backend. If the gauge is not updated at the next flush, it will send the previous value. Gauge also may be set relatively to previously stored value. Is shift not passed, then value used. If value not passed, used default value equals 1. To set a gauge to a negative number you need first set it to 0.

Absolute value:

POST /gauge/{key}
X-JWT-Token: {tokenString}
value=1

Shift of previous value:

POST /gauge/{key}
X-JWT-Token: {tokenString}
shift=-1
ParameterDescriptionDefault value
valueInteger valueOptional. Default 1
shiftSigned int, relative to previously stored valueOptional

Timing

POST /timing/{key}
X-JWT-Token: {tokenString}
time=1234567&sampleRate=1
ParameterDescriptionDefault value
timeTime in millisecondsRequired
sampleRateFloat sample rate to skip metrics from 0 to 1Optional. Default to 1: accept all

Set

POST /set/{key}
X-JWT-Token: {tokenString}
value=1
ParameterDescriptionDefault value
valueInteger valueOptional. Default 1

Response

Server sends 200 OK if send success, even StatsD server is down.

Other HTTP status codes:

CODEDescription
400 Bad RequestInvalid parameters specified
401 UnauthorizedToken not sent
403 ForbiddenToken invalid/expired
404 Not foundInvalid url requested
405 Wrong methodRequest method not allowed for resource

Testing

It is useful for testing to start netcat UDP server, listening for connections and watch incoming metrics. To start server run:

nc -kluv localhost 8125

To send comamnd to statsd, run:

echo "counters" | nc localhost 8125

Benchmark

Machine for benchmarking:

Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz Dual Core / 8 GB RAM

Os:

Linux hp 4.15.0-65-generic #74-Ubuntu SMP Tue Sep 17 17:06:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Sysctl:

sudo sysctl net.ipv4.ip_local_port_range="15000 61000"
sudo sysctl net.ipv4.tcp_fin_timeout=30

Benchmarked by siege v. 4.0.4

Proxy CLI arguments

Without JWT token:

$ GOMAXPROCS=1 ./bin/statsd-http-proxy --http-host=127.0.0.1 --http-port=8080 --statsd-host=127.0.0.1 --statsd-port=8125

With JWT token:

$ GOMAXPROCS=1 ./bin/statsd-http-proxy --http-host=127.0.0.1 --http-port=8080 --statsd-host=127.0.0.1 --statsd-port=8125 --jwt-secret=somesecret

Requests to proxy

Router: Gorilla MUX, Keep alive: disabled, JWT auth: disabled

siege -R <(echo connection = close) -c 255 -r 2000 "http://127.0.0.1:8080/count/a.b.c.d POST value=42"

Router: Gorilla MUX, Keep alive: enabled, JWT auth: disabled

$ siege -R <(echo connection = keep-alive) -c 255 -r 2000 "http://127.0.0.1:8080/count/a.b.c.d POST value=42"

Router: Gorilla MUX, Keep alive: disabled, JWT auth: enabled

$ siege -R <(echo connection = close) -c 255 -r 2000 -H 'X-JWT-Token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdGF0c2QtcmVzdC1zZXJ2ZXIiLCJpYXQiOjE1MDY5NzI1ODAsImV4cCI6MTg4NTY2Mzc4MCwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3Nva2lsL3N0YXRzZC1yZXN0LXNlcnZlciIsInN1YiI6InNva2lsIn0.sOb0ccRBnN1u9IP2jhJrcNod14G5t-jMHNb_fsWov5c' "http://127.0.0.1:8080/count/a.b.c.d POST value=42"

Router: Gorilla MUX, Keep alive: enabled, JWT auth: enabled

$ siege -R <(echo connection = keep-alive) -c 255 -r 2000 -H 'X-JWT-Token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdGF0c2QtcmVzdC1zZXJ2ZXIiLCJpYXQiOjE1MDY5NzI1ODAsImV4cCI6MTg4NTY2Mzc4MCwiYXVkIjoiaHR0cHM6Ly9naXRodWIuY29tL3Nva2lsL3N0YXRzZC1yZXN0LXNlcnZlciIsInN1YiI6InNva2lsIn0.sOb0ccRBnN1u9IP2jhJrcNod14G5t-jMHNb_fsWov5c' "http://127.0.0.1:8080/count/a.b.c.d POST value=42"

Results

Concurent 255 users made 2000 requests each. Total request count: 510000

RouterKeep aliveJWTElapsed timeTransaction rateConcurrency
GorillaMux 1.7.3disableddisabled94.73 secs5383.72 trans/sec244.02
GorillaMux 1.7.3enableddisabled55.70 secs9156.19 trans/sec252.27
GorillaMux 1.7.3disabledenabled117.80 secs4329.37 trans/sec245.98
GorillaMux 1.7.3enabledenabled77.97 secs6540.98 trans/sec253.70
HttpRouter 1.3.0disableddisabled92.93 secs5487.99 trans/sec244.09
HttpRouter 1.3.0enableddisabled54.87 secs9294.70 trans/sec252.65
HttpRouter 1.3.0disabledenabled115.35 secs4421.33 trans/sec245.48
HttpRouter 1.3.0enabledenabled75.14 secs6787.33 trans/sec253.25

Useful resources

# Packages

No description provided by the author

# Variables

BuildDate is a date of build Injected by compilation flag.
BuildNumber is a current commit hash Injected by compilation flag.
Version is a current git commit hash and tag Injected by compilation flag.