Transition to new logger

This commit is contained in:
Melon 2024-05-13 19:33:33 +01:00
parent a8db73d957
commit 1f4f4414d5
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
17 changed files with 161 additions and 95 deletions

View File

@ -4,11 +4,11 @@ import (
"crypto/tls"
"crypto/x509/pkix"
"fmt"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/utils"
"github.com/mrmelon54/certgen"
"github.com/mrmelon54/rescheduler"
"io/fs"
"log"
"math/big"
"os"
"strings"
@ -17,6 +17,8 @@ import (
"time"
)
var Logger = logger.Logger.WithPrefix("Violet Certs")
// Certs is the certificate loader and management system.
type Certs struct {
cDir fs.FS
@ -69,7 +71,7 @@ func New(certDir fs.FS, keyDir fs.FS, selfCert bool) *Certs {
return now.AddDate(10, 0, 0)
})
if err != nil {
log.Fatalln("Failed to generate CA cert for self-signed mode:", err)
logger.Logger.Fatal("Failed to generate CA cert for self-signed mode", "err", err)
}
c.ca = ca
}
@ -145,7 +147,7 @@ func (c *Certs) threadCompile() {
// compile map and check errors
err := c.internalCompile(certMap)
if err != nil {
log.Printf("[Certs] Compile failed: %s\n", err)
Logger.Infof("Compile failed: %s\n", err)
return
}
@ -168,7 +170,7 @@ func (c *Certs) internalCompile(m map[string]*tls.Certificate) error {
return fmt.Errorf("failed to read cert dir: %w", err)
}
log.Printf("[Certs] Compiling lookup table for %d certificates\n", len(files))
Logger.Infof("Compiling lookup table for %d certificates\n", len(files))
// find and parse certs
for _, i := range files {

View File

@ -10,6 +10,7 @@ import (
"github.com/1f349/violet/domains"
errorPages "github.com/1f349/violet/error-pages"
"github.com/1f349/violet/favicons"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy"
"github.com/1f349/violet/proxy/websocket"
"github.com/1f349/violet/router"
@ -17,12 +18,11 @@ import (
"github.com/1f349/violet/servers/api"
"github.com/1f349/violet/servers/conf"
"github.com/1f349/violet/utils"
"github.com/mrmelon54/exit-reload"
"github.com/google/subcommands"
"github.com/mrmelon54/exit-reload"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"io/fs"
"log"
"net/http"
"os"
"path/filepath"
@ -45,19 +45,19 @@ func (s *serveCmd) Usage() string {
}
func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
log.Println("[Violet] Starting...")
logger.Logger.Info("Starting...")
if s.configPath == "" {
log.Println("[Violet] Error: config flag is missing")
logger.Logger.Info("Error: config flag is missing")
return subcommands.ExitUsageError
}
openConf, err := os.Open(s.configPath)
if err != nil {
if os.IsNotExist(err) {
log.Println("[Violet] Error: missing config file")
logger.Logger.Info("Error: missing config file")
} else {
log.Println("[Violet] Error: open config file: ", err)
logger.Logger.Info("Error: open config file: ", err)
}
return subcommands.ExitFailure
}
@ -65,7 +65,7 @@ func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
var config startUpConfig
err = json.NewDecoder(openConf).Decode(&config)
if err != nil {
log.Println("[Violet] Error: invalid config file: ", err)
logger.Logger.Info("Error: invalid config file: ", err)
return subcommands.ExitFailure
}
@ -81,12 +81,12 @@ func normalLoad(startUp startUpConfig, wd string) {
// create path to cert dir
err := os.MkdirAll(filepath.Join(wd, "certs"), os.ModePerm)
if err != nil {
log.Fatal("[Violet] Failed to create certificate path")
logger.Logger.Fatal("Failed to create certificate path")
}
// create path to key dir
err = os.MkdirAll(filepath.Join(wd, "keys"), os.ModePerm)
if err != nil {
log.Fatal("[Violet] Failed to create certificate key path")
logger.Logger.Fatal("Failed to create certificate key path")
}
}
@ -96,20 +96,20 @@ func normalLoad(startUp startUpConfig, wd string) {
errorPageDir = os.DirFS(startUp.ErrorPagePath)
err := os.MkdirAll(startUp.ErrorPagePath, os.ModePerm)
if err != nil {
log.Fatalf("[Violet] Failed to create error page path '%s'", startUp.ErrorPagePath)
logger.Logger.Fatal("Failed to create error page", "path", startUp.ErrorPagePath)
}
}
// load the MJWT RSA public key from a pem encoded file
mJwtVerify, err := mjwt.NewMJwtVerifierFromFile(filepath.Join(wd, "signer.public.pem"))
if err != nil {
log.Fatalf("[Violet] Failed to load MJWT verifier public key from file '%s': %s", filepath.Join(wd, "signer.public.pem"), err)
logger.Logger.Fatal("Failed to load MJWT verifier public key", "file", filepath.Join(wd, "signer.public.pem"), "err", err)
}
// open sqlite database
db, err := violet.InitDB(filepath.Join(wd, "violet.db.sqlite"))
if err != nil {
log.Fatal("[Violet] Failed to open database")
logger.Logger.Fatal("Failed to open database", "err", err)
}
certDir := os.DirFS(filepath.Join(wd, "certs"))
@ -155,20 +155,23 @@ func normalLoad(startUp startUpConfig, wd string) {
if srvConf.ApiListen != "" {
srvApi = api.NewApiServer(srvConf, allCompilables, promRegistry)
srvApi.SetKeepAlivesEnabled(false)
log.Printf("[API] Starting API server on: '%s'\n", srvApi.Addr)
go utils.RunBackgroundHttp("API", srvApi)
l := logger.Logger.With("server", "API")
l.Info("Starting server", "addr", srvApi.Addr)
go utils.RunBackgroundHttp(l, srvApi)
}
if srvConf.HttpListen != "" {
srvHttp = servers.NewHttpServer(srvConf, promRegistry)
srvHttp.SetKeepAlivesEnabled(false)
log.Printf("[HTTP] Starting HTTP server on: '%s'\n", srvHttp.Addr)
go utils.RunBackgroundHttp("HTTP", srvHttp)
l := logger.Logger.With("server", "HTTP")
l.Info("Starting server", "addr", srvHttp.Addr)
go utils.RunBackgroundHttp(l, srvHttp)
}
if srvConf.HttpsListen != "" {
srvHttps = servers.NewHttpsServer(srvConf, promRegistry)
srvHttps.SetKeepAlivesEnabled(false)
log.Printf("[HTTPS] Starting HTTPS server on: '%s'\n", srvHttps.Addr)
go utils.RunBackgroundHttps("HTTPS", srvHttps)
l := logger.Logger.With("server", "HTTPS")
l.Info("Starting server", "addr", srvHttps.Addr)
go utils.RunBackgroundHttps(l, srvHttps)
}
exit_reload.ExitReload("Violet", func() {

View File

@ -7,13 +7,13 @@ import (
"fmt"
"github.com/1f349/violet"
"github.com/1f349/violet/domains"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy"
"github.com/1f349/violet/proxy/websocket"
"github.com/1f349/violet/router"
"github.com/1f349/violet/target"
"github.com/AlecAivazis/survey/v2"
"github.com/google/subcommands"
"log"
"net"
"net/http"
"net/url"
@ -42,7 +42,7 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
// get absolute path to specify files
wdAbs, err := filepath.Abs(s.wdPath)
if err != nil {
fmt.Println("[Violet] Failed to get full directory path: ", err)
fmt.Println("Failed to get full directory path: ", err)
return subcommands.ExitFailure
}
@ -50,11 +50,11 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
createFile := false
err = survey.AskOne(&survey.Confirm{Message: fmt.Sprintf("Create Violet config files in this directory: '%s'?", wdAbs)}, &createFile)
if err != nil {
fmt.Println("[Violet] Error: ", err)
fmt.Println("Error: ", err)
return subcommands.ExitFailure
}
if !createFile {
fmt.Println("[Violet] Goodbye")
fmt.Println("Goodbye")
return subcommands.ExitSuccess
}
@ -111,7 +111,7 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
},
}, &answers)
if err != nil {
fmt.Println("[Violet] Error: ", err)
fmt.Println("Error: ", err)
return subcommands.ExitFailure
}
@ -142,14 +142,14 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
RateLimit: answers.RateLimit,
})
if err != nil {
fmt.Println("[Violet] Failed to write config file: ", err)
fmt.Println("Failed to write config file: ", err)
return subcommands.ExitFailure
}
// open sqlite database
db, err := violet.InitDB(databaseFile)
if err != nil {
log.Fatalf("[Violet] Failed to open database '%s'...", databaseFile)
logger.Logger.Fatal("Failed to open database", "err", err)
}
// domain manager to add a domain, no need to compile here as the program needs
@ -168,14 +168,14 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
return nil
}))
if err != nil {
fmt.Println("[Violet] Error: ", err)
fmt.Println("Error: ", err)
return subcommands.ExitFailure
}
// parse the api url
apiUrl, err := url.Parse(answers.ApiUrl)
if err != nil {
fmt.Println("[Violet] Failed to parse API URL: ", err)
fmt.Println("Failed to parse API URL: ", err)
return subcommands.ExitFailure
}
@ -191,13 +191,13 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
Active: true,
})
if err != nil {
fmt.Println("[Violet] Failed to insert api route into database: ", err)
fmt.Println("Failed to insert api route into database: ", err)
return subcommands.ExitFailure
}
}
fmt.Println("[Violet] Setup complete")
fmt.Printf("[Violet] Run the reverse proxy with `violet serve -conf %s`\n", confFile)
fmt.Println("Setup complete")
fmt.Printf("Run the reverse proxy with `violet serve -conf %s`\n", confFile)
return subcommands.ExitSuccess
}

