mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-25 08:30:29 +00:00
Add support for running profiling when debug build-tags provided (#491)
* wrap root HTTP handler in debug.WithPprof(), rearrange router.Start() to support this * remove unused code * set debug buildtag in build script when $DEBUG set * update go-debug version with fixed handler * use clone of router.srv for LE cert manager, reset server timeouts in debug * add kim's other libraries to README
This commit is contained in:
parent
420e2fb22b
commit
69011d4901
15 changed files with 248 additions and 37 deletions
|
@ -199,8 +199,10 @@ The following libraries and frameworks are used by GoToSocial, with gratitude
|
|||
- [google/wuffs](https://github.com/google/wuffs); png-stripping code. [Apache-2.0 License](https://spdx.org/licenses/Apache-2.0.html).
|
||||
- [go-playground/validator](https://github.com/go-playground/validator); struct validation. [MIT License](https://spdx.org/licenses/MIT.html)
|
||||
- [gorilla/websocket](https://github.com/gorilla/websocket); Websocket connectivity. [BSD-2-Clause License](https://spdx.org/licenses/BSD-2-Clause.html).
|
||||
- [gruf/go-debug](https://codeberg.org/gruf/go-debug); profiling support in debug builds. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [gruf/go-mutexes](https://codeberg.org/gruf/go-mutexes); mutex map. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [gruf/go-runners](https://codeberg.org/gruf/go-runners); worker pool library. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [gruf/go-store](https://codeberg.org/gruf/go-store); cacheing library. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [gruf/go-store](https://codeberg.org/gruf/go-store); local media store. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [h2non/filetype](https://github.com/h2non/filetype); filetype checking. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [jackc/pgx](https://github.com/jackc/pgx); Postgres driver. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
- [mcuadros/go-syslog](https://github.com/mcuadros/go-syslog); Syslog server library. [MIT License](https://spdx.org/licenses/MIT.html).
|
||||
|
|
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module github.com/superseriousbusiness/gotosocial
|
|||
go 1.18
|
||||
|
||||
require (
|
||||
codeberg.org/gruf/go-debug v1.1.2
|
||||
codeberg.org/gruf/go-errors v1.0.5
|
||||
codeberg.org/gruf/go-mutexes v1.1.2
|
||||
codeberg.org/gruf/go-runners v1.2.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -41,6 +41,8 @@ codeberg.org/gruf/go-bytes v1.0.1/go.mod h1:1v/ibfaosfXSZtRdW2rWaVrDXMc9E3bsi/M9
|
|||
codeberg.org/gruf/go-bytes v1.0.2 h1:malqE42Ni+h1nnYWBUAJaDDtEzF4aeN4uPN8DfMNNvo=
|
||||
codeberg.org/gruf/go-bytes v1.0.2/go.mod h1:1v/ibfaosfXSZtRdW2rWaVrDXMc9E3bsi/M9Ekx39cg=
|
||||
codeberg.org/gruf/go-cache v1.1.2/go.mod h1:/Dbc+xU72Op3hMn6x2PXF3NE9uIDFeS+sXPF00hN/7o=
|
||||
codeberg.org/gruf/go-debug v1.1.2 h1:7Tqkktg60M/4WtXTTNUFH2T/6irBw4tI4viv7IRLZDE=
|
||||
codeberg.org/gruf/go-debug v1.1.2/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
|
||||
codeberg.org/gruf/go-errors v1.0.5 h1:rxV70oQkfasUdggLHxOX2QAoJOMFM7XWxHQR45Zx/Fg=
|
||||
codeberg.org/gruf/go-errors v1.0.5/go.mod h1:n03EpmvcmfzU3/xJKC0XXtleXXJUNFpT2fgISODvZ1Y=
|
||||
codeberg.org/gruf/go-fastcopy v1.1.1 h1:HhPCeFdVR5pwiSVDnQEGJ+J2ny9b5QgfiESc0zrWQAY=
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"codeberg.org/gruf/go-debug"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
|
@ -32,7 +33,7 @@ import (
|
|||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
var (
|
||||
const (
|
||||
readTimeout = 60 * time.Second
|
||||
writeTimeout = 30 * time.Second
|
||||
idleTimeout = 30 * time.Second
|
||||
|
@ -69,38 +70,69 @@ func (r *router) AttachStaticFS(relativePath string, fs http.FileSystem) {
|
|||
|
||||
// Start starts the router nicely. It will serve two handlers if letsencrypt is enabled, and only the web/API handler if letsencrypt is not enabled.
|
||||
func (r *router) Start() {
|
||||
keys := config.Keys
|
||||
leEnabled := viper.GetBool(keys.LetsEncryptEnabled)
|
||||
var (
|
||||
keys = config.Keys
|
||||
|
||||
if leEnabled {
|
||||
bindAddress := viper.GetString(keys.BindAddress)
|
||||
lePort := viper.GetInt(keys.LetsEncryptPort)
|
||||
// listen is the server start function, by
|
||||
// default pointing to regular HTTP listener,
|
||||
// but updated to TLS if LetsEncrypt is enabled.
|
||||
listen = r.srv.ListenAndServe
|
||||
)
|
||||
|
||||
// serve the http handler on the selected letsencrypt port, for receiving letsencrypt requests and solving their devious riddles
|
||||
if viper.GetBool(keys.LetsEncryptEnabled) {
|
||||
// LetsEncrypt support is enabled
|
||||
|
||||
// Prepare an HTTPS-redirect handler for LetsEncrypt fallback
|
||||
redirect := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
target := "https://" + r.Host + r.URL.Path
|
||||
if len(r.URL.RawQuery) > 0 {
|
||||
target += "?" + r.URL.RawQuery
|
||||
}
|
||||
http.Redirect(rw, r, target, http.StatusTemporaryRedirect)
|
||||
})
|
||||
|
||||
// Clone HTTP server but with autocert handler
|
||||
srv := r.srv
|
||||
srv.Handler = r.certManager.HTTPHandler(redirect)
|
||||
|
||||
// Start the LetsEncrypt autocert manager HTTP server.
|
||||
go func() {
|
||||
listen := fmt.Sprintf("%s:%d", bindAddress, lePort)
|
||||
logrus.Infof("letsencrypt listening on %s", listen)
|
||||
if err := http.ListenAndServe(listen, r.certManager.HTTPHandler(http.HandlerFunc(httpsRedirect))); err != nil && err != http.ErrServerClosed {
|
||||
addr := fmt.Sprintf("%s:%d",
|
||||
viper.GetString(keys.BindAddress),
|
||||
viper.GetInt(keys.LetsEncryptPort),
|
||||
)
|
||||
|
||||
logrus.Infof("letsencrypt listening on %s", addr)
|
||||
|
||||
if err := srv.ListenAndServe(); err != nil &&
|
||||
err != http.ErrServerClosed {
|
||||
logrus.Fatalf("letsencrypt: listen: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// and serve the actual TLS handler
|
||||
go func() {
|
||||
logrus.Infof("listening on %s", r.srv.Addr)
|
||||
if err := r.srv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
|
||||
logrus.Fatalf("listen: %s", err)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
// no tls required
|
||||
go func() {
|
||||
logrus.Infof("listening on %s", r.srv.Addr)
|
||||
if err := r.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
logrus.Fatalf("listen: %s", err)
|
||||
}
|
||||
}()
|
||||
// TLS is enabled, update the listen function
|
||||
listen = func() error { return r.srv.ListenAndServeTLS("", "") }
|
||||
}
|
||||
|
||||
// Pass the server handler through a debug pprof middleware handler.
|
||||
// For standard production builds this will be a no-op, but when the
|
||||
// "debug" or "debugenv" build-tag is set pprof stats will be served
|
||||
// at the standard "/debug/pprof" URL.
|
||||
r.srv.Handler = debug.WithPprof(r.srv.Handler)
|
||||
if debug.DEBUG() {
|
||||
// Profiling requires timeouts longer than 30s, so reset these.
|
||||
logrus.Warn("resetting http.Server{} timeout to support profiling")
|
||||
r.srv.ReadTimeout = 0
|
||||
r.srv.WriteTimeout = 0
|
||||
}
|
||||
|
||||
// Start the main listener.
|
||||
go func() {
|
||||
logrus.Infof("listening on %s", r.srv.Addr)
|
||||
if err := listen(); err != nil && err != http.ErrServerClosed {
|
||||
logrus.Fatalf("listen: %s", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Stop shuts down the router nicely
|
||||
|
@ -193,13 +225,3 @@ func New(ctx context.Context, db db.DB) (Router, error) {
|
|||
certManager: m,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func httpsRedirect(w http.ResponseWriter, req *http.Request) {
|
||||
target := "https://" + req.Host + req.URL.Path
|
||||
|
||||
if len(req.URL.RawQuery) > 0 {
|
||||
target += "?" + req.URL.RawQuery
|
||||
}
|
||||
|
||||
http.Redirect(w, req, target, http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
set -eu
|
||||
|
||||
# DEBUG returns whether DEBUG build is enabled.
|
||||
DEBUG() { [ ! -z "${DEBUG-}" ]; }
|
||||
|
||||
CGO_ENABLED=0 go build -trimpath \
|
||||
-tags 'netgo osusergo static_build' \
|
||||
-tags "netgo osusergo static_build $(DEBUG && echo 'debugenv')" \
|
||||
-ldflags="-s -w -extldflags '-static' -X 'main.Version=${VERSION:-$(git describe --tags --abbrev=0)}'" \
|
||||
./cmd/gotosocial
|
||||
|
|
9
vendor/codeberg.org/gruf/go-debug/LICENSE
generated
vendored
Normal file
9
vendor/codeberg.org/gruf/go-debug/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 gruf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
37
vendor/codeberg.org/gruf/go-debug/README.md
generated
vendored
Normal file
37
vendor/codeberg.org/gruf/go-debug/README.md
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
# go-debug
|
||||
|
||||
This library provides a very simple method for compile-time or runtime determined debug checks, set using build tags.
|
||||
|
||||
The compile-time checks use Go constants, so when disabled your debug code will not be compiled.
|
||||
|
||||
The possible build tags are:
|
||||
|
||||
- "debug" || "" = debug determined at compile-time
|
||||
|
||||
- "debugenv" = debug determined at runtime using the $DEBUG environment variable
|
||||
|
||||
An example for how this works in practice can be seen by the following code:
|
||||
|
||||
```
|
||||
func main() {
|
||||
println("debug.DEBUG() =", debug.DEBUG())
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
# Debug determined at compile-time, it is disabled
|
||||
$ go run .
|
||||
debug.DEBUG() = false
|
||||
|
||||
# Debug determined at compile-time, it is enabled
|
||||
$ go run -tags=debug .
|
||||
debug.DEBUG() = true
|
||||
|
||||
# Debug determined at runtime, $DEBUG is not set
|
||||
$ go run -tags=debugenv .
|
||||
debug.DEBUG() = false
|
||||
|
||||
# Debug determined at runtime, $DEBUG is set
|
||||
$ DEBUG=y go run -tags=debugenv .
|
||||
debug.DEBUG() = true
|
||||
```
|
13
vendor/codeberg.org/gruf/go-debug/debug.go
generated
vendored
Normal file
13
vendor/codeberg.org/gruf/go-debug/debug.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
package debug
|
||||
|
||||
// DEBUG returns whether debugging is enabled.
|
||||
func DEBUG() bool {
|
||||
return debug
|
||||
}
|
||||
|
||||
// Run will only call fn if DEBUG is enabled.
|
||||
func Run(fn func()) {
|
||||
if debug {
|
||||
fn()
|
||||
}
|
||||
}
|
9
vendor/codeberg.org/gruf/go-debug/debug_env.go
generated
vendored
Normal file
9
vendor/codeberg.org/gruf/go-debug/debug_env.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
//go:build debugenv
|
||||
// +build debugenv
|
||||
|
||||
package debug
|
||||
|
||||
import "os"
|
||||
|
||||
// check if debug env variable is set
|
||||
var debug = (os.Getenv("DEBUG") != "")
|
7
vendor/codeberg.org/gruf/go-debug/debug_off.go
generated
vendored
Normal file
7
vendor/codeberg.org/gruf/go-debug/debug_off.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
//go:build !debug && !debugenv
|
||||
// +build !debug,!debugenv
|
||||
|
||||
package debug
|
||||
|
||||
// debug always off.
|
||||
const debug = false
|
7
vendor/codeberg.org/gruf/go-debug/debug_on.go
generated
vendored
Normal file
7
vendor/codeberg.org/gruf/go-debug/debug_on.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
//go:build debug && !debugenv
|
||||
// +build debug,!debugenv
|
||||
|
||||
package debug
|
||||
|
||||
// debug always on.
|
||||
const debug = true
|
16
vendor/codeberg.org/gruf/go-debug/pprof_off.go
generated
vendored
Normal file
16
vendor/codeberg.org/gruf/go-debug/pprof_off.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
//go:build !debug && !debugenv
|
||||
// +build !debug,!debugenv
|
||||
|
||||
package debug
|
||||
|
||||
import "net/http"
|
||||
|
||||
// ServePprof will start an HTTP server serving /debug/pprof only if debug enabled.
|
||||
func ServePprof(addr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithPprof will add /debug/pprof handling (provided by "net/http/pprof") only if debug enabled.
|
||||
func WithPprof(handler http.Handler) http.Handler {
|
||||
return handler
|
||||
}
|
63
vendor/codeberg.org/gruf/go-debug/pprof_on.go
generated
vendored
Normal file
63
vendor/codeberg.org/gruf/go-debug/pprof_on.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
//go:build debug || debugenv
|
||||
// +build debug debugenv
|
||||
|
||||
package debug
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ServePprof will start an HTTP server serving /debug/pprof only if debug enabled.
|
||||
func ServePprof(addr string) error {
|
||||
if !debug {
|
||||
// debug disabled in env
|
||||
return nil
|
||||
}
|
||||
handler := WithPprof(nil)
|
||||
return http.ListenAndServe(addr, handler)
|
||||
}
|
||||
|
||||
// WithPprof will add /debug/pprof handling (provided by "net/http/pprof") only if debug enabled.
|
||||
func WithPprof(handler http.Handler) http.Handler {
|
||||
if !debug {
|
||||
// debug disabled in env
|
||||
return handler
|
||||
}
|
||||
|
||||
// Default serve mux is setup with pprof
|
||||
pprofmux := http.DefaultServeMux
|
||||
|
||||
if pprofmux == nil {
|
||||
// Someone nil'ed the default mux
|
||||
pprofmux = &http.ServeMux{}
|
||||
pprofmux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
pprofmux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||
pprofmux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
pprofmux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
pprofmux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
// Ensure handler is non-nil
|
||||
handler = http.NotFoundHandler()
|
||||
}
|
||||
|
||||
// Debug enabled, return wrapped handler func
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
const prefix = "/debug/pprof"
|
||||
|
||||
// /debug/pprof(/.*)? -> pass to pprofmux
|
||||
if strings.HasPrefix(r.URL.Path, prefix) {
|
||||
path := r.URL.Path[len(prefix):]
|
||||
if path == "" || path[0] == '/' {
|
||||
pprofmux.ServeHTTP(rw, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// .* -> pass to handler
|
||||
handler.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
17
vendor/codeberg.org/gruf/go-debug/run_tests.sh
generated
vendored
Normal file
17
vendor/codeberg.org/gruf/go-debug/run_tests.sh
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/sh
|
||||
|
||||
(
|
||||
# Run in subshell with cmd echo
|
||||
set -ex
|
||||
|
||||
# Run debug tests
|
||||
DEBUG= go test -tags= -v
|
||||
DEBUG= go test -tags=debug -v
|
||||
DEBUG= go test -tags=debugenv -v
|
||||
DEBUG=y go test -tags=debugenv -v
|
||||
DEBUG=1 go test -tags=debugenv -v
|
||||
DEBUG=y go test -tags=debugenv,debug -v
|
||||
DEBUG=y go test -tags= -v
|
||||
)
|
||||
|
||||
echo 'success!'
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
|
@ -1,6 +1,9 @@
|
|||
# codeberg.org/gruf/go-bytes v1.0.2
|
||||
## explicit; go 1.14
|
||||
codeberg.org/gruf/go-bytes
|
||||
# codeberg.org/gruf/go-debug v1.1.2
|
||||
## explicit; go 1.16
|
||||
codeberg.org/gruf/go-debug
|
||||
# codeberg.org/gruf/go-errors v1.0.5
|
||||
## explicit; go 1.15
|
||||
codeberg.org/gruf/go-errors
|
||||
|
|
Loading…
Reference in a new issue