Skip to content

Commit

Permalink
Added httpd status counters collection and reporting.
Browse files Browse the repository at this point in the history
  • Loading branch information
bolshoy committed May 14, 2015
1 parent 24c0a7f commit be2d522
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 9 deletions.
76 changes: 67 additions & 9 deletions agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package gorelic
import (
"errors"
"fmt"
metrics "github.com/yvasiyarov/go-metrics"
"github.com/yvasiyarov/newrelic_platform_go"
"log"
"net/http"

metrics "github.com/yvasiyarov/go-metrics"
"github.com/yvasiyarov/newrelic_platform_go"
)

const (
Expand Down Expand Up @@ -45,16 +46,18 @@ type Agent struct {
CollectGcStat bool
CollectMemoryStat bool
CollectHTTPStat bool
CollectHTTPStatuses bool
GCPollInterval int
MemoryAllocatorPollInterval int
AgentGUID string
AgentVersion string
plugin *newrelic_platform_go.NewrelicPlugin
HTTPTimer metrics.Timer
HTTPStatusCounters map[int]metrics.Counter
Tracer *Tracer
}

//NewAgent build new Agent objects.
// NewAgent builds new Agent objects.
func NewAgent() *Agent {
agent := &Agent{
NewrelicName: DefaultAgentName,
Expand All @@ -71,8 +74,23 @@ func NewAgent() *Agent {
return agent
}

// our custom component
type resettableComponent struct {
newrelic_platform_go.IComponent
counters map[int]metrics.Counter
}

// newrelic_platform_go.IComponent interface implementation
func (c resettableComponent) ClearSentData() {
c.IComponent.ClearSentData()
for _, counter := range c.counters {
counter.Clear()
}
}

//WrapHTTPHandlerFunc instrument HTTP handler functions to collect HTTP metrics
func (agent *Agent) WrapHTTPHandlerFunc(h tHTTPHandlerFunc) tHTTPHandlerFunc {
agent.CollectHTTPStat = true
agent.initTimer()
return func(w http.ResponseWriter, req *http.Request) {
proxy := newHTTPHandlerFunc(h)
Expand All @@ -83,6 +101,7 @@ func (agent *Agent) WrapHTTPHandlerFunc(h tHTTPHandlerFunc) tHTTPHandlerFunc {

//WrapHTTPHandler instrument HTTP handler object to collect HTTP metrics
func (agent *Agent) WrapHTTPHandler(h http.Handler) http.Handler {
agent.CollectHTTPStat = true
agent.initTimer()

proxy := newHTTPHandler(h)
Expand All @@ -96,18 +115,18 @@ func (agent *Agent) Run() error {
return errors.New("please, pass a valid newrelic license key")
}

agent.plugin = newrelic_platform_go.NewNewrelicPlugin(agent.AgentVersion, agent.NewrelicLicense, agent.NewrelicPollInterval)
component := newrelic_platform_go.NewPluginComponent(agent.NewrelicName, agent.AgentGUID)
agent.plugin.AddComponent(component)

// Init reporting component, add default metrics (runtime) and tracer.
var component newrelic_platform_go.IComponent
component = newrelic_platform_go.NewPluginComponent(agent.NewrelicName, agent.AgentGUID)
addRuntimeMericsToComponent(component)

agent.Tracer = newTracer(component)

// Check agent flags and add relevant metrics.
if agent.CollectGcStat {
addGCMericsToComponent(component, agent.GCPollInterval)
agent.debug(fmt.Sprintf("Init GC metrics collection. Poll interval %d seconds.", agent.GCPollInterval))
}

if agent.CollectMemoryStat {
addMemoryMericsToComponent(component, agent.MemoryAllocatorPollInterval)
agent.debug(fmt.Sprintf("Init memory allocator metrics collection. Poll interval %d seconds.", agent.MemoryAllocatorPollInterval))
Expand All @@ -119,7 +138,21 @@ func (agent *Agent) Run() error {
agent.debug(fmt.Sprintf("Init HTTP metrics collection."))
}

if agent.CollectHTTPStatuses {
agent.initStatusCounters()
component = &resettableComponent{component, agent.HTTPStatusCounters}
addHTTPStatusMetricsToComponent(component, agent.HTTPStatusCounters)
agent.debug(fmt.Sprintf("Init HTTP status metrics collection."))
}

// Init newrelic reporting plugin.
agent.plugin = newrelic_platform_go.NewNewrelicPlugin(agent.AgentVersion, agent.NewrelicLicense, agent.NewrelicPollInterval)
agent.plugin.Verbose = agent.Verbose

// Add our metrics component to the plugin.
agent.plugin.AddComponent(component)

// Start reporting!
go agent.plugin.Run()
return nil
}
Expand All @@ -129,8 +162,33 @@ func (agent *Agent) initTimer() {
if agent.HTTPTimer == nil {
agent.HTTPTimer = metrics.NewTimer()
}
}

//Initialize metrics.Counters objects, used to collect HTTP statuses
func (agent *Agent) initStatusCounters() {
httpStatuses := []int{
http.StatusContinue, http.StatusSwitchingProtocols,

http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNonAuthoritativeInfo,
http.StatusNoContent, http.StatusResetContent, http.StatusPartialContent,

http.StatusMultipleChoices, http.StatusMovedPermanently, http.StatusFound, http.StatusSeeOther,
http.StatusNotModified, http.StatusUseProxy, http.StatusTemporaryRedirect,

http.StatusBadRequest, http.StatusUnauthorized, http.StatusPaymentRequired, http.StatusForbidden,
http.StatusNotFound, http.StatusMethodNotAllowed, http.StatusNotAcceptable, http.StatusProxyAuthRequired,
http.StatusRequestTimeout, http.StatusConflict, http.StatusGone, http.StatusLengthRequired,
http.StatusPreconditionFailed, http.StatusRequestEntityTooLarge, http.StatusRequestURITooLong, http.StatusUnsupportedMediaType,
http.StatusRequestedRangeNotSatisfiable, http.StatusExpectationFailed, http.StatusTeapot,

http.StatusInternalServerError, http.StatusNotImplemented, http.StatusBadGateway,
http.StatusServiceUnavailable, http.StatusGatewayTimeout, http.StatusHTTPVersionNotSupported,
}

agent.CollectHTTPStat = true
agent.HTTPStatusCounters = make(map[int]metrics.Counter, len(httpStatuses))
for _, statusCode := range httpStatuses {
agent.HTTPStatusCounters[statusCode] = metrics.NewCounter()
}
}

//Print debug messages
Expand Down
33 changes: 33 additions & 0 deletions http_status_metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package gorelic

import (
"fmt"

"github.com/yvasiyarov/go-metrics"
"github.com/yvasiyarov/newrelic_platform_go"
)

// New metrica collector - counter per each http status code.
type counterByStatusMetrica struct {
counter metrics.Counter
name string
units string
}

// metrics.IMetrica interface implementation.
func (m *counterByStatusMetrica) GetName() string { return m.name }

func (m *counterByStatusMetrica) GetUnits() string { return m.units }

func (m *counterByStatusMetrica) GetValue() (float64, error) { return float64(m.counter.Count()), nil }

// addHTTPStatusMetricsToComponent initializes counter metrics for all http statuses and adds them to the component.
func addHTTPStatusMetricsToComponent(component newrelic_platform_go.IComponent, statusCounters map[int]metrics.Counter) {
for statusCode, counter := range statusCounters {
component.AddMetrica(&counterByStatusMetrica{
counter: counter,
name: fmt.Sprintf("http/status/%d", statusCode),
units: "count",
})
}
}

0 comments on commit be2d522

Please sign in to comment.