View File

@ -4,13 +4,15 @@ import (
"context"
_ "embed"
"github.com/1f349/violet/database"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/utils"
"github.com/mrmelon54/rescheduler"
"log"
"strings"
"sync"
)
var Logger = logger.Logger.WithPrefix("Violet Domains")
// Domains is the domain list and management system.
type Domains struct {
db *database.Queries
@ -68,7 +70,7 @@ func (d *Domains) threadCompile() {
// compile map and check errors
err := d.internalCompile(domainMap)
if err != nil {
log.Printf("[Domains] Compile failed: %s\n", err)
Logger.Info("Compile faile", "err", err)
return
}
@ -81,7 +83,7 @@ func (d *Domains) threadCompile() {
// internalCompile is a hidden internal method for querying the database during
// the Compile() method.
func (d *Domains) internalCompile(m map[string]struct{}) error {
log.Println("[Domains] Updating domains from database")
Logger.Info("Updating domains from database")
// sql or something?
rows, err := d.db.GetActiveDomains(context.Background())
@ -105,7 +107,7 @@ func (d *Domains) Put(domain string, active bool) {
Active: active,
})
if err != nil {
log.Printf("[Violet] Database error: %s\n", err)
logger.Logger.Infof("Database error: %s\n", err)
}
}
@ -114,6 +116,6 @@ func (d *Domains) Delete(domain string) {
defer d.s.Unlock()
err := d.db.DeleteDomain(context.Background(), domain)
if err != nil {
log.Printf("[Violet] Database error: %s\n", err)
logger.Logger.Infof("Database error: %s\n", err)
}
}

View File

@ -2,9 +2,9 @@ package error_pages
import (
"fmt"
"github.com/1f349/violet/logger"
"github.com/mrmelon54/rescheduler"
"io/fs"
"log"
"net/http"
"path/filepath"
"strconv"
@ -12,6 +12,8 @@ import (
"sync"
)
var Logger = logger.Logger.WithPrefix("Violet Error Pages")
// ErrorPages stores the custom error pages and is called by the servers to
// output meaningful pages for HTTP error codes
type ErrorPages struct {
@ -78,7 +80,7 @@ func (e *ErrorPages) threadCompile() {
if e.dir != nil {
err := e.internalCompile(errorPageMap)
if err != nil {
log.Printf("[ErrorPages] Compile failed: %s\n", err)
Logger.Info("Compile failed", "err", err)
return
}
}
@ -96,7 +98,7 @@ func (e *ErrorPages) internalCompile(m map[int]func(rw http.ResponseWriter)) err
return fmt.Errorf("failed to read error pages dir: %w", err)
}
log.Printf("[ErrorPages] Compiling lookup table for %d error pages\n", len(files))
Logger.Info("Compiling lookup table", "page count", len(files))
// find and load error pages
for _, i := range files {
@ -111,20 +113,20 @@ func (e *ErrorPages) internalCompile(m map[int]func(rw http.ResponseWriter)) err
// if the extension is not 'html' then ignore the file
if ext != ".html" {
log.Printf("[ErrorPages] WARNING: ignoring non '.html' file in error pages directory: '%s'\n", name)
Logger.Warn("Ignoring non '.html' file in error pages directory", "name", name)
continue
}
// if the name can't be
nameInt, err := strconv.Atoi(strings.TrimSuffix(name, ".html"))
if err != nil {
log.Printf("[ErrorPages] WARNING: ignoring invalid error page in error pages directory: '%s'\n", name)
Logger.Warn("Ignoring invalid error page in error pages directory", "name", name)
continue
}
// check if code is in range 100-599
if nameInt < 100 || nameInt >= 600 {
log.Printf("[ErrorPages] WARNING: ignoring invalid error page in error pages directory must be 100-599: '%s'\n", name)
Logger.Warn("Ignoring invalid error page in error pages directory must be 100-599", "name", name)
continue
}

View File

@ -74,7 +74,7 @@ func (l *FaviconList) PreProcess(convert func(in []byte) ([]byte, error)) error
// download SVG
l.Svg.Raw, err = getFaviconViaRequest(l.Svg.Url)
if err != nil {
return fmt.Errorf("[Favicons] Failed to fetch SVG icon: %w", err)
return fmt.Errorf("favicons: failed to fetch SVG icon: %w", err)
}
l.Svg.Hash = hex.EncodeToString(sha256.New().Sum(l.Svg.Raw))
}
@ -84,14 +84,14 @@ func (l *FaviconList) PreProcess(convert func(in []byte) ([]byte, error)) error
// download PNG
l.Png.Raw, err = getFaviconViaRequest(l.Png.Url)
if err != nil {
return fmt.Errorf("[Favicons] Failed to fetch PNG icon: %w", err)
return fmt.Errorf("favicons: failed to fetch PNG icon: %w", err)
}
} else if l.Svg != nil {
// generate PNG from SVG
l.Png = &FaviconImage{}
l.Png.Raw, err = convert(l.Svg.Raw)
if err != nil {
return fmt.Errorf("[Favicons] Failed to generate PNG icon: %w", err)
return fmt.Errorf("favicons: failed to generate PNG icon: %w", err)
}
}
@ -100,19 +100,19 @@ func (l *FaviconList) PreProcess(convert func(in []byte) ([]byte, error)) error
// download ICO
l.Ico.Raw, err = getFaviconViaRequest(l.Ico.Url)
if err != nil {
return fmt.Errorf("[Favicons] Failed to fetch ICO icon: %w", err)
return fmt.Errorf("favicons: failed to fetch ICO icon: %w", err)
}
} else if l.Png != nil {
// generate ICO from PNG
l.Ico = &FaviconImage{}
decode, err := png.Decode(bytes.NewReader(l.Png.Raw))
if err != nil {
return fmt.Errorf("[Favicons] Failed to decode PNG icon: %w", err)
return fmt.Errorf("favicons: failed to decode PNG icon: %w", err)
}
b := decode.Bounds()
l.Ico.Raw, err = png2ico.ConvertPngToIco(l.Png.Raw, b.Dx(), b.Dy())
if err != nil {
return fmt.Errorf("[Favicons] Failed to generate ICO icon: %w", err)
return fmt.Errorf("favicons: failed to generate ICO icon: %w", err)
}
}
@ -139,16 +139,16 @@ func (l *FaviconList) genSha256() {
var getFaviconViaRequest = func(url string) ([]byte, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, fmt.Errorf("[Favicons] Failed to send request '%s': %w", url, err)
return nil, fmt.Errorf("favicons: Failed to send request '%s': %w", url, err)
}
req.Header.Set("X-Violet-Raw-Favicon", "1")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("[Favicons] Failed to do request '%s': %w", url, err)
return nil, fmt.Errorf("favicons: failed to do request '%s': %w", url, err)
}
rawBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[Favicons] Failed to read response '%s': %w", url, err)
return nil, fmt.Errorf("favicons: failed to read response '%s': %w", url, err)
}
return rawBody, nil
}

View File

@ -6,12 +6,14 @@ import (
"errors"
"fmt"
"github.com/1f349/violet/database"
"github.com/1f349/violet/logger"
"github.com/mrmelon54/rescheduler"
"golang.org/x/sync/errgroup"
"log"
"sync"
)
var Logger = logger.Logger.WithPrefix("Violet Favicons")
var ErrFaviconNotFound = errors.New("favicon not found")
// Favicons is a dynamic favicon generator which supports overwriting favicons
@ -66,7 +68,7 @@ func (f *Favicons) threadCompile() {
err := f.internalCompile(favicons)
if err != nil {
// log compile errors
log.Printf("[Favicons] Compile failed: %s\n", err)
Logger.Info("Compile failed", "err", err)
return
}

10
go.mod
View File

@ -5,6 +5,7 @@ go 1.22
require (
github.com/1f349/mjwt v0.2.5
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/charmbracelet/log v0.4.0
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/google/subcommands v1.2.0
github.com/google/uuid v1.6.0
@ -25,25 +26,34 @@ require (
)
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/lipgloss v0.10.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.53.0 // indirect
github.com/prometheus/procfs v0.14.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect

23
go.sum
View File

@ -4,18 +4,26 @@ github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkk
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA=
github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
@ -45,6 +53,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@ -52,6 +62,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@ -67,6 +80,10 @@ github.com/mrmelon54/rescheduler v0.0.3 h1:TrkJL6S7PKvXuo1mvdgRgsILA/pk5L1lrXhV/
github.com/mrmelon54/rescheduler v0.0.3/go.mod h1:q415n6W1xcePPP5Rix6FOiADgcN66BYMyNOsFnNyoWQ=
github.com/mrmelon54/trie v0.0.3 h1:wZmws84FiGNBZJ00garLyQ2EQhtx0SipVoV7fK8+kZE=
github.com/mrmelon54/trie v0.0.3/go.mod h1:d3hl0YUBSWR3XN4S9BDLkGVzLT4VgwP2mZkBJM6uFpw=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -79,6 +96,10 @@ github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+a
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s=
github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
@ -94,6 +115,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=

12
logger/logger.go Normal file
View File

@ -0,0 +1,12 @@
package logger
import (
"github.com/charmbracelet/log"
"os"
)
var Logger = log.NewWithOptions(os.Stderr, log.Options{
ReportCaller: true,
ReportTimestamp: true,
Prefix: "Violet",
})

View File

@ -2,15 +2,19 @@ package proxy
import (
"crypto/tls"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy/websocket"
"github.com/google/uuid"
"log"
"net"
"net/http"
"sync"
"time"
)
var loggerSecure = logger.Logger.WithPrefix("Violet Secure Transport")
var loggerInsecure = logger.Logger.WithPrefix("Violet Insecure Transport")
var loggerWebsocket = logger.Logger.WithPrefix("Violet Websocket Transport")
type HybridTransport struct {
baseDialer *net.Dialer
normalTransport http.RoundTripper
@ -72,23 +76,23 @@ func NewHybridTransportWithCalls(normal, insecure http.RoundTripper, ws *websock
// SecureRoundTrip calls the secure transport
func (h *HybridTransport) SecureRoundTrip(req *http.Request) (*http.Response, error) {
u := uuid.New()
log.Println("[Transport] Start upgrade:", u)
defer log.Println("[Transport] Stop upgrade:", u)
loggerSecure.Info("Start upgrade", "id", u)
defer loggerSecure.Info("Stop upgrade", "id", u)
return h.normalTransport.RoundTrip(req)
}
// InsecureRoundTrip calls the insecure transport
func (h *HybridTransport) InsecureRoundTrip(req *http.Request) (*http.Response, error) {
u := uuid.New()
log.Println("[Transport insecure] Start upgrade:", u)
defer log.Println("[Transport insecure] Stop upgrade:", u)
loggerInsecure.Info("Start upgrade", "id", u)
defer loggerInsecure.Info("Stop upgrade", "id", u)
return h.insecureTransport.RoundTrip(req)
}
// ConnectWebsocket calls the websocket upgrader and thus hijacks the connection
func (h *HybridTransport) ConnectWebsocket(rw http.ResponseWriter, req *http.Request) {
u := uuid.New()
log.Println("[Websocket] Start upgrade:", u)
loggerWebsocket.Info("Start upgrade", "id", u)
h.ws.Upgrade(rw, req)
log.Println("[Websocket] Stop upgrade:", u)
loggerWebsocket.Info("Stop upgrade", "id", u)
}

View File

@ -1,13 +1,15 @@
package websocket
import (
"github.com/1f349/violet/logger"
"github.com/gorilla/websocket"
"log"
"net/http"
"sync"
"time"
)
var Logger = logger.Logger.WithPrefix("Violet Websocket")
var upgrader = websocket.Upgrader{
HandshakeTimeout: time.Second * 5,
ReadBufferSize: 1024,
@ -34,7 +36,7 @@ func NewServer() *Server {
func (s *Server) Upgrade(rw http.ResponseWriter, req *http.Request) {
req.URL.Scheme = "ws"
log.Printf("[Websocket] Upgrading request to '%s' from '%s'\n", req.URL.String(), req.Header.Get("Origin"))
Logger.Info("Upgrading request", "url", req.URL, "origin", req.Header.Get("Origin"))
c, err := upgrader.Upgrade(rw, req, nil)
if err != nil {
@ -54,12 +56,12 @@ func (s *Server) Upgrade(rw http.ResponseWriter, req *http.Request) {
s.conns[c.RemoteAddr().String()] = c
s.connLock.Unlock()
log.Printf("[Websocket] Dialing: '%s'\n", req.URL.String())
Logger.Info("Dialing", "url", req.URL)
// dial for internal connection
ic, _, err := websocket.DefaultDialer.DialContext(req.Context(), req.URL.String(), nil)
if err != nil {
log.Printf("[Websocket] Failed to dial '%s': %s\n", req.URL.String(), err)
Logger.Info("Failed to dial", "url", req.URL, "err", err)
s.Remove(c)
return
}
@ -73,7 +75,7 @@ func (s *Server) Upgrade(rw http.ResponseWriter, req *http.Request) {
go s.wsRelay(d2, ic, c)
// wait for done signal and close both connections
log.Println("[Websocket] Completed websocket hijacking")
Logger.Info("Completed websocket hijacking")
// waiting until d1 or d2 close then automatically defer close both connections
select {
@ -89,7 +91,7 @@ func (s *Server) wsRelay(done chan struct{}, a, b *websocket.Conn) {
for {
mt, message, err := a.ReadMessage()
if err != nil {
log.Println("Websocket read message error: ", err)
Logger.Info("Read message", "err", err)
return
}
if b.WriteMessage(mt, message) != nil {

View File

@ -4,15 +4,17 @@ import (
"context"
_ "embed"
"github.com/1f349/violet/database"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy"
"github.com/1f349/violet/target"
"github.com/mrmelon54/rescheduler"
"log"
"net/http"
"strings"
"sync"
)
var Logger = logger.Logger.WithPrefix("Violet Manager")
// Manager is a database and mutex wrap around router allowing it to be
// dynamically regenerated after updating the database of routes.
type Manager struct {
@ -54,7 +56,7 @@ func (m *Manager) threadCompile() {
// compile router and check errors
err := m.internalCompile(router)
if err != nil {
log.Printf("[Manager] Compile failed: %s\n", err)
Logger.Info("Compile failed", "err", err)
return
}
@ -67,7 +69,7 @@ func (m *Manager) threadCompile() {
// internalCompile is a hidden internal method for querying the database during
// the Compile() method.
func (m *Manager) internalCompile(router *Router) error {
log.Println("[Manager] Updating routes from database")
Logger.Info("Updating routes from database")
// sql or something?
routeRows, err := m.db.GetActiveRoutes(context.Background())

View File

@ -3,11 +3,11 @@ package api
import (
"encoding/json"
"github.com/1f349/mjwt"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/router"
"github.com/1f349/violet/target"
"github.com/1f349/violet/utils"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
"strings"
)
@ -19,7 +19,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
routes, err := manager.GetAllRoutes(domains)
if err != nil {
log.Printf("[Violet] Failed to get routes from database: %s\n", err)
logger.Logger.Infof("Failed to get routes from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to get routes from database")
return
}
@ -29,7 +29,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.POST("/route", parseJsonAndCheckOwnership[routeSource](verify, "route", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t routeSource) {
err := manager.InsertRoute(target.RouteWithActive(t))
if err != nil {
log.Printf("[Violet] Failed to insert route into database: %s\n", err)
logger.Logger.Infof("Failed to insert route into database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to insert route into database")
return
}
@ -38,7 +38,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.DELETE("/route", parseJsonAndCheckOwnership[sourceJson](verify, "route", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t sourceJson) {
err := manager.DeleteRoute(t.Src)
if err != nil {
log.Printf("[Violet] Failed to delete route from database: %s\n", err)
logger.Logger.Infof("Failed to delete route from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to delete route from database")
return
}
@ -51,7 +51,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
redirects, err := manager.GetAllRedirects(domains)
if err != nil {
log.Printf("[Violet] Failed to get redirects from database: %s\n", err)
logger.Logger.Infof("Failed to get redirects from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to get redirects from database")
return
}
@ -61,7 +61,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.POST("/redirect", parseJsonAndCheckOwnership[redirectSource](verify, "redirect", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t redirectSource) {
err := manager.InsertRedirect(target.RedirectWithActive(t))
if err != nil {
log.Printf("[Violet] Failed to insert redirect into database: %s\n", err)
logger.Logger.Infof("Failed to insert redirect into database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to insert redirect into database")
return
}
@ -70,7 +70,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.DELETE("/redirect", parseJsonAndCheckOwnership[sourceJson](verify, "redirect", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t sourceJson) {
err := manager.DeleteRedirect(t.Src)
if err != nil {
log.Printf("[Violet] Failed to delete redirect from database: %s\n", err)
logger.Logger.Infof("Failed to delete redirect from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to delete redirect from database")
return
}

View File

@ -4,13 +4,13 @@ import (
"crypto/tls"
"fmt"
"github.com/1f349/violet/favicons"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/servers/conf"
"github.com/1f349/violet/servers/metrics"
"github.com/1f349/violet/utils"
"github.com/prometheus/client_golang/prometheus"
"github.com/sethvargo/go-limiter/httplimit"
"github.com/sethvargo/go-limiter/memorystore"
"log"
"net/http"
"path"
"runtime"
@ -21,7 +21,7 @@ import (
// endpoints for the reverse proxy.
func NewHttpsServer(conf *conf.Conf, registry *prometheus.Registry) *http.Server {
r := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
log.Printf("[Debug] Request: %s - '%s' - '%s' - '%s' - len: %d - thread: %d\n", req.Method, req.URL.String(), req.RemoteAddr, req.Host, req.ContentLength, runtime.NumGoroutine())
logger.Logger.Debug("Request", "method", req.Method, "url", req.URL, "remote", req.RemoteAddr, "host", req.Host, "length", req.ContentLength, "goroutine", runtime.NumGoroutine())
conf.Router.ServeHTTP(rw, req)
})
favMiddleware := setupFaviconMiddleware(conf.Favicons, r)
@ -88,13 +88,13 @@ func setupRateLimiter(rateLimit uint64, next http.Handler) http.Handler {
Interval: time.Minute,
})
if err != nil {
log.Fatalln(err)
logger.Logger.Fatal("Failed to initialize memory store", "err", err)
}
// create a middleware using ips as the key for rate limits
middleware, err := httplimit.NewMiddleware(store, httplimit.IPKeyFunc())
if err != nil {
log.Fatalln(err)
logger.Logger.Fatal("Failed to initialize httplimit middleware", "err", err)
}
return middleware.Handle(next)
}

View File

@ -2,6 +2,7 @@ package target
import (
"fmt"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy"
"github.com/1f349/violet/utils"
"github.com/google/uuid"
@ -9,7 +10,6 @@ import (
"github.com/rs/cors"
"golang.org/x/net/http/httpguts"
"io"
"log"
"net"
"net/http"
"net/textproto"
@ -18,6 +18,8 @@ import (
"strings"
)
var Logger = logger.Logger.WithPrefix("Violet Serve Route")
// serveApiCors outputs the cors headers to make APIs work.
var serveApiCors = cors.New(cors.Options{
// allow all origins for api requests
@ -128,7 +130,7 @@ func (r Route) internalServeHTTP(rw http.ResponseWriter, req *http.Request) {
// create the internal request
req2, err := http.NewRequest(req.Method, u.String(), req.Body)
if err != nil {
log.Printf("[ServeRoute::ServeHTTP()] Error generating new request: %s\n", err)
Logger.Warn("Error generating new request", "err", err)
utils.RespondVioletError(rw, http.StatusBadGateway, "error generating new request")
return
}
@ -179,7 +181,7 @@ func (r Route) internalServeHTTP(rw http.ResponseWriter, req *http.Request) {
resp, err = r.Proxy.SecureRoundTrip(req2)
}
if err != nil {
log.Printf("[ServeRoute::ServeHTTP()] Error receiving internal round trip response: %s\n", err)
Logger.Warn("Error receiving internal round trip response", "err", err)
utils.RespondVioletError(rw, http.StatusBadGateway, "error receiving internal round trip response")
return
}
@ -191,7 +193,7 @@ func (r Route) internalServeHTTP(rw http.ResponseWriter, req *http.Request) {
if resp.StatusCode == http.StatusLoopDetected {
u := uuid.New()
log.Printf("[ServeRoute::ServeHTTP()] Loop Detected: %s %s '%s' -> '%s'\n", u, req.Method, req.URL.String(), req2.URL.String())
Logger.Warn("Loop Detected", "id", u, "method", req.Method, "url", req.URL, "url2", req2.URL.String())
utils.RespondVioletError(rw, http.StatusLoopDetected, "error loop detected: "+u.String())
return
}

View File

@ -2,33 +2,33 @@ package utils
import (
"errors"
"log"
"github.com/charmbracelet/log"
"net/http"
"strings"
)
// logHttpServerError is the internal function powering the logging in
// RunBackgroundHttp and RunBackgroundHttps.
func logHttpServerError(prefix string, err error) {
func logHttpServerError(logger *log.Logger, err error) {
if err != nil {
if errors.Is(err, http.ErrServerClosed) {
log.Printf("[%s] The http server shutdown successfully\n", prefix)
logger.Info("The http server shutdown successfully")
} else {
log.Printf("[%s] Error trying to host the http server: %s\n", prefix, err.Error())
logger.Info("Error trying to host the http server", "err", err.Error())
}
}
}
// RunBackgroundHttp runs a http server and logs when the server closes or
// errors.
func RunBackgroundHttp(prefix string, s *http.Server) {
logHttpServerError(prefix, s.ListenAndServe())
func RunBackgroundHttp(logger *log.Logger, s *http.Server) {
logHttpServerError(logger, s.ListenAndServe())
}
// RunBackgroundHttps runs a http server with TLS encryption and logs when the
// server closes or errors.
func RunBackgroundHttps(prefix string, s *http.Server) {
logHttpServerError(prefix, s.ListenAndServeTLS("", ""))
func RunBackgroundHttps(logger *log.Logger, s *http.Server) {
logHttpServerError(logger, s.ListenAndServeTLS("", ""))
}
// GetBearer returns the bearer from the Authorization header or an empty string