Skip to content

Instantly share code, notes, and snippets.

@maisnamraju
Forked from creack/main.go
Created June 27, 2019 10:53
Show Gist options
  • Select an option

  • Save maisnamraju/34a88f307105b01b43324b61b74e15fa to your computer and use it in GitHub Desktop.

Select an option

Save maisnamraju/34a88f307105b01b43324b61b74e15fa to your computer and use it in GitHub Desktop.

Revisions

  1. @creack creack revised this gist Jan 7, 2018. 1 changed file with 62 additions and 29 deletions.
    91 changes: 62 additions & 29 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -13,20 +13,47 @@ import (
    "time"
    )

    var healthy int64
    type middleware func(http.Handler) http.Handler
    type middlewares []middleware

    func shutdown(quit <-chan os.Signal, server *http.Server) {
    <-quit
    server.ErrorLog.Printf("Server is shutting down...\n")
    atomic.StoreInt64(&healthy, 0)
    func (mws middlewares) apply(hdlr http.Handler) http.Handler {
    if len(mws) == 0 {
    return hdlr
    }
    return mws[1:].apply(mws[0](hdlr))
    }

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    func (c *controller) shutdown(ctx context.Context, server *http.Server) context.Context {
    ctx, done := context.WithCancel(ctx)

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    server.ErrorLog.Fatalf("Could not gracefully shutdown the server: %s\n", err)
    }
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    go func() {
    defer done()

    <-quit
    signal.Stop(quit)
    close(quit)

    atomic.StoreInt64(&c.healthy, 0)
    server.ErrorLog.Printf("Server is shutting down...\n")

    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    server.ErrorLog.Fatalf("Could not gracefully shutdown the server: %s\n", err)
    }
    }()

    return ctx
    }

    type controller struct {
    logger *log.Logger
    nextRequestID func() string
    healthy int64
    }

    func main() {
    @@ -38,69 +65,75 @@ func main() {
    logger := log.New(os.Stdout, "http: ", log.LstdFlags)
    logger.Printf("Server is starting...")

    c := &controller{logger: logger, nextRequestID: func() string { return strconv.FormatInt(time.Now().UnixNano(), 36) }}
    router := http.NewServeMux()
    router.HandleFunc("/", index)
    router.HandleFunc("/healthz", healthz)
    router.HandleFunc("/", c.index)
    router.HandleFunc("/healthz", c.healthz)

    server := &http.Server{
    Addr: listenAddr,
    Handler: tracing(logging(router, logger), func() string { return strconv.FormatInt(time.Now().UnixNano(), 36) }),
    Handler: (middlewares{c.tracing, c.logging}).apply(router),
    ErrorLog: logger,
    ReadTimeout: 5 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout: 15 * time.Second,
    }

    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    go shutdown(quit, server)
    ctx := c.shutdown(context.Background(), server)

    logger.Printf("Server is ready to handle requests at %q\n", listenAddr)
    atomic.StoreInt64(&healthy, time.Now().UnixNano())
    atomic.StoreInt64(&c.healthy, time.Now().UnixNano())

    if err := server.ListenAndServe(); err != http.ErrServerClosed {
    logger.Fatalf("Could not listen on %q: %s\n", listenAddr, err)
    }
    <-ctx.Done()
    logger.Printf("Server stopped\n")
    }

    func index(w http.ResponseWriter, req *http.Request) {
    func (c *controller) index(w http.ResponseWriter, req *http.Request) {
    if req.URL.Path != "/" {
    http.NotFound(w, req)
    return
    }
    fmt.Fprintf(w, "Hello, World!\n")
    }

    func healthz(w http.ResponseWriter, req *http.Request) {
    h := atomic.LoadInt64(&healthy)
    if h == 0 {
    func (c *controller) healthz(w http.ResponseWriter, req *http.Request) {
    if h := atomic.LoadInt64(&c.healthy); h == 0 {
    w.WriteHeader(http.StatusServiceUnavailable)
    return
    } else {
    fmt.Fprintf(w, "uptime: %s\n", time.Since(time.Unix(0, h)))
    }
    fmt.Fprintf(w, "uptime: %s\n", time.Since(time.Unix(0, h)))
    }

    func logging(hdlr http.Handler, logger *log.Logger) http.Handler {
    func (c *controller) logging(hdlr http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    defer func(start time.Time) {
    requestID := w.Header().Get("X-Request-Id")
    if requestID == "" {
    requestID = "unknown"
    }
    logger.Println(requestID, req.Method, req.URL.Path, req.RemoteAddr, req.UserAgent(), time.Since(start))
    c.logger.Println(requestID, req.Method, req.URL.Path, req.RemoteAddr, req.UserAgent(), time.Since(start))
    }(time.Now())
    hdlr.ServeHTTP(w, req)
    })
    }

    func tracing(hdlr http.Handler, nextRequestID func() string) http.Handler {
    func (c *controller) tracing(hdlr http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    requestID := req.Header.Get("X-Request-Id")
    if requestID == "" {
    requestID = nextRequestID()
    requestID = c.nextRequestID()
    }
    w.Header().Set("X-Request-Id", requestID)
    hdlr.ServeHTTP(w, req)
    })
    }

    // main_test.go
    var (
    _ http.Handler = http.HandlerFunc((&controller{}).index)
    _ http.Handler = http.HandlerFunc((&controller{}).healthz)
    _ middleware = (&controller{}).logging
    _ middleware = (&controller{}).tracing
    )
  2. @creack creack revised this gist Jan 7, 2018. 1 changed file with 60 additions and 80 deletions.
    140 changes: 60 additions & 80 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -2,125 +2,105 @@ package main

    import (
    "context"
    "flag"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"
    "strconv"
    "sync/atomic"
    "syscall"
    "time"
    )

    type key int
    var healthy int64

    const (
    requestIDKey key = 0
    )
    func shutdown(quit <-chan os.Signal, server *http.Server) {
    <-quit
    server.ErrorLog.Printf("Server is shutting down...\n")
    atomic.StoreInt64(&healthy, 0)

    var (
    listenAddr string
    healthy int32
    )
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    server.ErrorLog.Fatalf("Could not gracefully shutdown the server: %s\n", err)
    }
    }

    func main() {
    flag.StringVar(&listenAddr, "listen-addr", ":5000", "server listen address")
    flag.Parse()
    listenAddr := ":5000"
    if len(os.Args) == 2 {
    listenAddr = os.Args[1]
    }

    logger := log.New(os.Stdout, "http: ", log.LstdFlags)
    logger.Println("Server is starting...")
    logger.Printf("Server is starting...")

    router := http.NewServeMux()
    router.Handle("/", index())
    router.Handle("/healthz", healthz())

    nextRequestID := func() string {
    return fmt.Sprintf("%d", time.Now().UnixNano())
    }
    router.HandleFunc("/", index)
    router.HandleFunc("/healthz", healthz)

    server := &http.Server{
    Addr: listenAddr,
    Handler: tracing(nextRequestID)(logging(logger)(router)),
    Handler: tracing(logging(router, logger), func() string { return strconv.FormatInt(time.Now().UnixNano(), 36) }),
    ErrorLog: logger,
    ReadTimeout: 5 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout: 15 * time.Second,
    }

    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)

    go func() {
    <-quit
    logger.Println("Server is shutting down...")
    atomic.StoreInt32(&healthy, 0)

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    go shutdown(quit, server)

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    logger.Fatalf("Could not gracefully shutdown the server: %v\n", err)
    }
    }()
    logger.Printf("Server is ready to handle requests at %q\n", listenAddr)
    atomic.StoreInt64(&healthy, time.Now().UnixNano())

    logger.Println("Server is ready to handle requests at", listenAddr)
    atomic.StoreInt32(&healthy, 1)
    if err := server.ListenAndServe(); err != http.ErrServerClosed {
    logger.Fatalf("Could not listen on %s: %v\n", listenAddr, err)
    logger.Fatalf("Could not listen on %q: %s\n", listenAddr, err)
    }

    logger.Println("Server stopped")
    logger.Printf("Server stopped\n")
    }

    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)
    return
    }
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    w.Header().Set("X-Content-Type-Options", "nosniff")
    w.WriteHeader(http.StatusOK)
    fmt.Fprintln(w, "Hello, World!")
    })
    func index(w http.ResponseWriter, req *http.Request) {
    if req.URL.Path != "/" {
    http.NotFound(w, req)
    return
    }
    fmt.Fprintf(w, "Hello, World!\n")
    }

    func healthz() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if atomic.LoadInt32(&healthy) == 1 {
    w.WriteHeader(http.StatusNoContent)
    return
    }
    func healthz(w http.ResponseWriter, req *http.Request) {
    h := atomic.LoadInt64(&healthy)
    if h == 0 {
    w.WriteHeader(http.StatusServiceUnavailable)
    })
    }

    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)
    })
    return
    }
    fmt.Fprintf(w, "uptime: %s\n", time.Since(time.Unix(0, h)))
    }

    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")
    func logging(hdlr http.Handler, logger *log.Logger) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    defer func(start time.Time) {
    requestID := w.Header().Get("X-Request-Id")
    if requestID == "" {
    requestID = nextRequestID()
    requestID = "unknown"
    }
    ctx := context.WithValue(r.Context(), requestIDKey, requestID)
    w.Header().Set("X-Request-Id", requestID)
    next.ServeHTTP(w, r.WithContext(ctx))
    })
    }
    logger.Println(requestID, req.Method, req.URL.Path, req.RemoteAddr, req.UserAgent(), time.Since(start))
    }(time.Now())
    hdlr.ServeHTTP(w, req)
    })
    }

    func tracing(hdlr http.Handler, nextRequestID func() string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    requestID := req.Header.Get("X-Request-Id")
    if requestID == "" {
    requestID = nextRequestID()
    }
    w.Header().Set("X-Request-Id", requestID)
    hdlr.ServeHTTP(w, req)
    })
    }
  3. Enrico Foltran revised this gist Jan 7, 2018. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -52,15 +52,15 @@ func main() {

    go func() {
    <-quit
    logger.Println("Server is shoutting down...")
    logger.Println("Server is shutting down...")
    atomic.StoreInt32(&healthy, 0)

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    logger.Fatalf("Could not gracefully shoutdown the server: %v\n", err)
    logger.Fatalf("Could not gracefully shutdown the server: %v\n", err)
    }
    }()

  4. Enrico Foltran created this gist Jan 7, 2018.
    126 changes: 126 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,126 @@
    package main

    import (
    "context"
    "flag"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"
    "sync/atomic"
    "time"
    )

    type key int

    const (
    requestIDKey key = 0
    )

    var (
    listenAddr string
    healthy int32
    )

    func main() {
    flag.StringVar(&listenAddr, "listen-addr", ":5000", "server listen address")
    flag.Parse()

    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,
    }

    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)

    go func() {
    <-quit
    logger.Println("Server is shoutting down...")
    atomic.StoreInt32(&healthy, 0)

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    server.SetKeepAlivesEnabled(false)
    if err := server.Shutdown(ctx); err != nil {
    logger.Fatalf("Could not gracefully shoutdown the server: %v\n", err)
    }
    }()

    logger.Println("Server is ready to handle requests at", listenAddr)
    atomic.StoreInt32(&healthy, 1)
    if err := server.ListenAndServe(); 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)
    return
    }
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    w.Header().Set("X-Content-Type-Options", "nosniff")
    w.WriteHeader(http.StatusOK)
    fmt.Fprintln(w, "Hello, World!")
    })
    }

    func healthz() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if atomic.LoadInt32(&healthy) == 1 {
    w.WriteHeader(http.StatusNoContent)
    return
    }
    w.WriteHeader(http.StatusServiceUnavailable)
    })
    }

    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))
    })
    }
    }