Browse Source

initial prototype

pull/1/head
Brett Langdon 9 years ago
parent
commit
13da6ff8dc
3 changed files with 186 additions and 1 deletions
  1. +25
    -1
      README.md
  2. +50
    -0
      handler.go
  3. +111
    -0
      setup.go

+ 25
- 1
README.md View File

@ -1,2 +1,26 @@
caddy-dogstatsd
caddy dogstatsd
=============== ===============
A [Caddy](https://caddyserver.com/) plugin for reporting metrics to [Datadog](https://datadoghq.com).
## Installation
## Configuration
```
dogstatsd [{host:port} [samplerate]]
```
```
dogstatsd {
host {host:port}
samplerate {samplerate}
namespace {namespace}
tags {name:value} [{name:value}...]
}
```
## Metrics
caddy.response.count - counter - number of requests handled
caddy.response.time - histogram - milliseconds spent handling request

+ 50
- 0
handler.go View File

@ -0,0 +1,50 @@
package caddydogstatsd
import (
"fmt"
"net/http"
"time"
"github.com/datadog/datadog-go/statsd"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
// DogstatsdHandler is a middleware handler for reporting dogstatsd metrics on requests
type DogstatsdHandler struct {
Client *statsd.Client
SampleRate float64
Next httpserver.Handler
}
// ServeHTTP is the middleware handler which will emit dogstatsd metrics after handling a request
func (h DogstatsdHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
// If we do not have a statsd.Client configured, then skip any processing
if h.Client == nil {
return h.Next.ServeHTTP(w, r)
}
// Grab the request start time
var start time.Time
start = time.Now()
// Handle the request
var code int
var err error
code, err = h.Next.ServeHTTP(w, r)
// Grab the request durection in Milliseconds
var elapsed time.Duration
var elapsedMS float64
elapsed = time.Since(start)
elapsedMS = float64(elapsed.Nanoseconds()) / float64(time.Millisecond)
// Report our request metrics to dogstatsd
var client statsd.Client
client = *h.Client
var extraTags = []string{
fmt.Sprintf("status_code:%d", code),
}
client.Count("caddy.response.count", 1, extraTags, h.SampleRate)
client.TimeInMilliseconds("caddy.response.time", elapsedMS, extraTags, h.SampleRate)
return code, err
}

+ 111
- 0
setup.go View File

@ -0,0 +1,111 @@
package caddydogstatsd
import (
"fmt"
"strconv"
"strings"
"github.com/datadog/datadog-go/statsd"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
func init() {
// register our plugin with Caddy
caddy.RegisterPlugin("dogstatsd", caddy.Plugin{
ServerType: "http",
Action: setup,
})
}
func setup(c *caddy.Controller) error {
for c.Next() {
// only parse if the initial directive is "dogstatsd"
if c.Val() != "dogstatsd" {
continue
}
// default config values
var namespace = ""
var host = "127.0.0.1:8125"
var globalTags = []string{}
var sampleRate = 1.0
// if we have a block, then parse that
// e.g.
// dogstatsd {
// host 127.0.0.1:8125
// }
for c.NextBlock() {
// each line if of the format `{key} {arg} [{arg}...]`
var key string
key = c.Val()
var args []string
args = c.RemainingArgs()
// we expect every directive to have at least 1 argument
if len(args) == 0 {
return c.ArgErr()
}
// parse directives
switch key {
case "host":
host = args[0]
case "samplerate":
var err error
sampleRate, err = strconv.ParseFloat(args[0], 64)
if err != nil {
return c.SyntaxErr(fmt.Sprintf("expected float for \"samplerate\", instead found \"%s\"", args[0]))
}
case "namespace":
namespace = args[0]
if !strings.HasSuffix(namespace, ".") {
namespace += "."
}
case "tags":
globalTags = args
default:
return c.SyntaxErr(fmt.Sprintf("expected one of \"host\", \"samplerate\", \"namespace\", \"tags\", instead found \"%s\"", key))
}
}
// handle non-block configuration
// e.g.
// dogstatsd [{host:port} [{samplerate}]]
if c.NextArg() {
var args []string
args = c.RemainingArgs()
if len(args) > 0 {
host = args[0]
}
if len(args) > 1 {
var err error
sampleRate, err = strconv.ParseFloat(args[1], 64)
if err != nil {
return c.SyntaxErr(fmt.Sprintf("expected float for \"samplerate\", instead found \"%s\"", args[1]))
}
}
}
// add our middleware
var cfg *httpserver.SiteConfig
cfg = httpserver.GetConfig(c)
cfg.AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
var client *statsd.Client
var err error
client, err = statsd.New(host)
if err == nil {
client.Namespace = namespace
client.Tags = globalTags
}
return DogstatsdHandler{
Client: client,
SampleRate: sampleRate,
Next: next,
}
})
}
return nil
}

Loading…
Cancel
Save