5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-20 19:09:29 +08:00
wails/v3/pkg/services/log/log.go
2025-02-13 03:11:21 +01:00

196 lines
5.2 KiB
Go

package log
import (
"context"
_ "embed"
"log/slog"
"sync/atomic"
"github.com/wailsapp/wails/v3/pkg/application"
)
// A Level is the importance or severity of a log event.
// The higher the level, the more important or severe the event.
//
// Values are arbitrary, but there are four predefined ones.
type Level = int
const (
Debug = Level(slog.LevelDebug)
Info = Level(slog.LevelInfo)
Warning = Level(slog.LevelWarn)
Error = Level(slog.LevelError)
)
type Config struct {
// Logger is the logger to use. If not set, a default logger will be used.
Logger *slog.Logger
// LogLevel defines the log level of the logger.
LogLevel slog.Level
}
//wails:inject export {
//wails:inject DebugContext as Debug,
//wails:inject InfoContext as Info,
//wails:inject WarningContext as Warning,
//wails:inject ErrorContext as Error,
//wails:inject };
type Service struct {
config atomic.Pointer[Config]
level slog.LevelVar
}
// New initialises a logging service with the default configuration.
func New() *Service {
return NewWithConfig(nil)
}
// NewWithConfig initialises a logging service with a custom configuration.
func NewWithConfig(config *Config) *Service {
result := &Service{}
result.Configure(config)
return result
}
// ServiceName returns the name of the plugin.
// You should use the go module format e.g. github.com/myuser/myplugin
func (l *Service) ServiceName() string {
return "github.com/wailsapp/wails/v3/plugins/log"
}
// Configure reconfigures the logger dynamically.
// If config is nil, it falls back to the default configuration.
//
//wails:ignore
func (l *Service) Configure(config *Config) {
if config == nil {
config = &Config{}
} else {
// Clone to prevent changes from the outside.
clone := new(Config)
*clone = *config
config = clone
}
l.level.Set(slog.Level(config.LogLevel))
if config.Logger == nil {
config.Logger = application.DefaultLogger(&l.level)
}
l.config.Store(config)
}
// Level returns the currently configured log level,
// that is either the one configured initially
// or the last value passed to [Service.SetLogLevel].
//
// Through this method, [Service] implements the [slog.Leveler] interface.
// The intended use case is to propagate
// the service's dynamic level setting to custom loggers.
// For example:
//
// logService := log.New()
// customLogger := slog.New(slog.NewTextHandler(
// customWriter,
// &slog.HandlerOptions{
// Level: logService,
// },
// ))
// logService.Configure(&log.Config{
// Logger: customLogger
// })
//
// By doing so, setting updates made through [Service.SetLogLevel]
// will propagate dynamically to the custom logger.
//
//wails:ignore
func (l *Service) Level() slog.Level {
return l.level.Level()
}
// LogLevel returns the currently configured log level,
// that is either the one configured initially
// or the last value passed to [Service.SetLogLevel].
func (l *Service) LogLevel() Level {
return Level(l.Level())
}
// SetLogLevel changes the current log level.
func (l *Service) SetLogLevel(level Level) {
l.level.Set(slog.Level(level))
}
// Log emits a log record with the current time and the given level and message.
// The Record's attributes consist of the Logger's attributes followed by
// the attributes specified by args.
//
// The attribute arguments are processed as follows:
// - If an argument is a string and this is not the last argument,
// the following argument is treated as the value and the two are combined
// into an attribute.
// - Otherwise, the argument is treated as a value with key "!BADKEY".
//
// Log feeds the binding call context into the configured logger,
// so custom handlers may access context values, e.g. the current window.
func (l *Service) Log(ctx context.Context, level Level, message string, args ...any) {
l.config.Load().Logger.Log(ctx, slog.Level(level), message, args...)
}
// Debug logs at level [Debug].
//
//wails:ignore
func (l *Service) Debug(message string, args ...any) {
l.DebugContext(context.Background(), message, args...)
}
// Info logs at level [Info].
//
//wails:ignore
func (l *Service) Info(message string, args ...any) {
l.InfoContext(context.Background(), message, args...)
}
// Warning logs at level [Warning].
//
//wails:ignore
func (l *Service) Warning(message string, args ...any) {
l.WarningContext(context.Background(), message, args...)
}
// Error logs at level [Error].
//
//wails:ignore
func (l *Service) Error(message string, args ...any) {
l.ErrorContext(context.Background(), message, args...)
}
// DebugContext logs at level [Debug].
//
//wails:internal
func (l *Service) DebugContext(ctx context.Context, message string, args ...any) {
l.Log(ctx, Debug, message, args...)
}
// InfoContext logs at level [Info].
//
//wails:internal
func (l *Service) InfoContext(ctx context.Context, message string, args ...any) {
l.Log(ctx, Info, message, args...)
}
// WarningContext logs at level [Warn].
//
//wails:internal
func (l *Service) WarningContext(ctx context.Context, message string, args ...any) {
l.Log(ctx, Warning, message, args...)
}
// ErrorContext logs at level [Error].
//
//wails:internal
func (l *Service) ErrorContext(ctx context.Context, message string, args ...any) {
l.Log(ctx, Error, message, args...)
}