I am newbie to GoLang and want to define a global counter in go-lang to record how many queries are made to the http server.
I think the simplest way is to define a 'global' variable that stored the current count, and increase it in every query (let's put the concurrence problem aside for convenient).
Any way, here is my code I planned to achieve this so far:
package main
import (
"fmt"
"net/http"
)
count := 0 // *Error* non-declaration statement outside function body
func increment() error{
count = count + 1
return nil
}
func mainHandler(w http.ResponseWriter, r *http.Request){
increment()
fmt.Fprint(w,count)
}
func main(){
http.HandleFunc("/", mainHandler)
http.ListenAndServe(":8085",nil)
}
As you can see, var count
could not be defined there, It's vary from Java servlet which I formerly using.
So how can I achieve this?
Outside of functions you cannot use the short variable declaration :=
. Outside of a function to define a global variable you have to use a variable declaration (with the var
keyword):
var count int
It will automatically be initialized to int
's zero value which is 0
.
Links:
Relevant sections of the Go Language Specification which I recommend you to read:
Note:
Since handling of each request runs in its own goroutine, you need explicit synchronization to access the shared counter, or you have to use other synchronized means to do a proper counting.
You may want to use standard way in golang that in expvar
package for an example http://go-wise.blogspot.com/2011/10/expvar.html
package main
import (
"expvar"
"fmt"
"http"
"io"
)
// Two metrics, these are exposed by "magic" :)
// Number of calls to our server.
var numCalls = expvar.NewInt("num_calls")
// Last user.
var lastUser = expvar.NewString("last_user")
func HelloServer(w http.ResponseWriter, req *http.Request) {
user := req.FormValue("user")
// Update metrics
numCalls.Add(1)
lastUser.Set(user)
msg := fmt.Sprintf("G'day %s
", user)
io.WriteString(w, msg)
}
func main() {
http.HandleFunc("/", HelloServer)
http.ListenAndServe(":8080", nil)
}
Beware that you might want to consider using the sync
package, because counter = counter + 1
will skip one if it's called simultaneously.
The counter must be incremented atomically or else you will have race conditions and miss some counts.
Declare a global int64
variable and access it using the sync.atomic
methods:
package main
import (
"net/http"
"sync/atomic"
)
var requests int64 = 0
// increments the number of requests and returns the new value
func incRequests() int64 {
return atomic.AddInt64(&requests, 1)
}
// returns the current value
func getRequests() int64 {
return atomic.LoadInt64(&requests)
}
func handler(w http.ResponseWriter, r *http.Request) {
incRequests()
// handle the request here ...
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}