Skip to content
Open
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
61 changes: 57 additions & 4 deletions pkg/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,75 @@
package logger

import (
"os"
"time"

"github.com/sirupsen/logrus"
prefixed "github.com/x-cray/logrus-prefixed-formatter"
"gopkg.in/natefinch/lumberjack.v2"
)

// cstLocation is the CST (UTC+8) location used for log timestamps.
// Initialized once at package init with a graceful fallback for systems
// without tzdata (e.g., minimal OpenWrt/ImmortalWrt builds).
var cstLocation *time.Location

func init() {
if loc, err := time.LoadLocation("Asia/Shanghai"); err == nil {
cstLocation = loc
} else {
cstLocation = time.FixedZone("CST", 8*3600)
}
}

// isJournaldStream returns true if dae's stdout/stderr is captured by systemd's
// journald. Systemd sets the JOURNAL_STREAM environment variable for each
// service's standard streams (value is "device:inode"). When true we suppress
// dae's own timestamp to avoid the redundant "journald prefix + CST timestamp"
// double-prefix that PR #1021 introduced by removing --disable-timestamp from
// dae.service.
func isJournaldStream() bool {
return os.Getenv("JOURNAL_STREAM") != ""
}

// cstFormatter wraps prefixed.TextFormatter to use CST timezone for timestamps
// without modifying the global time.Local, which would affect unrelated code.
type cstFormatter struct {
*prefixed.TextFormatter
}

// Format overrides the timestamp formatting to use CST timezone.
func (f *cstFormatter) Format(entry *logrus.Entry) ([]byte, error) {
// Create a copy of the entry to avoid modifying the shared entry object
if !f.DisableTimestamp && entry.Time != (time.Time{}) {
modifiedEntry := *entry
modifiedEntry.Time = entry.Time.In(cstLocation)
return f.TextFormatter.Format(&modifiedEntry)
}
return f.TextFormatter.Format(entry)
}

func SetLogger(log *logrus.Logger, logLevel string, disableTimestamp bool, logFileOpt *lumberjack.Logger) {
level, err := logrus.ParseLevel(logLevel)
if err != nil {
level = logrus.InfoLevel
}

log.SetLevel(level)
log.SetFormatter(&prefixed.TextFormatter{
DisableTimestamp: disableTimestamp,
FullTimestamp: true,
TimestampFormat: "Jan 02 15:04:05",
// Auto-disable timestamp under journald to avoid double prefix.
// When writing to a logfile we always emit the CST timestamp (the file
// needs a self-describing timestamp). --disable-timestamp still forces
// suppression for callers that explicitly want it.
if !disableTimestamp && isJournaldStream() && logFileOpt == nil {
disableTimestamp = true
}
log.SetFormatter(&cstFormatter{
TextFormatter: &prefixed.TextFormatter{
DisableTimestamp: disableTimestamp,
FullTimestamp: true,
ForceFormatting: true,
TimestampFormat: "2006-01-02 15:04:05",
},
})
if logFileOpt != nil {
log.SetOutput(logFileOpt)
Expand Down
Loading