stats

package module
v0.0.0-...-965cb2d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2019 License: MIT Imports: 7 Imported by: 462

README

Go stats handler
================

.. image:: https://secure.travis-ci.org/thoas/stats.svg?branch=master
    :alt: Build Status
    :target: http://travis-ci.org/thoas/stats

stats is a ``net/http`` handler in golang reporting various metrics about
your web application.

This middleware has been developed and required for the need of picfit_,
an image resizing server written in Go.

Compatibility
-------------

This handler supports the following frameworks at the moment:

* `negroni`_
* `martini`_
* `gocraft/web <https://github.com/gocraft/web>`_
* `Gin <https://github.com/gin-gonic/gin>`_
* `Goji <https://github.com/zenazn/goji>`_
* `Beego <https://github.com/astaxie/beego>`_
* `HTTPRouter <https://github.com/julienschmidt/httprouter>`_

We don't support your favorite Go framework? Send me a PR or
create a new `issue <https://github.com/thoas/stats/issues>`_ and
I will implement it :)

Installation
------------

1. Make sure you have a Go language compiler >= 1.3 (required) and git installed.
2. Make sure you have the following go system dependencies in your $PATH: bzr, svn, hg, git
3. Ensure your GOPATH_ is properly set.
4. Download it:

::

    go get github.com/thoas/stats


Usage
-----

Basic net/http
..............

To use this handler directly with ``net/http``, you need to call the
middleware with the handler itself:

.. code-block:: go

    package main

    import (
        "net/http"
        "github.com/thoas/stats"
    )

    func main() {
        h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            w.Write([]byte("{\"hello\": \"world\"}"))
        })

        handler := stats.New().Handler(h)
        http.ListenAndServe(":8080", handler)
    }

Negroni
.......

If you are using negroni_ you can implement the handler as
a simple middleware in ``server.go``:

.. code-block:: go

    package main

    import (
        "net/http"
        "github.com/codegangsta/negroni"
        "github.com/thoas/stats"
        "encoding/json"
    )

    func main() {
        middleware := stats.New()

        mux := http.NewServeMux()

        mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            w.Write([]byte("{\"hello\": \"world\"}"))
        })

        mux.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")

            stats := middleware.Data()

            b, _ := json.Marshal(stats)

            w.Write(b)
        })

        n := negroni.Classic()
        n.Use(middleware)
        n.UseHandler(mux)
        n.Run(":3000")
    }

HTTPRouter
.......

If you are using HTTPRouter_ you need to call the middleware with the handler itself:

.. code-block:: go
    
    package main                                                                          

    import (
            "encoding/json"
            "github.com/julienschmidt/httprouter"
            "github.com/thoas/stats"
            "net/http"
    )
    
    func main() {
            router := httprouter.New()
            s := stats.New()
            router.GET("/stats", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
                    w.Header().Set("Content-Type", "application/json; charset=utf-8")
                    s, err := json.Marshal(s.Data())
                    if err != nil {
                            http.Error(w, err.Error(), http.StatusInternalServerError)
                    }
                    w.Write(s)
            })
            http.ListenAndServe(":8080", s.Handler(router))
    }
    
    
Martini
.......

If you are using martini_, you can implement the handler as a wrapper of
a ``Martini.Context`` in ``server.go``:


.. code-block:: go

    package main

    import (
        "encoding/json"
        "github.com/go-martini/martini"
        "github.com/thoas/stats"
        "net/http"
    )

    func main() {
        middleware := stats.New()

        m := martini.Classic()
        m.Get("/", func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            w.Write([]byte("{\"hello\": \"world\"}"))
        })
        m.Get("/stats", func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")

            stats := middleware.Data()

            b, _ := json.Marshal(stats)

            w.Write(b)
        })

        m.Use(func(c martini.Context, w http.ResponseWriter, r *http.Request) {
            beginning, recorder := middleware.Begin(w)

            c.Next()

            middleware.End(beginning, stats.WithRecorder(recorder))
        })
        m.Run()
    }

Run it in a shell:

::

    $ go run server.go

Then in another shell run:

::

    $ curl http://localhost:3000/stats | python -m "json.tool"

Expect the following result:

.. code-block:: json

    {
        "total_response_time": "1.907382ms",
        "average_response_time": "86.699\u00b5s",
        "average_response_time_sec": 8.6699e-05,
        "count": 1,
        "pid": 99894,
        "status_code_count": {
            "200": 1
        },
        "time": "2015-03-06 17:23:27.000677896 +0100 CET",
        "total_count": 22,
        "total_response_time_sec": 0.0019073820000000002,
        "total_status_code_count": {
            "200": 22
        },
        "unixtime": 1425659007,
        "uptime": "4m14.502271612s",
        "uptime_sec": 254.502271612
    }

See `examples <https://github.com/thoas/stats/blob/master/examples>`_ to
test them.


Inspiration
-----------

`Antoine Imbert <https://github.com/ant0ine>`_ is the original author
of this middleware.

Originally developed for `go-json-rest <https://github.com/ant0ine/go-json-rest>`_,
it had been ported as a simple Golang handler by `Florent Messa <https://github.com/thoas>`_
to be used in various frameworks.

This middleware implements a ticker which is launched every seconds to
reset requests/sec and will implement new features in a near future :)

.. _GOPATH: http://golang.org/doc/code.html#GOPATH
.. _StatusMiddleware: https://github.com/ant0ine/go-json-rest/blob/master/rest/status.go
.. _go-json-rest: https://github.com/ant0ine/go-json-rest
.. _negroni: https://github.com/codegangsta/negroni
.. _martini: https://github.com/go-martini/martini
.. _picfit: https://github.com/thoas/picfit
.. _HTTPRouter: https://github.com/julienschmidt/httprouter

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Data

type Data struct {
	Pid                    int                `json:"pid"`
	Hostname               string             `json:"hostname"`
	UpTime                 string             `json:"uptime"`
	UpTimeSec              float64            `json:"uptime_sec"`
	Time                   string             `json:"time"`
	TimeUnix               int64              `json:"unixtime"`
	StatusCodeCount        map[string]int     `json:"status_code_count"`
	TotalStatusCodeCount   map[string]int     `json:"total_status_code_count"`
	Count                  int                `json:"count"`
	TotalCount             int                `json:"total_count"`
	TotalResponseTime      string             `json:"total_response_time"`
	TotalResponseTimeSec   float64            `json:"total_response_time_sec"`
	TotalResponseSize      int64              `json:"total_response_size"`
	AverageResponseSize    int64              `json:"average_response_size"`
	AverageResponseTime    string             `json:"average_response_time"`
	AverageResponseTimeSec float64            `json:"average_response_time_sec"`
	TotalMetricsCounts     map[string]int     `json:"total_metrics_counts"`
	AverageMetricsTimers   map[string]float64 `json:"average_metrics_timers"`
}

Data serializable structure

type Label

type Label struct {
	Name  string
	Value string
}

Label data structure

type Option

type Option func(*Options)

Option represents a stats option.

func WithRecorder

func WithRecorder(recorder ResponseWriter) Option

WithRecorder sets the recorder to use in stats.

func WithSize

func WithSize(size int) Option

WithSize sets the size to use in stats.

func WithStatusCode

func WithStatusCode(statusCode int) Option

WithStatusCode sets the status code to use in stats.

type Options

type Options struct {
	// contains filtered or unexported fields
}

Options are stats options.

func (Options) Size

func (o Options) Size() int

Size returns the response size.

func (Options) StatusCode

func (o Options) StatusCode() int

StatusCode returns the response status code.

type ResponseWriter

type ResponseWriter interface {
	http.ResponseWriter
	http.Flusher
	// Status returns the status code of the response or 0 if the response has not been written.
	Status() int
	// Written returns whether or not the ResponseWriter has been written.
	Written() bool
	// Size returns the size of the response body.
	Size() int
	// Before allows for a function to be called before the ResponseWriter has been written to. This is
	// useful for setting headers or any other operations that must happen before a response has been written.
	Before(func(ResponseWriter))
}

func NewRecorderResponseWriter

func NewRecorderResponseWriter(w http.ResponseWriter, statusCode int) ResponseWriter

type Stats

type Stats struct {
	Hostname            string
	Uptime              time.Time
	Pid                 int
	ResponseCounts      map[string]int
	TotalResponseCounts map[string]int
	TotalResponseTime   time.Time
	TotalResponseSize   int64
	MetricsCounts       map[string]int
	MetricsTimers       map[string]time.Time
	// contains filtered or unexported fields
}

Stats data structure

func New

func New() *Stats

New constructs a new Stats structure

func (*Stats) Begin

func (mw *Stats) Begin(w http.ResponseWriter) (time.Time, ResponseWriter)

Begin starts a recorder

func (*Stats) Close

func (mw *Stats) Close()

func (*Stats) Data

func (mw *Stats) Data() *Data

Data returns the data serializable structure

func (*Stats) End

func (mw *Stats) End(start time.Time, opts ...Option)

End closes the recorder with a specific status

func (*Stats) Handler

func (mw *Stats) Handler(h http.Handler) http.Handler

Handler is a MiddlewareFunc makes Stats implement the Middleware interface.

func (*Stats) MeasureSince

func (mw *Stats) MeasureSince(key string, start time.Time)

MeasureSince method for execution time recording

func (*Stats) MeasureSinceWithLabels

func (mw *Stats) MeasureSinceWithLabels(key string, start time.Time, labels []Label)

MeasureSinceWithLabels method for execution time recording with custom labels

func (*Stats) ResetResponseCounts

func (mw *Stats) ResetResponseCounts()

ResetResponseCounts reset the response counts

func (*Stats) ServeHTTP

func (mw *Stats) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)

ServeHTTP: Negroni compatible interface

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL