Skip to content

Commit

Permalink
Add metric for visitor country code
Browse files Browse the repository at this point in the history
  • Loading branch information
fiorix committed Nov 21, 2015
1 parent c50f9c4 commit 55971d8
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 22 deletions.
1 change: 1 addition & 0 deletions apiserver/cmd.go
Expand Up @@ -90,6 +90,7 @@ func Run() error {
Max: *flQuotaMax,
Interval: *flQuotaIntvl,
},
UseXForwardedFor: *flUseXFF,
})

if !*flSilent {
Expand Down
62 changes: 47 additions & 15 deletions apiserver/http.go
Expand Up @@ -15,11 +15,12 @@ import (

// HandlerConfig holds configuration for freegeoip http handlers.
type HandlerConfig struct {
Prefix string
Origin string
PublicDir string
DB *freegeoip.DB
RateLimiter RateLimiter
Prefix string
Origin string
PublicDir string
DB *freegeoip.DB
RateLimiter RateLimiter
UseXForwardedFor bool
}

// NewHandler creates a freegeoip http handler.
Expand All @@ -30,26 +31,21 @@ func NewHandler(conf *HandlerConfig) http.Handler {
ah.RegisterEncoder(mux, "csv", &freegeoip.CSVEncoder{UseCRLF: true})
ah.RegisterEncoder(mux, "xml", &freegeoip.XMLEncoder{Indent: true})
ah.RegisterEncoder(mux, "json", &freegeoip.JSONEncoder{})
return mux
return ah.metricsCollector(mux)
}

// ConnStateFunc is a function that can handle connection state.
type ConnStateFunc func(c net.Conn, s http.ConnState)

// ConnStateMetrics collect metrics per connection state, per protocol.
// e.g. new http, closed http.
func ConnStateMetrics(proto string) ConnStateFunc {
ipver := func(c net.Conn) string {
ip, _, _ := net.SplitHostPort(c.RemoteAddr().String())
if net.ParseIP(ip).To4() != nil {
return "4"
}
return "6"
}
return func(c net.Conn, s http.ConnState) {
switch s {
case http.StateNew:
clientIPProtoCounter.WithLabelValues(ipver(c)).Inc()
clientConnsGauge.WithLabelValues(proto).Inc()
case http.StateClosed:
clientConnsGauge.WithLabelValues(proto).Inc()
clientConnsGauge.WithLabelValues(proto).Dec()
}
}
}
Expand Down Expand Up @@ -88,3 +84,39 @@ func (ah *apiHandler) RegisterEncoder(mux *http.ServeMux, path string, enc freeg
f = prometheus.InstrumentHandler(path, f)
mux.Handle(ah.prefix(path), f)
}

func (ah *apiHandler) metricsCollector(handler http.Handler) http.Handler {
type query struct {
Country struct {
ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
}
f := func(w http.ResponseWriter, r *http.Request) {
handler.ServeHTTP(w, r)
// Collect metrics after serving the request.
var ip net.IP
if ah.conf.UseXForwardedFor {
ip = net.ParseIP(r.RemoteAddr)
} else {
addr, _, _ := net.SplitHostPort(r.RemoteAddr)
ip = net.ParseIP(addr)
}
if ip == nil {
// TODO: increment error count?
return
}
if ip.To4() != nil {
clientIPProtoCounter.WithLabelValues("4").Inc()
} else {
clientIPProtoCounter.WithLabelValues("6").Inc()
}
var q query
err := ah.conf.DB.Lookup(ip, &q)
if err != nil || q.Country.ISOCode == "" {
clientCountryCounter.WithLabelValues("unknown").Inc()
return
}
clientCountryCounter.WithLabelValues(q.Country.ISOCode).Inc()
}
return http.HandlerFunc(f)
}
2 changes: 1 addition & 1 deletion apiserver/http_test.go
Expand Up @@ -60,7 +60,7 @@ func TestHandler(t *testing.T) {
t.Fatal(err)
}
if m.Country != "Venezuela" && m.City != "Caracas" {
t.Fatal("Query data does not match: want Caracas,Venezuela, have %q,%q",
t.Fatalf("Query data does not match: want Caracas,Venezuela, have %q,%q",
m.City, m.Country)
}
}
21 changes: 15 additions & 6 deletions apiserver/metrics.go
Expand Up @@ -10,30 +10,39 @@ import "github.com/prometheus/client_golang/prometheus"

var dbEventCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "db_event_counter",
Help: "Counter per DB event",
Name: "freegeoip_db_events_total",
Help: "Database events",
},
[]string{"event"},
)

var clientCountryCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "freegeoip_client_country_code_total",
Help: "Country ISO code of clients",
},
[]string{"country_code"},
)

var clientIPProtoCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "client_ipproto_version",
Help: "IP version of clients",
Name: "freegeoip_client_ipproto_version_total",
Help: "IP version (4 or 6) of clients",
},
[]string{"ip"},
)

var clientConnsGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "client_connections",
Help: "Number of client connections per protocol",
Name: "freegeoip_client_connections",
Help: "Number of active client connections per protocol",
},
[]string{"proto"},
)

func init() {
prometheus.MustRegister(dbEventCounter)
prometheus.MustRegister(clientCountryCounter)
prometheus.MustRegister(clientConnsGauge)
prometheus.MustRegister(clientIPProtoCounter)
}

0 comments on commit 55971d8

Please sign in to comment.