♻️ Refactored tracing system to cost less memory

This commit is contained in:
LittleSheep 2025-01-14 17:22:23 +08:00
parent 5ccbc592b7
commit ee8b7e5660
12 changed files with 70 additions and 35 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
/letsencrypt /letsencrypt
/certs /certs
/dist /dist
/logs
.DS_Store .DS_Store

View File

@ -3,7 +3,7 @@ FROM golang:alpine as roadsign-server
WORKDIR /source WORKDIR /source
COPY . . COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildvcs -o /dist ./pkg/cmd/server/main.go RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildvcs -o /dist ./pkg/cmd/main.go
# Runtime # Runtime
FROM golang:alpine FROM golang:alpine

View File

@ -24,9 +24,10 @@ id = "example-region"
[[locations]] [[locations]]
id = "example" id = "example"
host = ["localhost:8000"] hosts = ["localhost:8000"]
path = ["/"] paths = ["/"]
[[locations.destinations]] [[locations.destinations]]
id = "example-destination" id = "example-destination"
uri = "https://example.com" uri = "https://example.com"
helmet = { x_frame_options = "SAMEORIGIN" } helmet = { x_frame_options = "SAMEORIGIN" }

1
go.mod
View File

@ -28,6 +28,7 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/net v0.29.0 // indirect golang.org/x/net v0.29.0 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
) )
require ( require (

2
go.sum
View File

@ -169,6 +169,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -44,6 +44,9 @@ func main() {
log.Warn().Msgf("RoadSign auto generated api credential is %s", credential) log.Warn().Msgf("RoadSign auto generated api credential is %s", credential)
} }
// Initialize access logging
navi.InitializeLogging()
// Load & init navigator // Load & init navigator
if err := navi.ReadInConfig(viper.GetString("paths.configs")); err != nil { if err := navi.ReadInConfig(viper.GetString("paths.configs")); err != nil {
log.Panic().Err(err).Msg("An error occurred when loading configurations.") log.Panic().Err(err).Msg("An error occurred when loading configurations.")

View File

@ -16,9 +16,7 @@ func ReadInConfig(root string) error {
instance := &RoadApp{ instance := &RoadApp{
Regions: make([]*Region, 0), Regions: make([]*Region, 0),
Metrics: &RoadMetrics{ Metrics: &RoadMetrics{
Traces: make([]RoadTrace, 0),
Traffic: make(map[string]int64), Traffic: make(map[string]int64),
TrafficFrom: make(map[string]int64),
TotalTraffic: 0, TotalTraffic: 0,
StartupAt: time.Now(), StartupAt: time.Now(),
}, },

20
pkg/navi/logging.go Normal file
View File

@ -0,0 +1,20 @@
package navi
import (
"log"
"github.com/spf13/viper"
"gopkg.in/natefinch/lumberjack.v2"
)
var accessLogger *log.Logger
func InitializeLogging() {
accessLogger = log.New(&lumberjack.Logger{
Filename: viper.GetString("logging.access"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 30,
Compress: true,
}, "", 0)
}

View File

@ -1,15 +1,16 @@
package navi package navi
import ( import (
"github.com/spf13/viper" "bufio"
"os"
"time" "time"
jsoniter "github.com/json-iterator/go"
"github.com/spf13/viper"
) )
type RoadMetrics struct { type RoadMetrics struct {
Traces []RoadTrace `json:"-"`
Traffic map[string]int64 `json:"traffic"` Traffic map[string]int64 `json:"traffic"`
TrafficFrom map[string]int64 `json:"traffic_from"`
TotalTraffic int64 `json:"total_traffic"` TotalTraffic int64 `json:"total_traffic"`
StartupAt time.Time `json:"startup_at"` StartupAt time.Time `json:"startup_at"`
} }
@ -42,22 +43,28 @@ func (v *RoadMetrics) AddTrace(trace RoadTrace) {
} else { } else {
v.Traffic[trace.Region]++ v.Traffic[trace.Region]++
} }
if _, ok := v.TrafficFrom[trace.IpAddress]; !ok {
v.TrafficFrom[trace.IpAddress] = 0 raw, _ := jsoniter.Marshal(trace)
} else { accessLogger.Println(string(raw))
v.TrafficFrom[trace.IpAddress]++
} }
v.Traces = append(v.Traces, trace) func (v *RoadMetrics) ReadTrace() []RoadTrace {
fp := viper.GetString("logging.access")
file, err := os.Open(fp)
if err != nil {
return nil
}
defer file.Close()
// Garbage recycle var out []RoadTrace
if len(v.Traffic) > viper.GetInt("performance.traces_limit") { scanner := bufio.NewScanner(file)
clear(v.Traffic) for scanner.Scan() {
} line := scanner.Text()
if len(v.TrafficFrom) > viper.GetInt("performance.traces_limit") { var entry RoadTrace
clear(v.TrafficFrom) if err := jsoniter.Unmarshal([]byte(line), &entry); err == nil {
} out = append(out, entry)
if len(v.Traces) > viper.GetInt("performance.traces_limit") {
clear(v.Traces)
} }
} }
return out
}

View File

@ -10,5 +10,5 @@ func getTraffic(c *fiber.Ctx) error {
} }
func getTraces(c *fiber.Ctx) error { func getTraces(c *fiber.Ctx) error {
return c.JSON(navi.R.Metrics.Traces) return c.JSON(navi.R.Metrics.ReadTrace())
} }

View File

@ -1,11 +1,12 @@
package sideload package sideload
import ( import (
"time"
"git.solsynth.dev/goatworks/roadsign/pkg/navi" "git.solsynth.dev/goatworks/roadsign/pkg/navi"
"git.solsynth.dev/goatworks/roadsign/pkg/warden" "git.solsynth.dev/goatworks/roadsign/pkg/warden"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/samber/lo" "github.com/samber/lo"
"time"
) )
func getStats(c *fiber.Ctx) error { func getStats(c *fiber.Ctx) error {
@ -27,7 +28,6 @@ func getStats(c *fiber.Ctx) error {
"uptime": time.Since(navi.R.Metrics.StartupAt).Milliseconds(), "uptime": time.Since(navi.R.Metrics.StartupAt).Milliseconds(),
"traffic": fiber.Map{ "traffic": fiber.Map{
"total": navi.R.Metrics.TotalTraffic, "total": navi.R.Metrics.TotalTraffic,
"unique_client": len(navi.R.Metrics.TrafficFrom),
}, },
}) })
} }

View File

@ -21,6 +21,9 @@ force_https = false
max_body_size = 549_755_813_888 # 512 GiB max_body_size = 549_755_813_888 # 512 GiB
max_qps = -1 max_qps = -1
[logging]
access = "./logs/access.log"
[paths] [paths]
configs = "./config" configs = "./config"
@ -29,8 +32,7 @@ request_logging = true
capture_traces = true capture_traces = true
[performance] [performance]
low_memory = true low_memory = false
traces_limit = 256
prefork = false prefork = false
[security] [security]