feat: add option to log the n most active IPs each hour (#496)

Reviewed-on: https://codeberg.org/Codeberg/pages-server/pulls/496
Co-authored-by: crapStone <me@crapstone.dev>
Co-committed-by: crapStone <me@crapstone.dev>
This commit is contained in:
crapStone 2025-06-25 22:12:33 +02:00 committed by crapStone
parent d27c594c28
commit 5477ba2c46
8 changed files with 97 additions and 5 deletions

View file

@ -1,8 +1,10 @@
package handler
import (
"net"
"net/http"
"strings"
"sync"
"github.com/rs/zerolog/log"
@ -24,10 +26,28 @@ func Handler(
cfg config.ServerConfig,
giteaClient *gitea.Client,
canonicalDomainCache, redirectsCache cache.ICache,
mostActiveIpMap *sync.Map,
) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
ctx := context.New(w, req)
log := log.With().Str("ReqId", ctx.ReqId).Strs("Handler", []string{req.Host, req.RequestURI}).Logger()
if cfg.LogMostActiveIps {
ip, _, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
log.Warn().Err(err).Msg("Failed to get IP address. Using complete remoteAddr string")
ip = req.RemoteAddr
}
success := false
for !success {
value, _ := mostActiveIpMap.LoadOrStore(ip, uint(0))
count := value.(uint)
success = mostActiveIpMap.CompareAndSwap(ip, count, count+1)
}
}
log.Debug().Msg("\n----------------------------------------------------------")
ctx.RespWriter.Header().Set("Server", "pages-server")

View file

@ -3,6 +3,7 @@ package handler
import (
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"
@ -29,7 +30,7 @@ func TestHandlerPerformance(t *testing.T) {
AllowedCorsDomains: []string{"raw.codeberg.org", "fonts.codeberg.org", "design.codeberg.org"},
PagesBranches: []string{"pages"},
}
testHandler := Handler(serverCfg, giteaClient, cache.NewInMemoryCache(), cache.NewInMemoryCache())
testHandler := Handler(serverCfg, giteaClient, cache.NewInMemoryCache(), cache.NewInMemoryCache(), &sync.Map{})
testCase := func(uri string, status int) {
t.Run(uri, func(t *testing.T) {

View file

@ -7,7 +7,9 @@ import (
"net"
"net/http"
"os"
"sort"
"strings"
"sync"
"time"
"github.com/pires/go-proxyproto"
@ -135,8 +137,41 @@ func Serve(ctx *cli.Context) error {
StartProfilingServer(ctx.String("profiling-address"))
}
mostActiveIpMap := &sync.Map{}
if cfg.Server.LogMostActiveIps {
go func() {
ticker := time.NewTicker(1 * time.Hour)
for range ticker.C {
type kv struct {
Key string
Value uint
}
var kvArray []kv
mostActiveIpMap.Range(func(k, v any) bool {
kvArray = append(kvArray, kv{k.(string), v.(uint)})
return true
})
mostActiveIpMap.Clear()
sort.Slice(kvArray, func(i, j int) bool {
return kvArray[i].Value > kvArray[j].Value
})
builder := strings.Builder{}
var item kv
for i := uint(0); i < cfg.Server.MostActiveIpCount; i++ {
item = kvArray[i]
builder.WriteString(fmt.Sprintf("\n%s, %d", item.Key, item.Value))
}
log.Log().Msg(fmt.Sprintf("%d most active IPs:%s", cfg.Server.MostActiveIpCount, builder.String()))
}
}()
}
// Create ssl handler based on settings
sslHandler := handler.Handler(cfg.Server, giteaClient, canonicalDomainCache, redirectsCache)
sslHandler := handler.Handler(cfg.Server, giteaClient, canonicalDomainCache, redirectsCache, mostActiveIpMap)
// Start the ssl listener
log.Info().Msgf("Start SSL server using TCP listener on %s", listener.Addr())