diff --git a/README.md b/README.md index cc66a64..aaac772 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,10 @@ _git-pages_ has robust observability features built in: * If `SENTRY_DSN` environment variable is set, panics are reported to Sentry. * If `SENTRY_DSN` and `SENTRY_LOGS=1` environment variables are set, logs are uploaded to Sentry. * If `SENTRY_DSN` and `SENTRY_TRACING=1` environment variables are set, traces are uploaded to Sentry. +* Optional syslog integration allows transmitting application logs to a syslog daemon. When present, the `SYSLOG_ADDR` environment variable enables the integration, and the variable's value is used to configure the absolute path to a Unix socket (usually located at `/dev/log` on Unix systems) or a network address of one of the following formats: + * for TLS over TCP: `tcp+tls://host:port`; + * for plain TCP: `tcp://host:post`; + * for UDP: `udp://host:port`. Architecture (v2) diff --git a/go.mod b/go.mod index 4450ed3..6bc93e2 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.25.0 require ( codeberg.org/git-pages/go-headers v1.1.0 + codeberg.org/git-pages/go-slog-syslog v0.0.0-20251122140925-40467958039d github.com/KimMachineGun/automemlimit v0.7.5 github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 github.com/creasty/defaults v1.8.0 @@ -39,6 +40,7 @@ require ( github.com/kevinburke/ssh_config v1.4.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/crc32 v1.3.0 // indirect + github.com/leodido/go-syslog/v4 v4.3.0 // indirect github.com/minio/crc64nvme v1.1.0 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect diff --git a/go.sum b/go.sum index 7ca36af..eb44add 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ codeberg.org/git-pages/go-headers v1.1.0 h1:rk7/SOSsn+XuL7PUQZFYUaWKHEaj6K8mXmUV9rF2VxE= codeberg.org/git-pages/go-headers v1.1.0/go.mod h1:N4gwH0U3YPwmuyxqH7xBA8j44fTPX+vOEP7ejJVBPts= +codeberg.org/git-pages/go-slog-syslog v0.0.0-20251122140501-cef0168bba20 h1:gwBA9NToHbaExklHIdOvjc4gzVJkDeffHxlsPY64NrM= +codeberg.org/git-pages/go-slog-syslog v0.0.0-20251122140501-cef0168bba20/go.mod h1:8NPSXbYcVb71qqNM5cIgn1/uQgMisLbu2dVD1BNxsUw= +codeberg.org/git-pages/go-slog-syslog v0.0.0-20251122140925-40467958039d h1:+U2YyXy2QX8oe1e5+UFR1PXfgIK79QWgAgM9l9FQG5o= +codeberg.org/git-pages/go-slog-syslog v0.0.0-20251122140925-40467958039d/go.mod h1:8NPSXbYcVb71qqNM5cIgn1/uQgMisLbu2dVD1BNxsUw= github.com/KimMachineGun/automemlimit v0.7.5 h1:RkbaC0MwhjL1ZuBKunGDjE/ggwAX43DwZrJqVwyveTk= github.com/KimMachineGun/automemlimit v0.7.5/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -73,6 +77,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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-syslog/v4 v4.3.0 h1:bbSpI/41bYK9iSdlYzcwvlxuLOE8yi4VTFmedtnghdA= +github.com/leodido/go-syslog/v4 v4.3.0/go.mod h1:eJ8rUfDN5OS6dOkCOBYlg2a+hbAg6pJa99QXXgMrd98= github.com/maypok86/otter/v2 v2.2.1 h1:hnGssisMFkdisYcvQ8L019zpYQcdtPse+g0ps2i7cfI= github.com/maypok86/otter/v2 v2.2.1/go.mod h1:1NKY9bY+kB5jwCXBJfE59u+zAwOt6C7ni1FTlFFMqVs= github.com/minio/crc64nvme v1.1.0 h1:e/tAguZ+4cw32D+IO/8GSf5UVr9y+3eJcxZI2WOO/7Q= diff --git a/src/observe.go b/src/observe.go index 1ca1cee..be1981d 100644 --- a/src/observe.go +++ b/src/observe.go @@ -13,10 +13,13 @@ import ( "runtime/debug" "strconv" "strings" + "sync" "time" slogmulti "github.com/samber/slog-multi" + syslog "codeberg.org/git-pages/go-slog-syslog" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -42,6 +45,8 @@ var ( }, []string{"method"}) ) +var syslogHandler syslog.Handler + func hasSentry() bool { return os.Getenv("SENTRY_DSN") != "" } @@ -83,6 +88,19 @@ func InitObservability() { log.Println("unknown log format", config.LogFormat) } + if syslogAddr := os.Getenv("SYSLOG_ADDR"); syslogAddr != "" { + var err error + syslogHandler, err = syslog.NewHandler(&syslog.HandlerOptions{ + Address: syslogAddr, + AppName: "git-pages", + StructuredDataID: "git-pages", + }) + if err != nil { + log.Fatalf("syslog: %v", err) + } + logHandlers = append(logHandlers, syslogHandler) + } + if hasSentry() { enableLogs := false if value, err := strconv.ParseBool(os.Getenv("SENTRY_LOGS")); err == nil { @@ -154,9 +172,15 @@ func levelsFromMinimum(minLevel slog.Level) []slog.Level { } func FiniObservability() { - if hasSentry() { - sentry.Flush(2 * time.Second) + var wg sync.WaitGroup + timeout := 2 * time.Second + if syslogHandler != nil { + wg.Go(func() { syslogHandler.Flush(timeout) }) } + if hasSentry() { + wg.Go(func() { sentry.Flush(timeout) }) + } + wg.Wait() } func ObserveError(err error) {