Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Build and Release
on:
push:
branches:
- dev
- dev-oltp
paths:
- 'agent/**'
- 'dashboard/**'
Expand All @@ -13,7 +13,7 @@ on:
- 'v*'
pull_request:
branches:
- dev
- dev-oltp
workflow_dispatch:
inputs:
release_cli:
Expand All @@ -25,8 +25,8 @@ on:
env:
REGISTRY_GHCR: ghcr.io
REGISTRY_DOCKERHUB: docker.io
GO_VERSION: '1.22'
NODE_VERSION: '18'
GO_VERSION: '1.23'
NODE_VERSION: '20'

jobs:
# Build and push Agent Docker image
Expand Down Expand Up @@ -413,4 +413,4 @@ jobs:
echo "- [GitHub Packages](https://github.com/${{ github.repository }}/pkgs/container)" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.ref_type }}" == "tag" ]]; then
echo "- [Release Page](https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }})" >> $GITHUB_STEP_SUMMARY
fi
fi
20 changes: 20 additions & 0 deletions agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Server Configuration
PORT=5000

# Log Paths
TRAEFIK_LOG_DASHBOARD_ACCESS_PATH=/var/log/traefik/access.log
TRAEFIK_LOG_DASHBOARD_ERROR_PATH=/var/log/traefik/traefik.log

# Log Format (json or clf)
TRAEFIK_LOG_DASHBOARD_LOG_FORMAT=json

# System Monitoring
TRAEFIK_LOG_DASHBOARD_SYSTEM_MONITORING=true

# Authentication Token (required for production)
TRAEFIK_LOG_DASHBOARD_AUTH_TOKEN=your-secret-token-here

# GeoIP Configuration
TRAEFIK_LOG_DASHBOARD_GEOIP_ENABLED=true
TRAEFIK_LOG_DASHBOARD_GEOIP_CITY_DB=GeoLite2-City.mmdb
TRAEFIK_LOG_DASHBOARD_GEOIP_COUNTRY_DB=GeoLite2-Country.mmdb
2 changes: 1 addition & 1 deletion agent/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build stage
FROM golang:1.22-alpine AS builder
FROM golang:1.23-alpine AS builder

WORKDIR /app

Expand Down
25 changes: 25 additions & 0 deletions agent/cmd/agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/hhftechnology/traefik-log-dashboard/agent/internal/auth"
"github.com/hhftechnology/traefik-log-dashboard/agent/internal/config"
"github.com/hhftechnology/traefik-log-dashboard/agent/internal/routes"
"github.com/hhftechnology/traefik-log-dashboard/agent/pkg/location"
"github.com/hhftechnology/traefik-log-dashboard/agent/pkg/logger"
)

