Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
A simple golang web server with basic logging, tracing, health check, graceful shutdown and zero dependencies
package main
import (
type key int
const (
requestIDKey key = 0
var (
listenAddr string
healthy int32
func main() {
flag.StringVar(&listenAddr, "listen-addr", ":5000", "server listen address")
logger := log.New(os.Stdout, "http: ", log.LstdFlags)
logger.Println("Server is starting...")
router := http.NewServeMux()
router.Handle("/", index())
router.Handle("/healthz", healthz())
nextRequestID := func() string {
return fmt.Sprintf("%d", time.Now().UnixNano())
server := &http.Server{
Addr: listenAddr,
Handler: tracing(nextRequestID)(logging(logger)(router)),
ErrorLog: logger,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 15 * time.Second,
done := make(chan bool)
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
go func() {
logger.Println("Server is shutting down...")
atomic.StoreInt32(&healthy, 0)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
logger.Fatalf("Could not gracefully shutdown the server: %v\n", err)
logger.Println("Server is ready to handle requests at", listenAddr)
atomic.StoreInt32(&healthy, 1)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.Fatalf("Could not listen on %s: %v\n", listenAddr, err)
logger.Println("Server stopped")
func index() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
fmt.Fprintln(w, "Hello, World!")
func healthz() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if atomic.LoadInt32(&healthy) == 1 {
func logging(logger *log.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
requestID, ok := r.Context().Value(requestIDKey).(string)
if !ok {
requestID = "unknown"
logger.Println(requestID, r.Method, r.URL.Path, r.RemoteAddr, r.UserAgent())
next.ServeHTTP(w, r)
func tracing(nextRequestID func() string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestID := r.Header.Get("X-Request-Id")
if requestID == "" {
requestID = nextRequestID()
ctx := context.WithValue(r.Context(), requestIDKey, requestID)
w.Header().Set("X-Request-Id", requestID)
next.ServeHTTP(w, r.WithContext(ctx))
Copy link

rexlx commented May 17, 2021

I added a -d option to specify a directory to serve out, but im no good with forking and pull requests. I think I might have removed some useful functionality in the process :)) but if you like that flag, you can find the repo pinned to my github and hack away at it

Copy link

andrew-werdna commented Jun 21, 2021

This is cash-money awesome! Thank you for sharing this!

Copy link

rpeets commented Jul 11, 2021

Any pointers on how to include the http.statuscode in logs, please?

Copy link

titaneric commented Feb 11, 2022

Thanks for sharing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment