mirror of
https://github.com/alm494/sql_proxy.git
synced 2025-10-08 22:01:51 +02:00
systemd support
This commit is contained in:
5
Makefile
5
Makefile
@@ -1,5 +1,5 @@
|
||||
PROJECT_NAME := sql-proxy
|
||||
BUILD_VERSION := 1.2.1
|
||||
BUILD_VERSION := 1.3.1
|
||||
BUILD_TIME := $(shell date -u '+%Y-%m-%d_%H:%M:%S')
|
||||
BUILD_DIR := build
|
||||
GO_FILES := src/main.go
|
||||
@@ -15,7 +15,6 @@ GOARCH := amd64
|
||||
GOAMD64 := v2
|
||||
|
||||
# Application settings to run:
|
||||
LOG_LEVEL := 6
|
||||
BIND_PORT := 8080
|
||||
BIND_ADDR := localhost
|
||||
MAX_ROWS := 10000
|
||||
@@ -50,7 +49,7 @@ debug: clean
|
||||
# Run
|
||||
run: debug
|
||||
@echo "Running $(PROJECT_NAME) in debug mode..."
|
||||
BIND_ADDR=$(BIND_ADDR) BIND_PORT=$(BIND_PORT) MAX_ROWS=$(MAX_ROWS) TLS_CERT=$(TLS_CERT) TLS_KEY=$(TLS_KEY) LOG_LEVEL=$(LOG_LEVEL) $(BUILD_DIR)/$(PROJECT_NAME)-debug
|
||||
BIND_ADDR=$(BIND_ADDR) BIND_PORT=$(BIND_PORT) MAX_ROWS=$(MAX_ROWS) TLS_CERT=$(TLS_CERT) TLS_KEY=$(TLS_KEY) $(BUILD_DIR)/$(PROJECT_NAME)-debug
|
||||
|
||||
# Run test
|
||||
test:
|
||||
|
26
go.mod
26
go.mod
@@ -1,19 +1,23 @@
|
||||
module sql-proxy
|
||||
|
||||
go 1.23.5
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/denisenkom/go-mssqldb v0.12.3
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/go-sql-driver/mysql v1.9.3
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/crypto v0.42.0
|
||||
)
|
||||
|
||||
require github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
require (
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/kardianos/service v1.2.4 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
@@ -22,11 +26,11 @@ require (
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/gorilla/sessions v1.4.0
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.66.1 // indirect
|
||||
github.com/prometheus/procfs v0.17.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
)
|
||||
|
24
go.sum
24
go.sum
@@ -14,6 +14,8 @@ github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDror
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
||||
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||
@@ -28,8 +30,12 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
||||
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
||||
github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk=
|
||||
github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
@@ -39,16 +45,26 @@ github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
|
||||
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
@@ -56,6 +72,8 @@ golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@@ -69,6 +87,10 @@ golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -77,6 +99,8 @@ google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNI
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
@@ -17,7 +17,7 @@ func GetEnvInt(key string, defaultValue int) int {
|
||||
if intValue, err := strconv.Atoi(value); err == nil {
|
||||
return intValue
|
||||
}
|
||||
Log.Errorf("Invalid integer value for %s, using default value: %d", key, defaultValue)
|
||||
Logger.Errorf("Invalid integer value for %s, using default value: %d", key, defaultValue)
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
@@ -1,14 +1,103 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/kardianos/service"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var Log = &logrus.Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: new(logrus.TextFormatter),
|
||||
Hooks: make(logrus.LevelHooks),
|
||||
Level: logrus.ErrorLevel,
|
||||
type LoggerInterface interface {
|
||||
Info(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// Global logger:
|
||||
var Logger LoggerInterface
|
||||
|
||||
// service logger:
|
||||
type ServiceLogger struct {
|
||||
Logger service.Logger
|
||||
}
|
||||
|
||||
func (s *ServiceLogger) Info(args ...interface{}) {
|
||||
s.Logger.Info(args...)
|
||||
}
|
||||
|
||||
func (s *ServiceLogger) Infof(format string, args ...interface{}) {
|
||||
s.Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (s *ServiceLogger) Error(args ...interface{}) {
|
||||
s.Logger.Error(args...)
|
||||
}
|
||||
|
||||
func (s *ServiceLogger) Errorf(format string, args ...interface{}) {
|
||||
s.Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (s *ServiceLogger) Warn(args ...interface{}) {
|
||||
s.Logger.Warning(args...)
|
||||
}
|
||||
|
||||
func (s *ServiceLogger) Warnf(format string, args ...interface{}) {
|
||||
s.Logger.Warningf(format, args...)
|
||||
}
|
||||
|
||||
// Console logger:
|
||||
|
||||
type ConsoleLogger struct {
|
||||
Logger *logrus.Logger
|
||||
}
|
||||
|
||||
func (c *ConsoleLogger) Info(args ...interface{}) {
|
||||
c.Logger.Info(args...)
|
||||
}
|
||||
|
||||
func (c *ConsoleLogger) Infof(format string, args ...interface{}) {
|
||||
c.Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (c *ConsoleLogger) Error(args ...interface{}) {
|
||||
c.Logger.Error(args...)
|
||||
}
|
||||
|
||||
func (c *ConsoleLogger) Errorf(format string, args ...interface{}) {
|
||||
c.Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (c *ConsoleLogger) Warn(args ...interface{}) {
|
||||
c.Logger.Warn(args...)
|
||||
}
|
||||
|
||||
func (c *ConsoleLogger) Warnf(format string, args ...interface{}) {
|
||||
c.Logger.Warnf(format, args...)
|
||||
}
|
||||
|
||||
// Create logger variants
|
||||
func NewConsoleLogger() *ConsoleLogger {
|
||||
l := logrus.New()
|
||||
l.SetOutput(io.Discard)
|
||||
l.SetFormatter(&logrus.TextFormatter{
|
||||
ForceColors: true,
|
||||
FullTimestamp: true,
|
||||
})
|
||||
l.SetLevel(logrus.InfoLevel)
|
||||
l.SetOutput(os.Stdout)
|
||||
|
||||
return &ConsoleLogger{Logger: l}
|
||||
}
|
||||
|
||||
func NewServiceLogger(svcLogger service.Logger) *ServiceLogger {
|
||||
return &ServiceLogger{Logger: svcLogger}
|
||||
}
|
||||
|
||||
// Init
|
||||
func InitLogger(logger LoggerInterface) {
|
||||
Logger = logger
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Init map
|
||||
@@ -41,7 +40,7 @@ func (o *DbList) GetById(id string, updateTimestamp bool) (*sql.DB, bool) {
|
||||
|
||||
o.mu.RUnlock()
|
||||
|
||||
app.Log.Errorf("SQL connection with guid='%s' not found", id)
|
||||
app.Logger.Errorf("SQL connection with guid='%s' not found", id)
|
||||
return nil, false
|
||||
|
||||
}
|
||||
@@ -52,7 +51,7 @@ func (o *DbList) GetByParams(connInfo *DbConnInfo) (string, bool) {
|
||||
hash, err := connInfo.GetHash()
|
||||
if err != nil {
|
||||
errMsg := "Hash calculation failed"
|
||||
app.Log.WithError(err).Error(errMsg)
|
||||
app.Logger.Error(errMsg)
|
||||
return errMsg, false
|
||||
}
|
||||
|
||||
@@ -65,7 +64,7 @@ func (o *DbList) GetByParams(connInfo *DbConnInfo) (string, bool) {
|
||||
// Search existing connection by hash to reuse
|
||||
if bytes.Equal(dbConn.Hash[:], hash[:]) {
|
||||
guid = key
|
||||
app.Log.Debugf("DB connection with id %s found in the pool", guid)
|
||||
app.Logger.Infof("DB connection with id %s found in the pool", guid)
|
||||
|
||||
// Perform checks
|
||||
if err = dbConn.DB.Ping(); err == nil {
|
||||
@@ -79,7 +78,7 @@ func (o *DbList) GetByParams(connInfo *DbConnInfo) (string, bool) {
|
||||
delete(o.items, guid)
|
||||
o.mu.Unlock()
|
||||
o.mu.RLock()
|
||||
app.Log.Debugf("DB connection with id %s is dead and removed from the pool", guid)
|
||||
app.Logger.Infof("DB connection with id %s is dead and removed from the pool", guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,7 +116,7 @@ func (o *DbList) getNewConnection(connInfo *DbConnInfo, hash [32]byte) (string,
|
||||
connInfo.User, encodedPassword, connInfo.Host, connInfo.Port, connInfo.DbName)
|
||||
default:
|
||||
errMsg := fmt.Sprintf("No suitable driver implemented for server type '%s'", connInfo.DbType)
|
||||
app.Log.Error(errMsg)
|
||||
app.Logger.Error(errMsg)
|
||||
return errMsg, false
|
||||
}
|
||||
|
||||
@@ -130,14 +129,14 @@ func (o *DbList) getNewConnection(connInfo *DbConnInfo, hash [32]byte) (string,
|
||||
// Check for failure
|
||||
if err != nil {
|
||||
errMsg := "Error establishing SQL server connection"
|
||||
app.Log.WithError(err).Error(errMsg)
|
||||
app.Logger.Error(errMsg)
|
||||
return errMsg, false
|
||||
}
|
||||
|
||||
// Check if alive
|
||||
if err = newDb.Ping(); err != nil {
|
||||
errMsg := "Just created SQL connection is dead"
|
||||
app.Log.WithError(err).Error(errMsg)
|
||||
app.Logger.Error(errMsg)
|
||||
return errMsg, false
|
||||
}
|
||||
|
||||
@@ -151,14 +150,16 @@ func (o *DbList) getNewConnection(connInfo *DbConnInfo, hash [32]byte) (string,
|
||||
|
||||
o.items[newId] = newItem
|
||||
|
||||
app.Log.WithFields(logrus.Fields{
|
||||
"Host": connInfo.Host,
|
||||
"Port": connInfo.Port,
|
||||
"dbName": connInfo.DbName,
|
||||
"user": connInfo.User,
|
||||
"dbType": connInfo.DbType,
|
||||
"Id": newId,
|
||||
}).Infof("New SQL connection with id %s was added to the pool", newId)
|
||||
app.Logger.Infof("New SQL connection with id %s was added to the pool: "+
|
||||
"Host=%s, Port=%d, dbName=%s, user=%s, dbType=%s, Id=%s",
|
||||
newId,
|
||||
connInfo.Host,
|
||||
connInfo.Port,
|
||||
connInfo.DbName,
|
||||
connInfo.User,
|
||||
connInfo.DbType,
|
||||
newId,
|
||||
)
|
||||
|
||||
return newId, true
|
||||
}
|
||||
@@ -169,7 +170,7 @@ func (o *DbList) Delete(id string) {
|
||||
defer o.mu.Unlock()
|
||||
|
||||
delete(o.items, id)
|
||||
app.Log.Debugf("DB connection with id %s was deleted by query", id)
|
||||
app.Logger.Infof("DB connection with id %s was deleted by query", id)
|
||||
|
||||
}
|
||||
|
||||
@@ -302,8 +303,8 @@ func (o *DbList) RunMaintenance() {
|
||||
|
||||
o.mu.Unlock()
|
||||
|
||||
app.Log.Debugf("Regular task: SQL connection pool size = %d", countConn)
|
||||
app.Log.Debugf("Regular task: %d dead connections removed", countDeadConn)
|
||||
app.Log.Debugf("Regular task: %d lost prepared statements removed", countStmt)
|
||||
app.Logger.Infof("Regular task: SQL connection pool size = %d", countConn)
|
||||
app.Logger.Infof("Regular task: %d dead connections removed", countDeadConn)
|
||||
app.Logger.Infof("Regular task: %d lost prepared statements removed", countStmt)
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ func checkApiVersion(w http.ResponseWriter, r *http.Request) bool {
|
||||
apiVersion := r.Header.Get("API-Version")
|
||||
if apiVersion != app.ApiVersion {
|
||||
message := "Unsupported API version"
|
||||
app.Log.Error(message)
|
||||
app.Logger.Error(message)
|
||||
http.Error(w, message, http.StatusNotImplemented)
|
||||
return false
|
||||
} else {
|
||||
@@ -33,7 +33,7 @@ func checkApiVersion(w http.ResponseWriter, r *http.Request) bool {
|
||||
|
||||
func errorResponce(w http.ResponseWriter, message string, httpStatus int) {
|
||||
|
||||
app.Log.Error(message)
|
||||
app.Logger.Error(message)
|
||||
http.Error(w, message, httpStatus)
|
||||
|
||||
}
|
||||
|
@@ -6,8 +6,6 @@ import (
|
||||
"net/http"
|
||||
"sql-proxy/src/app"
|
||||
"sql-proxy/src/db"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func PrepareStatement(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -108,10 +106,7 @@ func ClosePreparedStatement(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
app.Log.WithFields(logrus.Fields{
|
||||
"connection_id": connId,
|
||||
"prepared_statement": stmtId,
|
||||
}).Debug("Delete prepared statememt received:")
|
||||
app.Logger.Infof("Delete prepared statememt received: connection_id=%s, prepared_statement=%s", connId, stmtId)
|
||||
|
||||
if ok := db.Handler.ClosePreparedStatement(connId, stmtId); !ok {
|
||||
errorResponce(w, "Forbidden", http.StatusForbidden)
|
||||
@@ -131,10 +126,7 @@ func parsePrepareStatementHttpHeadersAndBody(w http.ResponseWriter, r *http.Requ
|
||||
defer r.Body.Close()
|
||||
|
||||
sqlQuery := string(body)
|
||||
app.Log.WithFields(logrus.Fields{
|
||||
"sql": sqlQuery,
|
||||
"connection_id": connId,
|
||||
}).Debug("Prepared statement received:")
|
||||
app.Logger.Infof("Prepared statement received: sql=%s, connection_id=%s", sqlQuery, connId)
|
||||
|
||||
return connId, sqlQuery, true
|
||||
|
||||
@@ -163,10 +155,7 @@ func parseExecuteStatementHttpHeadersAndBody(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
}
|
||||
|
||||
app.Log.WithFields(logrus.Fields{
|
||||
"connection_id": connId,
|
||||
"statement_id": stmtId,
|
||||
}).Debug("Execute prepared statement received:")
|
||||
app.Logger.Infof("Execute prepared statement received: connection_id=%s, statement_id=%s", connId, stmtId)
|
||||
|
||||
return connId, stmtId, params, true
|
||||
|
||||
|
@@ -6,8 +6,6 @@ import (
|
||||
|
||||
"sql-proxy/src/app"
|
||||
"sql-proxy/src/db"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func SelectQuery(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -74,10 +72,7 @@ func parseQueryHttpHeadersAndBody(w http.ResponseWriter, r *http.Request) (strin
|
||||
defer r.Body.Close()
|
||||
|
||||
sqlQuery := string(body)
|
||||
app.Log.WithFields(logrus.Fields{
|
||||
"sql": sqlQuery,
|
||||
"connection_id": connId,
|
||||
}).Debug("SQL query received:")
|
||||
app.Logger.Infof("SQL query received: sql=%s, connection_id=%s", sqlQuery, connId)
|
||||
|
||||
return connId, sqlQuery, true
|
||||
|
||||
|
130
src/main.go
130
src/main.go
@@ -1,23 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"sql-proxy/src/app"
|
||||
"sql-proxy/src/db"
|
||||
"sql-proxy/src/handlers"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/kardianos/service"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
var svcLogger service.Logger
|
||||
|
||||
type program struct {
|
||||
exit chan struct{}
|
||||
}
|
||||
|
||||
func (p *program) Start(s service.Service) error {
|
||||
app.Logger.Info("Starting sql-proxy service...")
|
||||
p.exit = make(chan struct{})
|
||||
go p.run()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *program) run() {
|
||||
|
||||
// Application params taken from OS environment
|
||||
app.Log.SetLevel(logrus.Level(app.GetEnvInt("LOG_LEVEL", 2)))
|
||||
bindAddress := app.GetEnvString("BIND_ADDR", "localhost")
|
||||
if bindAddress == "*" {
|
||||
bindAddress = ""
|
||||
@@ -47,26 +64,95 @@ func main() {
|
||||
router.HandleFunc("/livez", handlers.Livez).Methods("GET")
|
||||
router.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
app.Log.Info("(c) 2025 Almaz Sharipov, MIT license, https://github.com/alm494/sql_proxy")
|
||||
app.Log.WithFields(logrus.Fields{
|
||||
"build_version": app.BuildVersion,
|
||||
"build_time": app.BuildTime,
|
||||
}).Info("Starting server sql-proxy:")
|
||||
|
||||
app.Log.WithFields(logrus.Fields{
|
||||
"bind_port": bindPort,
|
||||
"bind_address": bindAddress,
|
||||
"tls_cert": tlsCert,
|
||||
"tls_key": tlsKey,
|
||||
}).Info("Server started with the following parameters:")
|
||||
app.Logger.Info("(c) 2025 Almaz Sharipov, MIT license, https://github.com/alm494/sql_proxy ")
|
||||
app.Logger.Infof("build_version=%s, build_time=%s", app.BuildVersion, app.BuildTime)
|
||||
app.Logger.Infof("Server started with the following parameters: "+
|
||||
"bind_port=%d, bind_address=%s, tls_cert=%s, tls_key=%s", bindPort, bindAddress, tlsCert, tlsKey)
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", bindAddress, bindPort)
|
||||
if len(tlsCert) > 0 && len(tlsKey) > 0 {
|
||||
err = http.ListenAndServeTLS(addr, tlsCert, tlsKey, router)
|
||||
} else {
|
||||
err = http.ListenAndServe(addr, router)
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: router,
|
||||
}
|
||||
if err != nil {
|
||||
app.Log.WithError(err).Fatal("Fatal error occurred, service stopped")
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
if len(tlsCert) > 0 && len(tlsKey) > 0 {
|
||||
err = srv.ListenAndServeTLS(tlsCert, tlsKey)
|
||||
} else {
|
||||
err = srv.ListenAndServe()
|
||||
}
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
app.Logger.Errorf("Fatal error occurred, service stopped: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for exit signal
|
||||
<-p.exit
|
||||
|
||||
// Shutdown server gracefully
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
app.Logger.Errorf("Server shutdown failed: %v", err)
|
||||
} else {
|
||||
app.Logger.Info("Server exited properly")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *program) Stop(s service.Service) error {
|
||||
app.Logger.Info("Stopping sql-proxy service...")
|
||||
close(p.exit)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
svcConfig := &service.Config{
|
||||
Name: "sql-proxy",
|
||||
DisplayName: "SQL Proxy Service",
|
||||
Description: "A lightweight REST service designed to replace ADODB calls in legacy software systems that support web requests",
|
||||
Arguments: []string{},
|
||||
}
|
||||
|
||||
prg := &program{}
|
||||
s, err := service.New(prg, svcConfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
svcLogger, err = s.Logger(nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
// Handle service commands: install, start, stop, uninstall
|
||||
err := service.Control(s, os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Run as a regular app
|
||||
if !service.Interactive() {
|
||||
app.InitLogger(app.NewServiceLogger(svcLogger))
|
||||
err = s.Run()
|
||||
if err != nil {
|
||||
svcLogger.Error(err)
|
||||
}
|
||||
} else {
|
||||
// Run in console mode
|
||||
app.InitLogger(app.NewConsoleLogger())
|
||||
fmt.Println("Running in console mode...")
|
||||
prg.Start(nil)
|
||||
|
||||
// Wait for interrupt signal
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigChan
|
||||
fmt.Println("Received interrupt signal, shutting down...")
|
||||
prg.Stop(nil)
|
||||
}
|
||||
}
|
||||
|
63
systemd/install.sh
Executable file
63
systemd/install.sh
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
SERVICE_USER="sql-proxy"
|
||||
SERVICE_GROUP="sql-proxy"
|
||||
SERVICE_DIR="/opt/sql-proxy"
|
||||
LOG_DIR="/var/log/sql-proxy"
|
||||
EXECUTABLE="sql-proxy"
|
||||
SERVICE_FILE="/etc/systemd/system/sql-proxy.service"
|
||||
|
||||
if ! id "$SERVICE_USER" &>/dev/null; then
|
||||
useradd --system --no-create-home --shell /bin/false "$SERVICE_USER"
|
||||
echo "User $SERVICE_USER created."
|
||||
else
|
||||
echo "User $SERVICE_USER already exists."
|
||||
fi
|
||||
|
||||
mkdir -p "$SERVICE_DIR"
|
||||
mkdir -p "$LOG_DIR"
|
||||
chown "$SERVICE_USER:$SERVICE_GROUP" "$SERVICE_DIR"
|
||||
chown "$SERVICE_USER:$SERVICE_GROUP" "$LOG_DIR"
|
||||
|
||||
cp "./$EXECUTABLE" "$SERVICE_DIR/"
|
||||
chown "$SERVICE_USER:$SERVICE_GROUP" "$SERVICE_DIR/$EXECUTABLE"
|
||||
chmod +x "$SERVICE_DIR/$EXECUTABLE"
|
||||
|
||||
cat > "$SERVICE_FILE" <<EOF
|
||||
[Unit]
|
||||
Description=SQL Proxy Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Environment="BIND_ADDR=127.0.0.1"
|
||||
Environment="BIND_PORT=8080"
|
||||
Environment="MAX_ROWS=10000"
|
||||
#Environment="TLS_CERT=/etc/ssl/certs/cert.pem"
|
||||
#Environment="TLS_KEY=/etc/ssl/private/key.pem"
|
||||
|
||||
Type=simple
|
||||
User=$SERVICE_USER
|
||||
Group=$SERVICE_GROUP
|
||||
WorkingDirectory=$SERVICE_DIR
|
||||
ExecStartPre=-/bin/mkdir -p $LOG_DIR
|
||||
ExecStartPre=-/bin/chown $SERVICE_USER:$SERVICE_GROUP $LOG_DIR
|
||||
ExecStart=$SERVICE_DIR/$EXECUTABLE
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable sql-proxy --now
|
||||
|
||||
if systemctl is-active --quiet sql-proxy; then
|
||||
echo "Service is running. Restarting..."
|
||||
systemctl restart sql-proxy
|
||||
else
|
||||
echo "Starting sql-proxy service..."
|
||||
systemctl start sql-proxy
|
||||
fi
|
||||
|
||||
echo "SQL Proxy service installed and running."
|
Reference in New Issue
Block a user