♻️ Refactored tracing system to cost less memory
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,6 @@ | |||||||
| /letsencrypt | /letsencrypt | ||||||
| /certs | /certs | ||||||
| /dist | /dist | ||||||
|  | /logs | ||||||
|  |  | ||||||
| .DS_Store | .DS_Store | ||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -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= | ||||||
|   | |||||||
| @@ -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.") | ||||||
| @@ -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
									
								
							
							
						
						
									
										20
									
								
								pkg/navi/logging.go
									
									
									
									
									
										Normal 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) | ||||||
|  | } | ||||||
| @@ -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 | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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()) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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), |  | ||||||
| 		}, | 		}, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user