Files
forge/modules/log/manager.go
zeekayandHanzo Dev 9a07b4d089 legal: Hanzo AI, Inc. copyright above the upstream notices
2978 files. The fork is 2026-07-15 (rebrand: gitea.dev -> github.com/hanzoai/git),
so 2026 is the year, and "Copyright 2026 Hanzo AI, Inc." was already the form
used by the handful of files that had ours.

Shape is now:

	// Copyright 2026 Hanzo AI, Inc. All rights reserved.
	// Copyright 2015 The Gogs Authors. All rights reserved.
	// Copyright 2019 The Gitea Authors. All rights reserved.
	// SPDX-License-Identifier: MIT

Ours on top, theirs retained verbatim. Retained because MIT requires it, and
separately because they are true — those authors did write that code.

Not renamed to "The Git Authors": Git is a different project under a different
license, and putting its name here would attribute this code to people who have
nothing to do with it. Adding our line is the fix; overwriting theirs would have
been both a licence violation and a false statement.

gofmt still reports import-order drift in some of these files. It predates this
change (verified against a stash) and is left alone rather than burying a
one-line-per-file legal change under 3000 files of unrelated reordering.

Build clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 13:49:52 -07:00

144 lines
3.4 KiB
Go

// Copyright 2026 Hanzo AI, Inc. All rights reserved.
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package log
import (
"context"
"fmt"
"sync"
"sync/atomic"
)
const DEFAULT = "default"
// LoggerManager manages loggers and shared event writers
type LoggerManager struct {
ctx context.Context
ctxCancel context.CancelFunc
mu sync.Mutex
writers map[string]EventWriter
loggers map[string]*LoggerImpl
defaultLogger atomic.Pointer[LoggerImpl]
pauseMu sync.RWMutex
pauseChan chan struct{}
}
// GetLogger returns a logger with the given name. If the logger doesn't exist, a new empty one will be created.
func (m *LoggerManager) GetLogger(name string) *LoggerImpl {
if name == DEFAULT {
if logger := m.defaultLogger.Load(); logger != nil {
return logger
}
}
m.mu.Lock()
defer m.mu.Unlock()
logger := m.loggers[name]
if logger == nil {
logger = NewLoggerWithWriters(m.ctx, name)
m.loggers[name] = logger
if name == DEFAULT {
m.defaultLogger.Store(logger)
}
}
return logger
}
// PauseAll pauses all event writers
func (m *LoggerManager) PauseAll() {
m.pauseMu.Lock()
m.pauseChan = make(chan struct{})
m.pauseMu.Unlock()
}
// ResumeAll resumes all event writers
func (m *LoggerManager) ResumeAll() {
m.pauseMu.Lock()
close(m.pauseChan)
m.pauseChan = nil
m.pauseMu.Unlock()
}
// GetPauseChan returns a channel for writer pausing
func (m *LoggerManager) GetPauseChan() chan struct{} {
m.pauseMu.RLock()
defer m.pauseMu.RUnlock()
return m.pauseChan
}
// Close closes the logger manager, all loggers and writers will be closed, the messages are flushed.
func (m *LoggerManager) Close() {
m.mu.Lock()
defer m.mu.Unlock()
for _, logger := range m.loggers {
logger.Close()
}
m.loggers = map[string]*LoggerImpl{}
for _, writer := range m.writers {
eventWriterStopWait(writer)
}
m.writers = map[string]EventWriter{}
m.ctxCancel()
}
// DumpLoggers returns a map of all loggers and their event writers, for debugging and display purposes.
func (m *LoggerManager) DumpLoggers() map[string]any {
m.mu.Lock()
defer m.mu.Unlock()
dump := map[string]any{}
for name, logger := range m.loggers {
loggerDump := map[string]any{
"IsEnabled": logger.IsEnabled(),
"EventWriters": logger.DumpWriters(),
}
dump[name] = loggerDump
}
return dump
}
// NewSharedWriter creates a new shared event writer, it can be used by multiple loggers, and a shared writer won't be closed if a logger is closed.
func (m *LoggerManager) NewSharedWriter(writerName, writerType string, mode WriterMode) (writer EventWriter, err error) {
m.mu.Lock()
defer m.mu.Unlock()
if _, ok := m.writers[writerName]; ok {
return nil, fmt.Errorf("log event writer %q has been added before", writerName)
}
if writer, err = NewEventWriter(writerName, writerType, mode); err != nil {
return nil, err
}
m.writers[writerName] = writer
eventWriterStartGo(m.ctx, writer, true)
return writer, nil
}
func (m *LoggerManager) GetSharedWriter(writerName string) EventWriter {
m.mu.Lock()
defer m.mu.Unlock()
return m.writers[writerName]
}
var loggerManager = NewManager()
func GetManager() *LoggerManager {
return loggerManager
}
func NewManager() *LoggerManager {
m := &LoggerManager{writers: map[string]EventWriter{}, loggers: map[string]*LoggerImpl{}}
m.ctx, m.ctxCancel = newProcessTypedContext(context.Background(), "LoggerManager")
return m
}