forked from kevadesu/forgejo
Pause, Resume, Release&Reopen, Add and Remove Logging from command line (#11777)
* Make LogDescriptions race safe * Add manager commands for pausing, resuming, adding and removing loggers Signed-off-by: Andrew Thornton <art27@cantab.net> * Placate lint * Ensure that file logger is run! * Add support for smtp and conn Signed-off-by: Andrew Thornton <art27@cantab.net> * Add release-and-reopen Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
parent
38fb087d19
commit
c5b08f6d5a
17 changed files with 924 additions and 17 deletions
|
@ -77,6 +77,13 @@ func (i *connWriter) connect() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (i *connWriter) releaseReopen() error {
|
||||
if i.innerWriter != nil {
|
||||
return i.connect()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConnLogger implements LoggerProvider.
|
||||
// it writes messages in keep-live tcp connection.
|
||||
type ConnLogger struct {
|
||||
|
@ -119,6 +126,11 @@ func (log *ConnLogger) GetName() string {
|
|||
return "conn"
|
||||
}
|
||||
|
||||
// ReleaseReopen causes the ConnLogger to reconnect to the server
|
||||
func (log *ConnLogger) ReleaseReopen() error {
|
||||
return log.out.(*connWriter).releaseReopen()
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register("conn", NewConn)
|
||||
}
|
||||
|
|
|
@ -68,6 +68,20 @@ func (log *ConsoleLogger) Init(config string) error {
|
|||
func (log *ConsoleLogger) Flush() {
|
||||
}
|
||||
|
||||
// ReleaseReopen causes the console logger to reconnect to os.Stdout
|
||||
func (log *ConsoleLogger) ReleaseReopen() error {
|
||||
if log.Stderr {
|
||||
log.NewWriterLogger(&nopWriteCloser{
|
||||
w: os.Stderr,
|
||||
})
|
||||
} else {
|
||||
log.NewWriterLogger(&nopWriteCloser{
|
||||
w: os.Stdout,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *ConsoleLogger) GetName() string {
|
||||
return "console"
|
||||
|
|
|
@ -29,6 +29,7 @@ type EventLogger interface {
|
|||
GetLevel() Level
|
||||
GetStacktraceLevel() Level
|
||||
GetName() string
|
||||
ReleaseReopen() error
|
||||
}
|
||||
|
||||
// ChannelledLog represents a cached channel to a LoggerProvider
|
||||
|
@ -117,6 +118,11 @@ func (l *ChannelledLog) Flush() {
|
|||
l.flush <- true
|
||||
}
|
||||
|
||||
// ReleaseReopen this ChannelledLog
|
||||
func (l *ChannelledLog) ReleaseReopen() error {
|
||||
return l.loggerProvider.ReleaseReopen()
|
||||
}
|
||||
|
||||
// GetLevel gets the level of this ChannelledLog
|
||||
func (l *ChannelledLog) GetLevel() Level {
|
||||
return l.loggerProvider.GetLevel()
|
||||
|
@ -145,6 +151,7 @@ type MultiChannelledLog struct {
|
|||
level Level
|
||||
stacktraceLevel Level
|
||||
closed chan bool
|
||||
paused chan bool
|
||||
}
|
||||
|
||||
// NewMultiChannelledLog a new logger instance with given logger provider and config.
|
||||
|
@ -159,6 +166,7 @@ func NewMultiChannelledLog(name string, bufferLength int64) *MultiChannelledLog
|
|||
stacktraceLevel: NONE,
|
||||
close: make(chan bool),
|
||||
closed: make(chan bool),
|
||||
paused: make(chan bool),
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
@ -229,6 +237,33 @@ func (m *MultiChannelledLog) closeLoggers() {
|
|||
m.closed <- true
|
||||
}
|
||||
|
||||
// Pause pauses this Logger
|
||||
func (m *MultiChannelledLog) Pause() {
|
||||
m.paused <- true
|
||||
}
|
||||
|
||||
// Resume resumes this Logger
|
||||
func (m *MultiChannelledLog) Resume() {
|
||||
m.paused <- false
|
||||
}
|
||||
|
||||
// ReleaseReopen causes this logger to tell its subloggers to release and reopen
|
||||
func (m *MultiChannelledLog) ReleaseReopen() error {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
var accumulatedErr error
|
||||
for _, logger := range m.loggers {
|
||||
if err := logger.ReleaseReopen(); err != nil {
|
||||
if accumulatedErr == nil {
|
||||
accumulatedErr = fmt.Errorf("Error whilst reopening: %s Error: %v", logger.GetName(), err)
|
||||
} else {
|
||||
accumulatedErr = fmt.Errorf("Error whilst reopening: %s Error: %v & %v", logger.GetName(), err, accumulatedErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return accumulatedErr
|
||||
}
|
||||
|
||||
// Start processing the MultiChannelledLog
|
||||
func (m *MultiChannelledLog) Start() {
|
||||
m.mutex.Lock()
|
||||
|
@ -238,8 +273,35 @@ func (m *MultiChannelledLog) Start() {
|
|||
}
|
||||
m.started = true
|
||||
m.mutex.Unlock()
|
||||
paused := false
|
||||
for {
|
||||
if paused {
|
||||
select {
|
||||
case paused = <-m.paused:
|
||||
if !paused {
|
||||
m.ResetLevel()
|
||||
}
|
||||
case _, ok := <-m.flush:
|
||||
if !ok {
|
||||
m.closeLoggers()
|
||||
return
|
||||
}
|
||||
m.mutex.Lock()
|
||||
for _, logger := range m.loggers {
|
||||
logger.Flush()
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
case <-m.close:
|
||||
m.closeLoggers()
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case paused = <-m.paused:
|
||||
if paused && m.level < INFO {
|
||||
m.level = INFO
|
||||
}
|
||||
case event, ok := <-m.queue:
|
||||
if !ok {
|
||||
m.closeLoggers()
|
||||
|
@ -275,7 +337,7 @@ func (m *MultiChannelledLog) LogEvent(event *Event) error {
|
|||
select {
|
||||
case m.queue <- event:
|
||||
return nil
|
||||
case <-time.After(60 * time.Second):
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
// We're blocked!
|
||||
return ErrTimeout{
|
||||
Name: m.name,
|
||||
|
|
|
@ -249,6 +249,19 @@ func (log *FileLogger) Flush() {
|
|||
_ = log.mw.fd.Sync()
|
||||
}
|
||||
|
||||
// ReleaseReopen releases and reopens log files
|
||||
func (log *FileLogger) ReleaseReopen() error {
|
||||
closingErr := log.mw.fd.Close()
|
||||
startingErr := log.StartLogger()
|
||||
if startingErr != nil {
|
||||
if closingErr != nil {
|
||||
return fmt.Errorf("Error during closing: %v Error during starting: %v", closingErr, startingErr)
|
||||
}
|
||||
return startingErr
|
||||
}
|
||||
return closingErr
|
||||
}
|
||||
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *FileLogger) GetName() string {
|
||||
return "file"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -192,6 +193,42 @@ func IsFatal() bool {
|
|||
return GetLevel() <= FATAL
|
||||
}
|
||||
|
||||
// Pause pauses all the loggers
|
||||
func Pause() {
|
||||
NamedLoggers.Range(func(key, value interface{}) bool {
|
||||
logger := value.(*Logger)
|
||||
logger.Pause()
|
||||
logger.Flush()
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// Resume resumes all the loggers
|
||||
func Resume() {
|
||||
NamedLoggers.Range(func(key, value interface{}) bool {
|
||||
logger := value.(*Logger)
|
||||
logger.Resume()
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// ReleaseReopen releases and reopens logging files
|
||||
func ReleaseReopen() error {
|
||||
var accumulatedErr error
|
||||
NamedLoggers.Range(func(key, value interface{}) bool {
|
||||
logger := value.(*Logger)
|
||||
if err := logger.ReleaseReopen(); err != nil {
|
||||
if accumulatedErr == nil {
|
||||
accumulatedErr = fmt.Errorf("Error reopening %s: %v", key.(string), err)
|
||||
} else {
|
||||
accumulatedErr = fmt.Errorf("Error reopening %s: %v & %v", key.(string), err, accumulatedErr)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return accumulatedErr
|
||||
}
|
||||
|
||||
// Close closes all the loggers
|
||||
func Close() {
|
||||
l, ok := NamedLoggers.Load(DEFAULT)
|
||||
|
|
|
@ -97,6 +97,11 @@ func (log *SMTPLogger) sendMail(p []byte) (int, error) {
|
|||
func (log *SMTPLogger) Flush() {
|
||||
}
|
||||
|
||||
// ReleaseReopen does nothing
|
||||
func (log *SMTPLogger) ReleaseReopen() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *SMTPLogger) GetName() string {
|
||||
return "smtp"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue