An open API service indexing awesome lists of open source software.

https://github.com/xyproto/sheepcounter

:sheep: ResponseWriter that can count bytes written to the client
https://github.com/xyproto/sheepcounter

byte-counting go http-server logging middleware

Last synced: 8 months ago
JSON representation

:sheep: ResponseWriter that can count bytes written to the client

Awesome Lists containing this project

README

          

# SheepCounter [![GoDoc](https://godoc.org/github.com/xyproto/sheepcounter?status.svg)](http://godoc.org/github.com/xyproto/sheepcounter) [![Report Card](https://img.shields.io/badge/go_report-A+-brightgreen.svg?style=flat)](http://goreportcard.com/report/xyproto/sheepcounter)

A `http.ResponseWriter` that can count the bytes written to the client so far.

# Why?

If you want to create an access log of how many bytes are sent to which clients, one method would be to write data to a buffer, count the bytes and then send the data to the client. This may be problematic for large files, since it eats up a lot of memory. It is also costly performance wise, since the data would then have to be counted while or after the data is sent to the client.

A better way is to store use the number returned by the `Write` function directly. This is not straightforward with `http.ResponseWriter` without wrapping it somehow, which is what this module does. A lightweight struct wraps both a `http.ResponseWriter` and an `uint64`, for keeping track of the written bytes.

# Examples

## Count the bytes sent, per response

~~~go
package main

import (
"fmt"
"github.com/xyproto/sheepcounter"
"log"
"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
sc := sheepcounter.New(w)
fmt.Fprintf(sc, "Hi %s!", r.URL.Path[1:])
fmt.Println("COUNTED:", sc.Counter()) // Counts the bytes sent, for this response only
}

func main() {
http.HandleFunc("/", handler)
fmt.Println("Serving on port 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
~~~

## Count the total amount of bytes sent

~~~go
package main

import (
"fmt"
"log"
"net/http"
"os"
"sync/atomic"

"github.com/xyproto/sheepcounter"
)

const (
title = "SheepCounter"
style = `body { margin: 4em; background: wheat; color: black; font-family: terminus, "courier new", courier; font-size: 1.1em; } a:link { color: #403020; } a:visited { color: #403020; } a:hover { color: #605040; } a:active { color: #605040; } #counter { color: red; }`
page = "%s%s%s"
)

var totalBytesWritten uint64

func helloHandler(w http.ResponseWriter, r *http.Request) {
sc := sheepcounter.New(w)
body := `

Here are the counted bytes.

`
fmt.Fprintf(sc, page, style, title, body)
written, err := sc.UCounter2()
if err != nil {
// Log an error and return
log.Printf("error: %s\n", err)
return
}
atomic.AddUint64(&totalBytesWritten, written)
log.Printf("counted %d bytes\n", written)
}

func counterHandler(w http.ResponseWriter, r *http.Request) {
sc := sheepcounter.New(w)
body := fmt.Sprintf(`

Total bytes sent from the server (without counting this response): %d

Back

`, atomic.LoadUint64(&totalBytesWritten))
fmt.Fprintf(sc, page, style, title, body)
written, err := sc.UCounter2()
if err != nil {
// Log an error and return
log.Printf("error: %s\n", err)
return
}
atomic.AddUint64(&totalBytesWritten, written)
log.Printf("counted %d bytes\n", written)
}

func main() {
http.HandleFunc("/", helloHandler)
http.HandleFunc("/counter", counterHandler)

httpAddr := os.Getenv("HTTP_ADDR")
if httpAddr == "" {
httpAddr = ":4000"
}

log.Println("Serving on " + httpAddr)
log.Fatal(http.ListenAndServe(httpAddr, nil))
}
~~~

# Requirements

* Go 1.18 or later

# General information

* Version: 1.6.2
* Alexander F. Rødseth <xyproto@archlinux.org>
* License: BSD-3