Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions api/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
"log"
"net/http"
"time"

Expand All @@ -17,6 +16,7 @@ import (
"github.com/gotify/server/v2/database"
"github.com/gotify/server/v2/decaymap"
"github.com/gotify/server/v2/model"
"github.com/rs/zerolog/log"
"github.com/zitadel/oidc/v3/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
Expand All @@ -30,7 +30,7 @@ func NewOIDC(conf *config.Configuration, db *database.GormDatabase, userChangeNo

cookieKey := make([]byte, 32)
if _, err := rand.Read(cookieKey); err != nil {
log.Fatalf("failed to generate OIDC cookie key: %v", err)
log.Fatal().Err(err).Msg("failed to generate OIDC cookie key")
}
cookieHandlerOpt := []httphelper.CookieHandlerOpt{}
if !conf.Server.SecureCookie {
Expand All @@ -50,7 +50,7 @@ func NewOIDC(conf *config.Configuration, db *database.GormDatabase, userChangeNo
opts...,
)
if err != nil {
log.Fatalf("failed to initialize OIDC provider: %v", err)
log.Fatal().Err(err).Msg("failed to initialize OIDC provider")
}

return &OIDCAPI{
Expand Down Expand Up @@ -415,7 +415,7 @@ func (a *OIDCAPI) resolveUser(info *oidc.UserInfo) (*model.User, int, error) {
return nil, http.StatusInternalServerError, fmt.Errorf("failed to create user: %w", err)
}
if err := a.UserChangeNotifier.fireUserAdded(user.ID); err != nil {
log.Printf("Could not notify user change: %v\n", err)
log.Error().Err(err).Uint("user_id", user.ID).Msg("Could not notify user change")
}
}
return user, 0, nil
Expand Down
4 changes: 2 additions & 2 deletions api/stream/client.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package stream

import (
"fmt"
"time"

"github.com/gorilla/websocket"
"github.com/gotify/server/v2/model"
"github.com/rs/zerolog/log"
)

const (
Expand Down Expand Up @@ -115,5 +115,5 @@ func printWebSocketError(prefix string, err error) {
return
}

fmt.Println("WebSocket:", prefix, err)
log.Warn().Err(err).Msgf("WebSocket %s", prefix)
}
21 changes: 18 additions & 3 deletions app.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package main

import (
"fmt"
"os"
"time"

"github.com/gotify/server/v2/config"
"github.com/gotify/server/v2/database"
"github.com/gotify/server/v2/mode"
"github.com/gotify/server/v2/model"
"github.com/gotify/server/v2/router"
"github.com/gotify/server/v2/runner"
"github.com/mattn/go-isatty"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)

var (
Expand All @@ -24,10 +27,12 @@ var (
)

func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339, NoColor: noColor()})

vInfo := &model.VersionInfo{Version: Version, Commit: Commit, BuildDate: BuildDate}
mode.Set(Mode)

fmt.Println("Starting Gotify version", vInfo.Version+"@"+BuildDate)
log.Info().Str("version", vInfo.Version).Str("build_date", BuildDate).Msg("Gotify")
conf := config.Get()

if conf.PluginsDir != "" {
Expand All @@ -49,7 +54,17 @@ func main() {
defer closeable()

if err := runner.Run(engine, conf); err != nil {
fmt.Println("Server error: ", err)
log.Error().Err(err).Msg("Server error")
os.Exit(1)
}
}

func noColor() bool {
// https://no-color.org/
if os.Getenv("NO_COLOR") == "1" {
return true
}

isTTY := isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())
return !isTTY
}
14 changes: 10 additions & 4 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package database
import (
"database/sql"
"errors"
"fmt"
"log"
"math"
"os"
"path/filepath"
Expand All @@ -14,20 +12,28 @@ import (
"github.com/gotify/server/v2/fracdex"
"github.com/gotify/server/v2/model"
"github.com/mattn/go-isatty"
"github.com/rs/zerolog/log"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)

// gormLogWriter routes gorm logger output through zerolog.
type gormLogWriter struct{}

func (gormLogWriter) Printf(format string, args ...interface{}) {
log.Warn().Str("component", "gorm").Msgf(format, args...)
}

var mkdirAll = os.MkdirAll

// New creates a new wrapper for the gorm database framework.
func New(dialect, connection, defaultUser, defaultPass string, strength int, createDefaultUserIfNotExist bool) (*GormDatabase, error) {
createDirectoryIfSqlite(dialect, connection)

dbLogger := logger.New(log.New(os.Stderr, "\r\n", log.LstdFlags), logger.Config{
dbLogger := logger.New(gormLogWriter{}, logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
IgnoreRecordNotFoundError: true,
Expand Down Expand Up @@ -111,7 +117,7 @@ func fillMissingSortKeys(db *gorm.DB) error {
if err := db.Order("user_id, sort_key, id ASC").Find(&apps).Error; err != nil && err != gorm.ErrRecordNotFound {
return err
}
fmt.Println("Migrating", len(apps), "application sort keys")
log.Info().Int("count", len(apps)).Msg("Migrating application sort keys")

sortKey := ""
currentUser := uint(math.MaxUint)
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/jinzhu/configor v1.2.2
github.com/mattn/go-isatty v0.0.20
github.com/robfig/cron v1.2.0
github.com/rs/zerolog v1.35.1
github.com/stretchr/testify v1.11.1
github.com/zitadel/oidc/v3 v3.45.5
golang.org/x/crypto v0.48.0
Expand Down Expand Up @@ -53,6 +54,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-sqlite3 v1.14.32 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,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/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
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=
Expand Down Expand Up @@ -129,6 +131,8 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
13 changes: 8 additions & 5 deletions plugin/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"os"
"path/filepath"
"plugin"
Expand All @@ -18,6 +17,7 @@ import (
"github.com/gotify/server/v2/auth"
"github.com/gotify/server/v2/model"
"github.com/gotify/server/v2/plugin/compat"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -155,7 +155,7 @@ func (m *Manager) PluginInfo(modulePath string) compat.Info {
if p, ok := m.plugins[modulePath]; ok {
return p.PluginInfo()
}
fmt.Println("Could not get plugin info for", modulePath)
log.Warn().Str("module_path", modulePath).Msg("Could not get plugin info")
return compat.Info{
Name: "UNKNOWN",
ModulePath: modulePath,
Expand Down Expand Up @@ -237,7 +237,7 @@ func (m *Manager) loadPlugins(directory string) error {

pluginPath := filepath.Join(directory, "./", name)

fmt.Println("Loading plugin", pluginPath)
log.Info().Str("path", pluginPath).Msg("Loading plugin")
pRaw, err := plugin.Open(pluginPath)
if err != nil {
return pluginFileLoadError{name, err}
Expand Down Expand Up @@ -355,7 +355,7 @@ func (m *Manager) initializeSingleUserPlugin(userCtx compat.UserContext, p compa
if err != nil {
// Single user plugin cannot be enabled
// Don't panic, disable for now and wait for user to update config
log.Printf("Plugin initialize failed for user %s: %s. Disabling now...", userCtx.Name, err.Error())
log.Warn().Err(err).Str("user", userCtx.Name).Msg("Plugin initialize failed, disabling now")
pluginConf.Enabled = false
m.db.UpdatePluginConf(pluginConf)
}
Expand All @@ -374,7 +374,10 @@ func (m *Manager) initializeConfigurerForSingleUserPlugin(instance compat.Plugin
if yaml.Unmarshal(pluginConf.Config, c) != nil || instance.ValidateAndSetConfig(c) != nil {
pluginConf.Enabled = false

log.Printf("Plugin %s for user %d failed to initialize because it rejected the current config. It might be outdated. A default config is used and the user would need to enable it again.", pluginConf.ModulePath, pluginConf.UserID)
log.Warn().
Str("module_path", pluginConf.ModulePath).
Uint("user_id", pluginConf.UserID).
Msg("Plugin failed to initialize because it rejected the current config. It might be outdated. A default config is used and the user would need to enable it again.")
newConf := bytes.NewBufferString("# Plugin initialization failed because it rejected the current config. It might be outdated.\r\n# A default plugin configuration is used:\r\n")

d, _ := yaml.Marshal(c)
Expand Down
68 changes: 45 additions & 23 deletions router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/gotify/server/v2/model"
"github.com/gotify/server/v2/plugin"
"github.com/gotify/server/v2/ui"
"github.com/rs/zerolog/log"
)

// Create creates the gin engine with all routes.
Expand All @@ -39,7 +40,7 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co
}
})

g.Use(gin.LoggerWithFormatter(logFormatter), gin.Recovery(), gerror.Handler(), location.Default())
g.Use(accessLogger(), gin.Recovery(), gerror.Handler(), location.Default())
g.NoRoute(gerror.NotFound())

if conf.Server.SSL.Enabled && conf.Server.SSL.RedirectToHTTPS {
Expand Down Expand Up @@ -239,31 +240,52 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co

var tokenRegexp = regexp.MustCompile("token=[^&]+")

func logFormatter(param gin.LogFormatterParams) string {
if (param.ClientIP == "127.0.0.1" || param.ClientIP == "::1") && param.Path == "/health" {
return ""
}
func accessLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()

var statusColor, methodColor, resetColor string
if param.IsOutputColor() {
statusColor = param.StatusCodeColor()
methodColor = param.MethodColor()
resetColor = param.ResetColor()
}
rawQuery := c.Request.URL.RawQuery
path := c.Request.URL.Path

c.Next()

clientIP := c.ClientIP()
if (clientIP == "127.0.0.1" || clientIP == "::1") && path == "/health" {
return
}

if rawQuery != "" {
path = path + "?" + rawQuery
}
path = tokenRegexp.ReplaceAllString(path, "token=[masked]")

latency := time.Since(start)
if latency > time.Minute {
latency = latency - latency%time.Second
}

status := c.Writer.Status()
evt := log.Info()
switch {
case status >= 500:
evt = log.Error()
case status >= 400:
evt = log.Warn()
}

evt.
Int("status", status).
Str("duration", latency.String()).
Str("ip", clientIP).
Str("method", c.Request.Method).
Str("path", path)

if errs := c.Errors.ByType(gin.ErrorTypePrivate).String(); errs != "" {
evt.Str("errors", strings.TrimSpace(errs))
}

if param.Latency > time.Minute {
param.Latency = param.Latency - param.Latency%time.Second
evt.Msg("HTTP")
}
path := tokenRegexp.ReplaceAllString(param.Path, "token=[masked]")
return fmt.Sprintf("%v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s",
param.TimeStamp.Format(time.RFC3339),
statusColor, param.StatusCode, resetColor,
param.Latency,
param.ClientIP,
methodColor, param.Method, resetColor,
path,
param.ErrorMessage,
)
}

type onlyImageFS struct {
Expand Down
Loading
Loading