Configure version and trace id
This commit is contained in:
parent
50d74f20f1
commit
e7a1116461
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
|
"go/weather/internal/version"
|
||||||
"go/weather/internal/web"
|
"go/weather/internal/web"
|
||||||
"go/weather/pkg/logger"
|
"go/weather/pkg/logger"
|
||||||
"log"
|
"log"
|
||||||
@ -32,7 +33,7 @@ func main() {
|
|||||||
addr := web.NewListenAddr("127.0.0.1", 8080)
|
addr := web.NewListenAddr("127.0.0.1", 8080)
|
||||||
|
|
||||||
defaultLogger.Sugar().Infof("Weather server is listening on %s", addr)
|
defaultLogger.Sugar().Infof("Weather server is listening on %s", addr)
|
||||||
server := web.New(defaultLogger, addr).
|
server := web.New(defaultLogger, addr, version.String()).
|
||||||
WithTLSConfigure().
|
WithTLSConfigure().
|
||||||
WithHandler().
|
WithHandler().
|
||||||
WithHTTPLogging().
|
WithHTTPLogging().
|
||||||
|
2
go.mod
2
go.mod
@ -6,8 +6,10 @@ require (
|
|||||||
github.com/elastic/go-sysinfo v1.6.0 // indirect
|
github.com/elastic/go-sysinfo v1.6.0 // indirect
|
||||||
github.com/elastic/go-windows v1.0.1 // indirect
|
github.com/elastic/go-windows v1.0.1 // indirect
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/hashicorp/go-version v1.2.1 // indirect
|
||||||
github.com/magefile/mage v1.11.0 // indirect
|
github.com/magefile/mage v1.11.0 // indirect
|
||||||
github.com/prometheus/procfs v0.6.0 // indirect
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
go.elastic.co/apm v1.11.0 // indirect
|
||||||
go.elastic.co/apm/module/apmzap v1.11.0 // indirect
|
go.elastic.co/apm/module/apmzap v1.11.0 // indirect
|
||||||
go.elastic.co/ecszap v1.0.0
|
go.elastic.co/ecszap v1.0.0
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -18,6 +18,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||||
|
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||||
|
31
internal/version/version.go
Normal file
31
internal/version/version.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
version "github.com/hashicorp/go-version"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Version ...
|
||||||
|
const Version = "1.0.0"
|
||||||
|
|
||||||
|
//Prerelease such as "dev" (in development), "beta", "rc1", etc.
|
||||||
|
var Prerelease = "dev"
|
||||||
|
|
||||||
|
//SemVer management
|
||||||
|
var SemVer *version.Version
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SemVer = version.Must(version.NewVersion(Version))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header is the header name used to send the current in http requests.
|
||||||
|
const Header = "Weather-Version"
|
||||||
|
|
||||||
|
// String returns the complete version string, including prerelease
|
||||||
|
func String() string {
|
||||||
|
if Prerelease != "" {
|
||||||
|
return fmt.Sprintf("%s-%s", Version, Prerelease)
|
||||||
|
}
|
||||||
|
return Version
|
||||||
|
}
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"go.elastic.co/apm"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,17 +27,22 @@ type WeatherServer struct {
|
|||||||
router *mux.Router
|
router *mux.Router
|
||||||
wlogger *logger.WeatherLogger
|
wlogger *logger.WeatherLogger
|
||||||
subRouters map[string]*mux.Router
|
subRouters map[string]*mux.Router
|
||||||
|
version string
|
||||||
}
|
}
|
||||||
|
|
||||||
//New construct new instance
|
//New construct new instance
|
||||||
func New(logger *logger.WeatherLogger, addr ListenAddr) *WeatherServer {
|
func New(logger *logger.WeatherLogger, addr ListenAddr, version string) *WeatherServer {
|
||||||
return &WeatherServer{
|
return &WeatherServer{
|
||||||
Server: http.Server{
|
Server: http.Server{
|
||||||
Addr: addr.String(),
|
Addr: addr.String(),
|
||||||
BaseContext: func(l net.Listener) context.Context {
|
BaseContext: func(l net.Listener) context.Context {
|
||||||
customContext := context.Background()
|
|
||||||
// here configure context properties
|
// here configure context properties
|
||||||
return customContext
|
dt := apm.DefaultTracer
|
||||||
|
tx := dt.StartTransactionOptions("http", "request", apm.TransactionOptions{
|
||||||
|
Start: time.Now(),
|
||||||
|
})
|
||||||
|
defer tx.End()
|
||||||
|
return apm.ContextWithTransaction(context.Background(), tx)
|
||||||
},
|
},
|
||||||
WriteTimeout: 15 * time.Second,
|
WriteTimeout: 15 * time.Second,
|
||||||
ReadTimeout: 15 * time.Second,
|
ReadTimeout: 15 * time.Second,
|
||||||
@ -44,6 +50,7 @@ func New(logger *logger.WeatherLogger, addr ListenAddr) *WeatherServer {
|
|||||||
router: mux.NewRouter(),
|
router: mux.NewRouter(),
|
||||||
wlogger: logger,
|
wlogger: logger,
|
||||||
subRouters: make(map[string]*mux.Router, 1),
|
subRouters: make(map[string]*mux.Router, 1),
|
||||||
|
version: version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +63,10 @@ func (ws *WeatherServer) WithHandler() *WeatherServer {
|
|||||||
|
|
||||||
api := ws.getOrCreateSubRouterByName(apiRouterName, apiPrefix)
|
api := ws.getOrCreateSubRouterByName(apiRouterName, apiPrefix)
|
||||||
api.HandleFunc("/health", func(rw http.ResponseWriter, r *http.Request) {
|
api.HandleFunc("/health", func(rw http.ResponseWriter, r *http.Request) {
|
||||||
json.NewEncoder(rw).Encode(map[string]bool{"ok": true})
|
json.NewEncoder(rw).Encode(map[string]interface{}{
|
||||||
|
"ok": true,
|
||||||
|
"version": ws.version,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return ws
|
return ws
|
||||||
|
6
pkg/headers/header.go
Normal file
6
pkg/headers/header.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package headers
|
||||||
|
|
||||||
|
const (
|
||||||
|
//ContentType ...
|
||||||
|
ContentType = "Content-Type"
|
||||||
|
)
|
@ -2,6 +2,7 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"go/weather/pkg/headers"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -79,50 +80,50 @@ func NewLogger(loggerName, logPath string, level zap.AtomicLevel) *WeatherLogger
|
|||||||
|
|
||||||
//HTTPLogHandler http handler to log http request and http response
|
//HTTPLogHandler http handler to log http request and http response
|
||||||
func (wl *WeatherLogger) HTTPLogHandler(next http.Handler) http.Handler {
|
func (wl *WeatherLogger) HTTPLogHandler(next http.Handler) http.Handler {
|
||||||
|
// dt := apm.DefaultTracer
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
ww := ResponseWriter{
|
ww := ResponseWriter{
|
||||||
ResponseWriter: w,
|
ResponseWriter: w,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// span, ctx := apm.StartSpan(r.Context(), "updateRequestCount", "custom")
|
||||||
|
// defer span.End()
|
||||||
|
|
||||||
wl.logHTTPRequest(r)
|
wl.logHTTPRequest(r)
|
||||||
next.ServeHTTP(&ww, r)
|
next.ServeHTTP(&ww, r)
|
||||||
wl.logHTTPResponse(ww)
|
wl.logHTTPResponse(ww)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type readCloser struct {
|
|
||||||
io.Reader
|
|
||||||
io.Closer
|
|
||||||
}
|
|
||||||
|
|
||||||
func useTeeReader(rc io.ReadCloser, w io.Writer) io.ReadCloser {
|
|
||||||
tee := io.TeeReader(rc, w)
|
|
||||||
teeCloser := readCloser{tee, rc}
|
|
||||||
return teeCloser
|
|
||||||
}
|
|
||||||
|
|
||||||
//logHTTPRequest print request information
|
//logHTTPRequest print request information
|
||||||
func (wl *WeatherLogger) logHTTPRequest(r *http.Request) {
|
func (wl *WeatherLogger) logHTTPRequest(r *http.Request) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
b, err := ioutil.ReadAll(io.TeeReader(r.Body, &buf))
|
b, err := ioutil.ReadAll(io.TeeReader(r.Body, &buf))
|
||||||
wl.handleError(err)
|
wl.handleError(err)
|
||||||
r.Body = readCloser{&buf, r.Body}
|
r.Body = struct {
|
||||||
traceContextFields := apmzap.TraceContext(r.Context())
|
io.Reader
|
||||||
|
io.Closer
|
||||||
|
}{&buf, r.Body}
|
||||||
|
|
||||||
// var buf bytes.Buffer
|
lwith := wl.Logger.
|
||||||
// var buf2 bytes.Buffer
|
With(apmzap.TraceContext(r.Context())...).
|
||||||
// b, err := io.Copy(io.MultiWriter(&buf, &buf2), r.Body)
|
With([]zap.Field{
|
||||||
// wl.handleError(err)
|
zap.String("http.request.method", r.Method),
|
||||||
// r.Body = readCloser{&buf2, r.Body}
|
// zap.Int64("http.request.bytes", r.Header ContentLength), // total body+header len
|
||||||
|
zap.String("http.request.mime_type", r.Header.Get(headers.ContentType)),
|
||||||
|
// zap.String(""),
|
||||||
|
// zap.String(""),
|
||||||
|
}...)
|
||||||
|
|
||||||
wl.Logger.With(traceContextFields...).Debug("Request",
|
if len(b) > 0 {
|
||||||
zap.String("http.request.method", r.Method),
|
lwith.With([]zap.Field{
|
||||||
zap.ByteString("http.request.body.content", b),
|
zap.ByteString("http.request.body.content", b),
|
||||||
zap.Int("http.request.body.bytes", len(b)),
|
zap.Int("http.request.body.bytes", len(b)),
|
||||||
// zap.Int64("http.request.bytes", r.Header ContentLength), // total body+header len
|
}...)
|
||||||
// zap.String(""),
|
}
|
||||||
// zap.String(""),
|
|
||||||
// zap.String(""),
|
// realy log
|
||||||
)
|
lwith.Debug("Request")
|
||||||
}
|
}
|
||||||
|
|
||||||
//logHTTPResponse print response information
|
//logHTTPResponse print response information
|
||||||
|
Loading…
Reference in New Issue
Block a user