func (s *Server) Respond(ctx context.Context, status int, m string, c int, data []*Item, w http.ResponseWriter) {
	span, ctx := ot.StartSpanFromContext(ctx, "Respond")
	defer span.Finish()
	span.SetTag("status", status)
	log := util.RequestIDLoggerFromContext(ctx, s.logger)
	res, err := NewResponse(status, m, c, data)
	if err != nil {
		s.internalError(ctx, w)
		log.Panicw("unable to create JSON response",
			"error", err,
		)
	}
	err = res.SendJSON(w)
	if err != nil {
		s.internalError(ctx, w)
		log.Panicw("sending JSON response failed",
			"error", err,
			"response", res,
		)
	}
	for k, v := range w.Header() {
		span.SetTag(fmt.Sprintf("header.%s", k), v)
	}
	span.LogKV(
		"message", m,
		"count", c,
		"data", data,
	)
}
Respond sends a JSON-encoded response.
package item
import (
	"context"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync/atomic"
	"syscall"
	"time"
	"github.com/go-redis/redis"
	"github.com/gorilla/mux"
	"github.com/obitech/micro-obs/util"
	ot "github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
)
const (
	serviceName = "item"
)
type Server struct {
	address  string
	endpoint string
	redis    *redis.Client
	redisOps uint64
	server   *http.Server
	router   *mux.Router
	logger   *util.Logger
	promReg  *prometheus.Registry
}
type ServerOptions func(*Server) error
func NewServer(options ...ServerOptions) (*Server, error) {
	logger, err := util.NewLogger("info", serviceName)
	if err != nil {
		return nil, errors.Wrap(err, "unable to create Logger")
	}
	rc, _ := NewRedisClient("redis://127.0.0.1:6379/0")
	s := &Server{
		address:  ":8080",
		endpoint: "127.0.0.1:8081",
		redis:    rc,
		logger:   logger,
		router:   util.NewRouter(),
		promReg:  prometheus.NewRegistry(),
	}
	for _, fn := range options {
		if err := fn(s); err != nil {
			return nil, errors.Wrap(err, "Failed to set server options")
		}
	}
	s.redis.WrapProcess(func(old func(cmd redis.Cmder) error) func(cmd redis.Cmder) error {
		return func(cmd redis.Cmder) error {
			atomic.AddUint64(&s.redisOps, 1)
			ops := atomic.LoadUint64(&s.redisOps)
			s.logger.Debugw("redis sent",
				"count", ops,
				"cmd", cmd,
			)
			err := old(cmd)
			s.logger.Debugw("redis received",
				"count", ops,
				"cmd", cmd,
			)
			return err
		}
	})
	s.logger.Debugw("Creating new server",
		"address", s.address,
		"endpoint", s.endpoint,
	)
	s.createRoutes()
	return s, nil
}
func (s *Server) InitPromReg() {
	s.promReg.MustRegister(
		prometheus.NewGoCollector(),
		prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}),
		rm.InFlightGauge, rm.Counter, rm.Duration, rm.ResponseSize,
	)
}
func (s *Server) Run() error {
	defer s.logger.Sync()
	defer s.redis.Close()
	l, err := net.Listen("tcp", s.address)
	if err != nil {
		return errors.Wrapf(err, "Failed creating listener on %s", s.address)
	}
	s.server = &http.Server{
		Handler:        s.router,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	var tracer ot.Tracer
	var closer io.Closer
	tracer, closer, err = util.InitTracer("item", s.logger)
	if err != nil {
		s.logger.Warnw("unable to initialize tracer",
			"error", err,
		)
	} else {
		defer closer.Close()
		ot.SetGlobalTracer(tracer)
	}
	go func() {
		s.logger.Infow("Server listening",
			"address", s.address,
			"endpoint", s.endpoint,
		)
		s.logger.Fatal(s.server.Serve(l))
	}()
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
	<-stop
	s.Stop()
	return nil
}
func (s *Server) Stop() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()
	s.logger.Info("Shutting down")
	if err := s.server.Shutdown(ctx); err != nil {
		s.logger.Errorw("HTTP server shutdown",
			"error", err,
		)
	}
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.router.ServeHTTP(w, r)
}
func (s *Server) internalError(ctx context.Context, w http.ResponseWriter) {
	status := http.StatusInternalServerError
	parent := ot.SpanFromContext(ctx)
	if parent != nil {
		parent.SetTag("status", status)
	}
	w.Header().Del("Content-Type")
	w.WriteHeader(status)
	if _, err := io.WriteString(w, "Internal Server Error\n"); err != nil {
		log := util.RequestIDLoggerFromContext(ctx, s.logger)
		log.Panicw("unable to send response",
			"error", err,
		)
	}
}