Expand All @@ -23,6 +24,26 @@ func main() {
logger.Log.Printf("System Monitoring: %v", cfg.SystemMonitoring)
logger.Log.Printf("Port: %s", cfg.Port)

// Initialize GeoIP location services if enabled
if cfg.GeoIPEnabled {
logger.Log.Printf("GeoIP: Enabled")
location.SetDatabasePaths(cfg.GeoIPCityDB, cfg.GeoIPCountryDB)

// Initialize location lookups
if err := location.InitializeLookups(); err != nil {
logger.Log.Printf("GeoIP: Failed to initialize (lookups will be unavailable): %v", err)
} else if location.LocationsEnabled() {
logger.Log.Printf("GeoIP: Successfully initialized")
} else {
logger.Log.Printf("GeoIP: No databases available (lookups will be unavailable)")
}

// Ensure cleanup on shutdown
defer location.Close()
} else {
logger.Log.Printf("GeoIP: Disabled")
}

// Initialize authentication
authenticator := auth.NewAuthenticator(cfg.AuthToken)
if authenticator.IsEnabled() {
Expand All @@ -49,6 +70,10 @@ func main() {
mux.HandleFunc("/api/system/logs", authenticator.Middleware(handler.HandleSystemLogs))
mux.HandleFunc("/api/system/resources", authenticator.Middleware(handler.HandleSystemResources))

// Location/GeoIP endpoints (with auth)
mux.HandleFunc("/api/location/lookup", authenticator.Middleware(handler.HandleLocationLookup))
mux.HandleFunc("/api/location/status", authenticator.Middleware(handler.HandleLocationStatus))

// Root endpoint
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
Expand Down
11 changes: 8 additions & 3 deletions agent/go.mod
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
module github.com/hhftechnology/traefik-log-dashboard/agent

go 1.22
go 1.23

require github.com/shirou/gopsutil/v3 v3.24.1
require (
github.com/joho/godotenv v1.5.1
github.com/oschwald/geoip2-golang v1.11.0
github.com/shirou/gopsutil/v3 v3.24.1
)

require (
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.13 // indirect
github.com/tklauser/numcpus v0.7.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/sys v0.21.0 // indirect
)
13 changes: 10 additions & 3 deletions agent/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNeKIkUct/gl9eod1TcXuj8stxvi/GoI=
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
Expand All @@ -27,8 +33,9 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
Expand All @@ -44,8 +51,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
57 changes: 18 additions & 39 deletions agent/internal/config/config.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package config

import (
"os"
"strconv"
"github.com/hhftechnology/traefik-log-dashboard/agent/internal/env"
)

// Config holds the application configuration
Expand All @@ -13,48 +12,28 @@ type Config struct {
SystemMonitoring bool
MonitorInterval int
Port string
LogFormat string
GeoIPEnabled bool
GeoIPCityDB string
GeoIPCountryDB string
}

// Load reads configuration from environment variables
// Load reads configuration from environment variables using the env package
func Load() *Config {
e := env.LoadEnv()

cfg := &Config{
AccessPath: getEnv("TRAEFIK_LOG_DASHBOARD_ACCESS_PATH", "/var/log/traefik/access.log"),
ErrorPath: getEnv("TRAEFIK_LOG_DASHBOARD_ERROR_PATH", "/var/log/traefik/traefik.log"),
AuthToken: getEnv("TRAEFIK_LOG_DASHBOARD_AUTH_TOKEN", ""),
SystemMonitoring: getEnvBool("TRAEFIK_LOG_DASHBOARD_SYSTEM_MONITORING", true),
MonitorInterval: getEnvInt("TRAEFIK_LOG_DASHBOARD_MONITOR_INTERVAL", 2000),
Port: getEnv("PORT", "5000"),
AccessPath: e.AccessPath,
ErrorPath: e.ErrorPath,
AuthToken: e.AuthToken,
SystemMonitoring: e.SystemMonitoring,
MonitorInterval: 2000, // Keep default for now
Port: e.Port,
LogFormat: e.LogFormat,
GeoIPEnabled: e.GeoIPEnabled,
GeoIPCityDB: e.GeoIPCityDB,
GeoIPCountryDB: e.GeoIPCountryDB,
}

return cfg
}

// getEnv retrieves an environment variable or returns a default value
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}

// getEnvBool retrieves a boolean environment variable or returns a default value
func getEnvBool(key string, defaultValue bool) bool {
if value := os.Getenv(key); value != "" {
boolValue, err := strconv.ParseBool(value)
if err == nil {
return boolValue
}
}
return defaultValue
}

// getEnvInt retrieves an integer environment variable or returns a default value
func getEnvInt(key string, defaultValue int) int {
if value := os.Getenv(key); value != "" {
intValue, err := strconv.Atoi(value)
if err == nil {
return intValue
}
}
return defaultValue
}
59 changes: 59 additions & 0 deletions agent/internal/env/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package env

import (
"os"

"github.com/joho/godotenv"
"github.com/hhftechnology/traefik-log-dashboard/agent/pkg/logger"
)

// Env holds environment variables for the agent
type Env struct {
Port string
AccessPath string
ErrorPath string
SystemMonitoring bool
AuthToken string
LogFormat string
GeoIPEnabled bool
GeoIPCityDB string
GeoIPCountryDB string
}

// LoadEnv loads environment variables from .env file if present
// and returns an Env struct with all configuration
func LoadEnv() Env {
// Load .env file if present
if err := godotenv.Load(); err != nil {
logger.Log.Println("No .env file found, using system environment variables")
}

return Env{
Port: getEnv("PORT", "5000"),
AccessPath: getEnv("TRAEFIK_LOG_DASHBOARD_ACCESS_PATH", "/var/log/traefik/access.log"),
ErrorPath: getEnv("TRAEFIK_LOG_DASHBOARD_ERROR_PATH", "/var/log/traefik/traefik.log"),
SystemMonitoring: getEnvBool("TRAEFIK_LOG_DASHBOARD_SYSTEM_MONITORING", true),
AuthToken: getEnv("TRAEFIK_LOG_DASHBOARD_AUTH_TOKEN", ""),
LogFormat: getEnv("TRAEFIK_LOG_DASHBOARD_LOG_FORMAT", "json"),
GeoIPEnabled: getEnvBool("TRAEFIK_LOG_DASHBOARD_GEOIP_ENABLED", true),
GeoIPCityDB: getEnv("TRAEFIK_LOG_DASHBOARD_GEOIP_CITY_DB", "GeoLite2-City.mmdb"),
GeoIPCountryDB: getEnv("TRAEFIK_LOG_DASHBOARD_GEOIP_COUNTRY_DB", "GeoLite2-Country.mmdb"),
}
}

// getEnv retrieves an environment variable or returns a default value
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}

// getEnvBool retrieves a boolean environment variable or returns a default value
func getEnvBool(key string, defaultValue bool) bool {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
return value == "true" || value == "1" || value == "yes"
}
Loading