REPOSITORY / ScuroNeko/Laniakea
Pull Requests
v1.0.0 #9
@@ -3,11 +3,14 @@
|
||||
## v1.0.0-rc.16
|
||||
|
||||
### Changed
|
||||
- Updated `slog` to `v2`.
|
||||
- Bot loggers now apply the configured token replacer consistently across the main bot logger, request logger, internal API and uploader loggers, webhook logger, and auto-managed plugin loggers, so bot tokens stay masked in both stdout and file-backed logs.
|
||||
- JSON `BotOpts` files now write `version`, reject newer unsupported config versions, keep older unversioned files loadable, and preserve the loaded file version in `BotOpts.FileConfigVersion`.
|
||||
- Active scenes now support scene-local callback payload handlers through `Scene.OnPayload(...)`, including observer lifecycle events for scene payload execution.
|
||||
|
||||
### Tests
|
||||
- Added regression coverage proving polling startup preserves an enabled request logger.
|
||||
- Updated file logger regression coverage for the current `sneklog` text prefix format.
|
||||
- Added regression coverage proving token masking still applies after `initLoggers(...)` switches loggers to file-backed writers and that auto-managed plugin loggers inherit token masking as well.
|
||||
- Added regression coverage for JSON config version handling and scene-local payload routing, including observer lifecycle events and callback fallthrough behavior.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"git.scuroneko.dev/scuroneko/extypes"
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/laniakea/utils"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
// AppData is the generic shared application data type injected into bots,
|
||||
@@ -38,11 +38,11 @@ type AppData any
|
||||
// Use Bot[NoData] to indicate no shared dependency injection is required.
|
||||
type NoData struct{ AppData }
|
||||
|
||||
// AppDataLogger builds a slog.LoggerWriter from injected application data.
|
||||
// AppDataLogger builds a sneklog.LoggerWriter from injected application data.
|
||||
//
|
||||
// Use it when shared application data exposes a log sink or adapter that should
|
||||
// receive framework logs.
|
||||
type AppDataLogger[T AppData] func(data T) slog.LoggerWriter
|
||||
type AppDataLogger[T AppData] func(data T) sneklog.LoggerWriter
|
||||
|
||||
// BotPayloadType defines the serialization format for callback data payloads.
|
||||
type BotPayloadType string
|
||||
@@ -90,10 +90,11 @@ type Bot[T AppData] struct {
|
||||
strictPayloadType bool
|
||||
maxWorkers int
|
||||
|
||||
logger *slog.Logger // Main bot logger (JSON stdout + optional file)
|
||||
RequestLogger *slog.Logger // Optional request-level API logging
|
||||
webHookLogger *slog.Logger // Webhook logger. Available only after Bot.RunWebHookWithContext.
|
||||
extraLoggers extypes.Slice[*slog.Logger] // API, Uploader, and custom loggers
|
||||
logger *sneklog.Logger // Main bot logger (JSON stdout + optional file)
|
||||
requestLogger *sneklog.Logger // Optional request-level API logging
|
||||
useReqLogger bool
|
||||
webHookLogger *sneklog.Logger // Webhook logger. Available only after Bot.RunWebHookWithContext.
|
||||
extraLoggers extypes.Slice[*sneklog.Logger] // API, Uploader, and custom loggers
|
||||
|
||||
plugins []Plugin[T] // Command/event handlers
|
||||
middlewares []Middleware[T] // Pre-processing filters (sorted by order)
|
||||
@@ -187,12 +188,14 @@ func NewBot[T any](opts *BotOpts) (*Bot[T], error) {
|
||||
debug: opts.Debug,
|
||||
prefixes: prefixes,
|
||||
token: opts.Token,
|
||||
plugins: make([]Plugin[T], 0),
|
||||
updateTypes: append([]tgapi.UpdateType{}, opts.UpdateTypes...),
|
||||
runners: make([]Runner[T], 0),
|
||||
extraLoggers: make([]*slog.Logger, 0),
|
||||
l10n: &L10n{},
|
||||
draftProvider: NewRandomDraftProvider(api),
|
||||
useReqLogger: opts.UseRequestLogger,
|
||||
|
||||
plugins: make([]Plugin[T], 0),
|
||||
updateTypes: append([]tgapi.UpdateType{}, opts.UpdateTypes...),
|
||||
runners: make([]Runner[T], 0),
|
||||
extraLoggers: make([]*sneklog.Logger, 0),
|
||||
l10n: &L10n{},
|
||||
draftProvider: NewRandomDraftProvider(api),
|
||||
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -235,6 +238,24 @@ func NewBot[T any](opts *BotOpts) (*Bot[T], error) {
|
||||
return bot, nil
|
||||
}
|
||||
|
||||
// SetLogger replaces the main bot logger.
|
||||
func (b *Bot[T]) SetLogger(l *sneklog.Logger) *Bot[T] {
|
||||
b.logger = l
|
||||
return b
|
||||
}
|
||||
|
||||
// SetRequestLogger replaces the request-level logger.
|
||||
func (b *Bot[T]) SetRequestLogger(l *sneklog.Logger) *Bot[T] {
|
||||
b.requestLogger = l
|
||||
return b
|
||||
}
|
||||
|
||||
// SetWebHookLogger replaces the webhook logger.
|
||||
func (b *Bot[T]) SetWebHookLogger(l *sneklog.Logger) *Bot[T] {
|
||||
b.webHookLogger = l
|
||||
return b
|
||||
}
|
||||
|
||||
// Close gracefully shuts down bot-owned resources.
|
||||
//
|
||||
// Close shuts down, in order:
|
||||
@@ -283,8 +304,8 @@ func (bot *Bot[T]) Close() error {
|
||||
logCloseErr(err)
|
||||
}
|
||||
}
|
||||
if bot.RequestLogger != nil {
|
||||
if err := bot.RequestLogger.Close(); err != nil {
|
||||
if bot.requestLogger != nil {
|
||||
if err := bot.requestLogger.Close(); err != nil {
|
||||
logCloseErr(err)
|
||||
}
|
||||
}
|
||||
@@ -322,14 +343,20 @@ func (bot *Bot[T]) SetUpdateOffset(offset int) {
|
||||
}
|
||||
|
||||
// GetLogger returns the main bot logger.
|
||||
func (bot *Bot[T]) GetLogger() *slog.Logger { return bot.logger }
|
||||
func (bot *Bot[T]) GetLogger() *sneklog.Logger { return bot.logger }
|
||||
|
||||
// GetRequestLogger returns the request-level logger, if configured.
|
||||
func (bot *Bot[T]) GetRequestLogger() *sneklog.Logger { return bot.requestLogger }
|
||||
|
||||
// GetWebHookLogger returns the webhook logger, if configured.
|
||||
func (bot *Bot[T]) GetWebHookLogger() *sneklog.Logger { return bot.webHookLogger }
|
||||
|
||||
// GetLoggerLevel returns the effective log level derived from the bot's debug
|
||||
// flag.
|
||||
func (bot *Bot[T]) GetLoggerLevel() slog.LogLevel {
|
||||
level := slog.FATAL
|
||||
func (bot *Bot[T]) GetLoggerLevel() sneklog.LogLevel {
|
||||
level := sneklog.FATAL
|
||||
if bot.debug {
|
||||
level = slog.DEBUG
|
||||
level = sneklog.DEBUG
|
||||
}
|
||||
return level
|
||||
}
|
||||
@@ -373,6 +400,22 @@ func (bot *Bot[T]) RunWithContext(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
defer bot.finishRun()
|
||||
if !bot.useReqLogger && bot.requestLogger != nil {
|
||||
bot.logger.Warnln("Opts#UseRequestLogger is false, but Bot#requestLogger present. Remove Bot#SetRequestLogger or set Opts#UseRequestLogger to true!")
|
||||
err := bot.requestLogger.Close()
|
||||
if err != nil {
|
||||
bot.logger.Errorln(err)
|
||||
}
|
||||
bot.requestLogger = nil
|
||||
}
|
||||
if bot.webHookLogger != nil {
|
||||
bot.logger.Warnln("Bot#webHookLogger present. You shouldn't set this, if ran in Long Polling mode!")
|
||||
err := bot.webHookLogger.Close()
|
||||
if err != nil {
|
||||
bot.logger.Errorln(err)
|
||||
}
|
||||
bot.webHookLogger = nil
|
||||
}
|
||||
|
||||
bot.ExecRunners(ctx)
|
||||
|
||||
|
||||
+5
-5
@@ -5,7 +5,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
// AddPrefixes adds one or more command prefixes (e.g., "/", "!").
|
||||
@@ -187,14 +187,14 @@ func (bot *Bot[T]) SetErrorTemplate(s string) *Bot[T] {
|
||||
// SetDebug enables or disables debug logging.
|
||||
func (bot *Bot[T]) SetDebug(debug bool) *Bot[T] {
|
||||
bot.debug = debug
|
||||
level := slog.FATAL
|
||||
level := sneklog.FATAL
|
||||
if debug {
|
||||
level = slog.DEBUG
|
||||
level = sneklog.DEBUG
|
||||
}
|
||||
|
||||
bot.logger.Level(level)
|
||||
if bot.RequestLogger != nil {
|
||||
bot.RequestLogger.Level(level)
|
||||
if bot.requestLogger != nil {
|
||||
bot.requestLogger.Level(level)
|
||||
}
|
||||
for _, p := range bot.plugins {
|
||||
if p.logger == nil {
|
||||
|
||||
+4
-4
@@ -129,7 +129,7 @@ func (bot *Bot[T]) AddRunner(runner Runner[T]) *Bot[T] {
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// bot.AddAppDataLoggerWriter(func(data *MyAppData) slog.LoggerWriter {
|
||||
// bot.AddAppDataLoggerWriter(func(data *MyAppData) sneklog.LoggerWriter {
|
||||
// return data.QueryLogger()
|
||||
// })
|
||||
func (bot *Bot[T]) AddAppDataLoggerWriter(writer AppDataLogger[T]) *Bot[T] {
|
||||
@@ -143,8 +143,8 @@ func (bot *Bot[T]) AddAppDataLoggerWriter(writer AppDataLogger[T]) *Bot[T] {
|
||||
}
|
||||
w := writer(bot.appData)
|
||||
bot.logger.AddWriter(w)
|
||||
if bot.RequestLogger != nil {
|
||||
bot.RequestLogger.AddWriter(w)
|
||||
if bot.requestLogger != nil {
|
||||
bot.requestLogger.AddWriter(w)
|
||||
}
|
||||
for _, l := range bot.managedExtraLoggers() {
|
||||
l.AddWriter(w)
|
||||
@@ -154,7 +154,7 @@ func (bot *Bot[T]) AddAppDataLoggerWriter(writer AppDataLogger[T]) *Bot[T] {
|
||||
p.logger.AddWriter(w)
|
||||
}
|
||||
}
|
||||
bot.addTokenReplacer(bot.logger, bot.RequestLogger)
|
||||
bot.addTokenReplacer(bot.logger, bot.requestLogger)
|
||||
bot.addTokenReplacer(bot.managedExtraLoggers()...)
|
||||
return bot
|
||||
}
|
||||
|
||||
+48
-22
@@ -13,7 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
type pollingRoundTripFunc func(*http.Request) (*http.Response, error)
|
||||
@@ -59,7 +59,7 @@ func TestGetUpdateTypesReturnsCopy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddPluginsSnapshotsConfiguration(t *testing.T) {
|
||||
bot := &Bot[NoData]{logger: slog.CreateLogger()}
|
||||
bot := &Bot[NoData]{logger: sneklog.CreateLogger()}
|
||||
plugin := NewPlugin[NoData]("demo")
|
||||
|
||||
cmd := plugin.NewCommand(func(ctx *MsgContext, db NoData) error { return nil }, "start")
|
||||
@@ -100,7 +100,7 @@ func TestBotPayloadTypeConfiguration(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddPluginsSkipsNilPlugin(t *testing.T) {
|
||||
bot := &Bot[NoData]{logger: slog.CreateLogger()}
|
||||
bot := &Bot[NoData]{logger: sneklog.CreateLogger()}
|
||||
plugin := NewPlugin[NoData]("demo")
|
||||
|
||||
bot.AddPlugins(nil, plugin)
|
||||
@@ -126,10 +126,10 @@ func TestInitLoggersFallsBackToStdoutLoggerOnFileError(t *testing.T) {
|
||||
if bot.logger == nil {
|
||||
t.Fatal("expected main logger fallback")
|
||||
}
|
||||
if bot.RequestLogger == nil {
|
||||
if bot.requestLogger == nil {
|
||||
t.Fatal("expected request logger fallback")
|
||||
}
|
||||
if err := bot.RequestLogger.Close(); err != nil {
|
||||
if err := bot.requestLogger.Close(); err != nil {
|
||||
t.Fatalf("failed to close request logger: %v", err)
|
||||
}
|
||||
if err := bot.logger.Close(); err != nil {
|
||||
@@ -177,11 +177,11 @@ func TestInitLoggersAppliesTokenReplacerToFileLoggers(t *testing.T) {
|
||||
bot.uploader.GetLogger().AddWriter(bot.uploader.GetLogger().CreateTextWriter(uploaderFile))
|
||||
|
||||
bot.logger.Infoln("main secret-token")
|
||||
bot.RequestLogger.Infoln("request secret-token")
|
||||
bot.requestLogger.Infoln("request secret-token")
|
||||
bot.api.GetLogger().Infoln("api secret-token")
|
||||
bot.uploader.GetLogger().Infoln("uploader secret-token")
|
||||
|
||||
if err := bot.RequestLogger.Close(); err != nil {
|
||||
if err := bot.requestLogger.Close(); err != nil {
|
||||
t.Fatalf("failed to close request logger: %v", err)
|
||||
}
|
||||
if err := bot.logger.Close(); err != nil {
|
||||
@@ -226,7 +226,7 @@ func TestInitLoggersAppliesTokenReplacerToFileLoggers(t *testing.T) {
|
||||
func TestAddPluginsAppliesTokenReplacerToPluginLogger(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
token: "secret-token",
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
}
|
||||
defer func() { _ = bot.logger.Close() }()
|
||||
|
||||
@@ -276,10 +276,10 @@ func TestNextPollRetryDelay(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddDatabaseLoggerWriterSkipsWhenAppDataIsUnset(t *testing.T) {
|
||||
bot := &Bot[NoData]{logger: slog.CreateLogger()}
|
||||
bot := &Bot[NoData]{logger: sneklog.CreateLogger()}
|
||||
called := false
|
||||
|
||||
bot.AddAppDataLoggerWriter(func(db NoData) slog.LoggerWriter {
|
||||
bot.AddAppDataLoggerWriter(func(db NoData) sneklog.LoggerWriter {
|
||||
called = true
|
||||
return nil
|
||||
})
|
||||
@@ -292,12 +292,12 @@ func TestAddDatabaseLoggerWriterSkipsWhenAppDataIsUnset(t *testing.T) {
|
||||
func TestAddDatabaseLoggerWriterSkipsWhenAppDataIsNil(t *testing.T) {
|
||||
type testDB struct{}
|
||||
|
||||
bot := &Bot[*testDB]{logger: slog.CreateLogger()}
|
||||
bot := &Bot[*testDB]{logger: sneklog.CreateLogger()}
|
||||
var db *testDB
|
||||
bot.SetAppData(db)
|
||||
|
||||
called := false
|
||||
bot.AddAppDataLoggerWriter(func(db *testDB) slog.LoggerWriter {
|
||||
bot.AddAppDataLoggerWriter(func(db *testDB) sneklog.LoggerWriter {
|
||||
called = true
|
||||
return nil
|
||||
})
|
||||
@@ -336,13 +336,13 @@ func TestShouldWarnOnValueAppData(t *testing.T) {
|
||||
func TestSetAppDataMarksValueWarningOnce(t *testing.T) {
|
||||
type testDB struct{}
|
||||
|
||||
bot := &Bot[testDB]{logger: slog.CreateLogger()}
|
||||
bot := &Bot[testDB]{logger: sneklog.CreateLogger()}
|
||||
bot.SetAppData(testDB{})
|
||||
if !bot.warnedValueData {
|
||||
t.Fatal("expected value-typed app data to mark warning state")
|
||||
}
|
||||
|
||||
ptrBot := &Bot[*testDB]{logger: slog.CreateLogger()}
|
||||
ptrBot := &Bot[*testDB]{logger: sneklog.CreateLogger()}
|
||||
ptrBot.SetAppData(&testDB{})
|
||||
if ptrBot.warnedValueData {
|
||||
t.Fatal("did not expect pointer-typed app data to mark warning state")
|
||||
@@ -350,7 +350,7 @@ func TestSetAppDataMarksValueWarningOnce(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetObserverAndGetObserver(t *testing.T) {
|
||||
bot := &Bot[NoData]{logger: slog.CreateLogger()}
|
||||
bot := &Bot[NoData]{logger: sneklog.CreateLogger()}
|
||||
observer := testObserver{}
|
||||
|
||||
if got := bot.GetObserver(); got != nil {
|
||||
@@ -364,7 +364,7 @@ func TestSetObserverAndGetObserver(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetObserverNilClearsObserver(t *testing.T) {
|
||||
bot := &Bot[NoData]{logger: slog.CreateLogger()}
|
||||
bot := &Bot[NoData]{logger: sneklog.CreateLogger()}
|
||||
bot.SetObserver(testObserver{})
|
||||
|
||||
if bot.GetObserver() == nil {
|
||||
@@ -382,7 +382,7 @@ func TestRunWithContextRejectsSecondRun(t *testing.T) {
|
||||
cancel()
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{{name: "demo"}},
|
||||
updateQueue: make(chan *tgapi.Update, 1),
|
||||
@@ -397,6 +397,32 @@ func TestRunWithContextRejectsSecondRun(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunWithContextKeepsEnabledRequestLogger(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
requestLogger := sneklog.CreateLogger()
|
||||
bot := &Bot[NoData]{
|
||||
logger: sneklog.CreateLogger(),
|
||||
requestLogger: requestLogger,
|
||||
useReqLogger: true,
|
||||
prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{{name: "demo"}},
|
||||
updateQueue: make(chan *tgapi.Update, 1),
|
||||
maxWorkers: 1,
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = bot.Close()
|
||||
})
|
||||
|
||||
if err := bot.RunWithContext(ctx); err != nil {
|
||||
t.Fatalf("RunWithContext returned error: %v", err)
|
||||
}
|
||||
if got := bot.GetRequestLogger(); got != requestLogger {
|
||||
t.Fatalf("expected enabled request logger to be preserved, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseDoesNotDeleteWebhook(t *testing.T) {
|
||||
requests := 0
|
||||
client := &http.Client{
|
||||
@@ -418,8 +444,8 @@ func TestCloseDoesNotDeleteWebhook(t *testing.T) {
|
||||
uploader := tgapi.NewUploader(api)
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
webHookLogger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
webHookLogger: sneklog.CreateLogger(),
|
||||
api: api,
|
||||
uploader: uploader,
|
||||
}
|
||||
@@ -457,7 +483,7 @@ func TestRunWithContextEmitsPollingRetryAndErrorEvents(t *testing.T) {
|
||||
}()
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
api: api,
|
||||
prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{{name: "demo"}},
|
||||
@@ -489,7 +515,7 @@ func TestBotConfigurationFreezesAfterRunStarts(t *testing.T) {
|
||||
|
||||
makeBot := func() *Bot[*testDB] {
|
||||
return &Bot[*testDB]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
updateTypes: []tgapi.UpdateType{tgapi.UpdateTypeMessage},
|
||||
payloadType: BotPayloadBase64,
|
||||
@@ -681,7 +707,7 @@ func TestBotConfigurationFreezesAfterRunStarts(t *testing.T) {
|
||||
|
||||
func TestAddPluginsAndRuntimeRegistrationsNoOpAfterRunStarts(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
middlewares: []Middleware[NoData]{NewMiddleware("base", func(ctx *MsgContext, db NoData) bool { return true })},
|
||||
runners: []Runner[NoData]{NewRunner("base", func(bot *Bot[NoData]) error { return nil })},
|
||||
|
||||
+22
-19
@@ -12,11 +12,12 @@ import (
|
||||
"git.scuroneko.dev/scuroneko/extypes"
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/laniakea/utils"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
"github.com/alitto/pond/v2"
|
||||
)
|
||||
|
||||
func (bot *Bot[T]) addTokenReplacer(loggers ...*slog.Logger) {
|
||||
func (bot *Bot[T]) addTokenReplacer(loggers ...*sneklog.Logger) {
|
||||
if bot.token == "" {
|
||||
return
|
||||
}
|
||||
@@ -28,7 +29,7 @@ func (bot *Bot[T]) addTokenReplacer(loggers ...*slog.Logger) {
|
||||
}
|
||||
}
|
||||
|
||||
func appendUniqueLogger(loggers []*slog.Logger, logger *slog.Logger) []*slog.Logger {
|
||||
func appendUniqueLogger(loggers []*sneklog.Logger, logger *sneklog.Logger) []*sneklog.Logger {
|
||||
if logger == nil {
|
||||
return loggers
|
||||
}
|
||||
@@ -38,8 +39,8 @@ func appendUniqueLogger(loggers []*slog.Logger, logger *slog.Logger) []*slog.Log
|
||||
return append(loggers, logger)
|
||||
}
|
||||
|
||||
func (bot *Bot[T]) managedExtraLoggers() []*slog.Logger {
|
||||
loggers := append([]*slog.Logger(nil), bot.extraLoggers...)
|
||||
func (bot *Bot[T]) managedExtraLoggers() []*sneklog.Logger {
|
||||
loggers := append([]*sneklog.Logger(nil), bot.extraLoggers...)
|
||||
if bot.api != nil {
|
||||
loggers = appendUniqueLogger(loggers, bot.api.GetLogger())
|
||||
}
|
||||
@@ -70,36 +71,38 @@ func (bot *Bot[T]) startUpdateWorkers(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (bot *Bot[T]) initLoggers(opts *BotOpts) {
|
||||
level := slog.FATAL
|
||||
level := sneklog.FATAL
|
||||
if opts.Debug {
|
||||
level = slog.DEBUG
|
||||
level = sneklog.DEBUG
|
||||
}
|
||||
|
||||
bot.logger = utils.CreateLogger("BOT", level)
|
||||
if opts.WriteToFile {
|
||||
path := fmt.Sprintf("%s/main.log", strings.TrimRight(opts.LoggerBasePath, "/"))
|
||||
logger, err := utils.CreateFileLogger("BOT", level, path)
|
||||
if err != nil {
|
||||
bot.logger.Errorln(err)
|
||||
} else {
|
||||
bot.logger = logger
|
||||
if bot.logger == nil {
|
||||
bot.logger = utils.CreateLogger("BOT", level)
|
||||
if opts.WriteToFile {
|
||||
path := fmt.Sprintf("%s/main.log", strings.TrimRight(opts.LoggerBasePath, "/"))
|
||||
logger, err := utils.CreateFileLogger("BOT", level, path)
|
||||
if err != nil {
|
||||
bot.logger.Errorln(err)
|
||||
} else {
|
||||
bot.logger = logger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.UseRequestLogger {
|
||||
bot.RequestLogger = utils.CreateLogger("REQUESTS", level)
|
||||
if opts.UseRequestLogger && bot.requestLogger == nil {
|
||||
bot.requestLogger = utils.CreateLogger("REQUESTS", level)
|
||||
if opts.WriteToFile {
|
||||
path := fmt.Sprintf("%s/requests.log", strings.TrimRight(opts.LoggerBasePath, "/"))
|
||||
logger, err := utils.CreateFileLogger("REQUESTS", level, path)
|
||||
if err != nil {
|
||||
bot.logger.Errorln(err)
|
||||
} else {
|
||||
bot.RequestLogger = logger
|
||||
bot.requestLogger = logger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bot.addTokenReplacer(bot.logger, bot.RequestLogger)
|
||||
bot.addTokenReplacer(bot.logger, bot.requestLogger)
|
||||
bot.addTokenReplacer(bot.managedExtraLoggers()...)
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -11,7 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
func TestEnqueueUpdateCopiesValue(t *testing.T) {
|
||||
@@ -35,7 +35,7 @@ func TestEnqueueUpdateCopiesValue(t *testing.T) {
|
||||
func TestUpdateHandlerEnqueuesUpdate(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
updateQueue: make(chan *tgapi.Update, 1),
|
||||
webHookLogger: slog.CreateLogger(),
|
||||
webHookLogger: sneklog.CreateLogger(),
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = bot.webHookLogger.Close()
|
||||
@@ -66,7 +66,7 @@ func TestUpdateHandlerEnqueuesUpdate(t *testing.T) {
|
||||
|
||||
func TestRunWebhookRuntimeRejectsSecondRun(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
updateQueue: make(chan *tgapi.Update, 1),
|
||||
maxWorkers: 1,
|
||||
}
|
||||
@@ -86,7 +86,7 @@ func TestRunWebhookRuntimeExecutesRunners(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
updateQueue: make(chan *tgapi.Update, 1),
|
||||
maxWorkers: 1,
|
||||
runners: []Runner[NoData]{
|
||||
@@ -185,7 +185,7 @@ func TestValidateWebhookTLSFiles(t *testing.T) {
|
||||
func TestUpdateHandlerRejectsOversizedBody(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
updateQueue: make(chan *tgapi.Update, 1),
|
||||
webHookLogger: slog.CreateLogger(),
|
||||
webHookLogger: sneklog.CreateLogger(),
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = bot.webHookLogger.Close()
|
||||
@@ -222,7 +222,7 @@ func TestStatusHandlerRequiresMatchingSecret(t *testing.T) {
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
api: api,
|
||||
webHookLogger: slog.CreateLogger(),
|
||||
webHookLogger: sneklog.CreateLogger(),
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = bot.webHookLogger.Close()
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
type roundTripFunc func(*http.Request) (*http.Response, error)
|
||||
@@ -51,7 +51,7 @@ func TestAutoGenerateCommandsChecksLimitBeforeDelete(t *testing.T) {
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
api: api,
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
plugins: []Plugin[NoData]{*plugin},
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
func TestDraftFlushRequiresChatID(t *testing.T) {
|
||||
@@ -24,7 +24,7 @@ func TestMsgContextNewDraftWorksWithoutLimiter(t *testing.T) {
|
||||
Msg: &tgapi.Message{
|
||||
Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate},
|
||||
},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
draftProvider: NewRandomDraftProvider(&tgapi.API{}),
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,7 @@ retract v1.0.0-rc.5
|
||||
|
||||
require (
|
||||
git.scuroneko.dev/scuroneko/extypes v1.2.3
|
||||
git.scuroneko.dev/scuroneko/slog v1.2.0
|
||||
github.com/alitto/pond/v2 v2.7.0
|
||||
git.scuroneko.dev/scuroneko/sneklog/v2 v2.0.1
|
||||
github.com/alitto/pond/v2 v2.7.1
|
||||
golang.org/x/time v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.19.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.21 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
git.scuroneko.dev/scuroneko/extypes v1.2.3 h1:n7QsfTZEn9fJNZLXGH/LkNq4cADaRk+LTu6LNMv9y6s=
|
||||
git.scuroneko.dev/scuroneko/extypes v1.2.3/go.mod h1:MhYpXC6sloLOpoM2guf64eSOrz+ET/QJZ8toobc3Ors=
|
||||
git.scuroneko.dev/scuroneko/slog v1.2.0 h1:xbwzrMcmN0NG/zTgEn508mn2JVnfZN5z/Zsi3PREfDM=
|
||||
git.scuroneko.dev/scuroneko/slog v1.2.0/go.mod h1:r+oz9NzvvdtWd9/PjeS+n5vQoNHL38BdcdLoBtJPvFU=
|
||||
github.com/alitto/pond/v2 v2.7.0 h1:c76L+yN916m/DRXjGCeUBHHu92uWnh/g1bwVk4zyyXg=
|
||||
github.com/alitto/pond/v2 v2.7.0/go.mod h1:xkjYEgQ05RSpWdfSd1nM3OVv7TBhLdy7rMp3+2Nq+yE=
|
||||
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
|
||||
github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
git.scuroneko.dev/scuroneko/sneklog/v2 v2.0.1 h1:nDGLsvxbYoSxSk9wrGCmb+tn5jPM+KYlBX+3ciyC2Yo=
|
||||
git.scuroneko.dev/scuroneko/sneklog/v2 v2.0.1/go.mod h1:q8XnLXzLdGjW0Jtcbh9/+G9WmfD68rsPQvLXEPxvum4=
|
||||
github.com/alitto/pond/v2 v2.7.1 h1:QxMbcfjcVTa0pyxX5Ib1226mM8u8D7gKUVkCUU4DYIw=
|
||||
github.com/alitto/pond/v2 v2.7.1/go.mod h1:xkjYEgQ05RSpWdfSd1nM3OVv7TBhLdy7rMp3+2Nq+yE=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
|
||||
+19
-19
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
type recordingObserver struct {
|
||||
@@ -55,7 +55,7 @@ func TestCheckPrefixesSkipsEmptyPrefixes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBotMiddlewareReceivesLogger(t *testing.T) {
|
||||
logger := slog.CreateLogger()
|
||||
logger := sneklog.CreateLogger()
|
||||
called := false
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
@@ -468,7 +468,7 @@ func TestHandleUpdateHandlersPopulateFromContext(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
|
||||
@@ -514,7 +514,7 @@ func TestHandleUpdateHandlersReceiveIsolatedContexts(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
plugins: []Plugin[NoData]{
|
||||
clonePlugin(first),
|
||||
clonePlugin(second),
|
||||
@@ -543,7 +543,7 @@ func TestHandleUpdateObserverEmitsUpdateErrors(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
observer: observer,
|
||||
}
|
||||
@@ -607,7 +607,7 @@ func TestHandleMessageFallbackRunsAfterCommandMiss(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
observer: observer,
|
||||
}
|
||||
@@ -658,7 +658,7 @@ func TestHandleMessageFallbackRunsForPlainText(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
}
|
||||
bot.AddPlugins(plugin)
|
||||
@@ -691,7 +691,7 @@ func TestHandleMessageFallbackRespectsMiddleware(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
}
|
||||
bot.AddPlugins(plugin)
|
||||
@@ -726,7 +726,7 @@ func TestHandleMessageFallbackDoesNotRunWhenCommandMatches(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
}
|
||||
bot.AddPlugins(plugin)
|
||||
@@ -771,7 +771,7 @@ func TestHandleChannelPostCommandWithSenderChat(t *testing.T) {
|
||||
}, "ping")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
@@ -808,7 +808,7 @@ func TestCommandHandlerBindArgsEndToEnd(t *testing.T) {
|
||||
)
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
@@ -845,7 +845,7 @@ func TestPayloadHandlerBindArgsEndToEnd(t *testing.T) {
|
||||
)
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
@@ -898,7 +898,7 @@ func TestHandleEditedMessageStaysOutOfCommandFlow(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
@@ -940,7 +940,7 @@ func TestHandleEditedChannelPostStaysOutOfCommandFlow(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
@@ -993,7 +993,7 @@ func TestHandleCallbackPopulatesMessageTargets(t *testing.T) {
|
||||
}, "approve")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
@@ -1052,7 +1052,7 @@ func TestHandleCallbackPopulatesInlineTargets(t *testing.T) {
|
||||
}, "inline.approve")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
}
|
||||
@@ -1086,7 +1086,7 @@ func TestHandleCallbackObserverEmitsPayloadEvents(t *testing.T) {
|
||||
}, "approve")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
observer: observer,
|
||||
@@ -1137,7 +1137,7 @@ func TestHandleCallbackObserverEmitsPayloadErrors(t *testing.T) {
|
||||
}, "approve")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
plugins: []Plugin[NoData]{clonePlugin(plugin)},
|
||||
observer: observer,
|
||||
@@ -1182,7 +1182,7 @@ func TestHandleCallbackObserverEmitsPayloadErrors(t *testing.T) {
|
||||
func TestHandleCallbackObserverEmitsDecodeErrors(t *testing.T) {
|
||||
observer := &recordingObserver{}
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
observer: observer,
|
||||
}
|
||||
|
||||
+2
-2
@@ -53,13 +53,13 @@ func (bot *Bot[T]) Updates(ctx context.Context) ([]tgapi.Update, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if bot.RequestLogger != nil {
|
||||
if bot.requestLogger != nil {
|
||||
for _, u := range updates {
|
||||
j, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
bot.GetLogger().Error(err)
|
||||
}
|
||||
bot.RequestLogger.Debugf("UPDATE %s\n", j)
|
||||
bot.requestLogger.Debugf("UPDATE %s\n", j)
|
||||
}
|
||||
}
|
||||
if len(updates) > 0 {
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
// MsgContext holds the normalized per-update context passed to command, payload,
|
||||
@@ -46,7 +46,7 @@ type MsgContext struct {
|
||||
|
||||
// Logger is the logger assigned by the matched plugin for the current handler call.
|
||||
// It may fall back to the bot logger when the plugin has no dedicated logger.
|
||||
Logger *slog.Logger
|
||||
Logger *sneklog.Logger
|
||||
|
||||
// InlineMsgId is the inline message identifier for callback queries that target
|
||||
// an inline message instead of a chat message.
|
||||
|
||||
+9
-9
@@ -10,7 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
func TestAnswerPhotoIncludesDirectMessagesTopicID(t *testing.T) {
|
||||
@@ -50,7 +50,7 @@ func TestAnswerPhotoIncludesDirectMessagesTopicID(t *testing.T) {
|
||||
Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate},
|
||||
DirectMessageTopic: &tgapi.DirectMessageTopic{TopicID: 77},
|
||||
},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
}
|
||||
|
||||
answer := ctx.AnswerPhoto("photo-id", "caption")
|
||||
@@ -202,7 +202,7 @@ func TestErrorDefaultRemainsUserVisibleForMessageFlow(t *testing.T) {
|
||||
ctx := &MsgContext{
|
||||
Api: api,
|
||||
Msg: &tgapi.Message{Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate}},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
errorTemplate: "Error: %s",
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ func TestErrorInternalSkipsUserReplyForMessageFlow(t *testing.T) {
|
||||
ctx := &MsgContext{
|
||||
Api: api,
|
||||
Msg: &tgapi.Message{Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate}},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
errorTemplate: "Error: %s",
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ func TestErrorInternalSkipsCallbackAnswer(t *testing.T) {
|
||||
|
||||
ctx := &MsgContext{
|
||||
Api: api,
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
errorTemplate: "%s",
|
||||
CallbackQueryId: "cb-1",
|
||||
}
|
||||
@@ -309,7 +309,7 @@ func TestErrorUserVisibleAnswersCallback(t *testing.T) {
|
||||
|
||||
ctx := &MsgContext{
|
||||
Api: api,
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
errorTemplate: "Oops: %s",
|
||||
CallbackQueryId: "cb-1",
|
||||
}
|
||||
@@ -327,7 +327,7 @@ func TestErrorUserVisibleAnswersCallback(t *testing.T) {
|
||||
func TestAnswerRejectsEmptyMessage(t *testing.T) {
|
||||
ctx := &MsgContext{
|
||||
Msg: &tgapi.Message{Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate}},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
}
|
||||
|
||||
if answer := ctx.Answer(""); answer != nil {
|
||||
@@ -357,7 +357,7 @@ func TestAnswerRejectsLongMessageWithoutSendingRequest(t *testing.T) {
|
||||
ctx := &MsgContext{
|
||||
Api: api,
|
||||
Msg: &tgapi.Message{Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate}},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
}
|
||||
|
||||
if answer := ctx.Answer(strings.Repeat("a", maxMessageTextLen+1)); answer != nil {
|
||||
@@ -441,7 +441,7 @@ func TestAnswerLongSplitsRequestsAndAttachesKeyboardToLastChunk(t *testing.T) {
|
||||
ctx := &MsgContext{
|
||||
Api: api,
|
||||
Msg: &tgapi.Message{Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate}},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
}
|
||||
kb := NewInlineKeyboardJson(1).AddCallbackButton("A", "cmd")
|
||||
text := strings.Repeat("a", maxMessageTextLen) + " " + strings.Repeat("b", 32)
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@ import (
|
||||
"git.scuroneko.dev/scuroneko/extypes"
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/laniakea/utils"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
// CommandValueType defines the expected type of command argument.
|
||||
@@ -169,7 +169,7 @@ type Plugin[T AppData] struct {
|
||||
scenes map[string]*Scene[T] // Optional scenes for multi-step interactions
|
||||
middlewares extypes.Slice[Middleware[T]] // Shared middlewares for all commands/payloads
|
||||
skipAutoCmd bool // If true, all commands in this plugin are excluded from auto-help
|
||||
logger *slog.Logger
|
||||
logger *sneklog.Logger
|
||||
|
||||
messageFallback CommandExecutor[T]
|
||||
handlers map[tgapi.UpdateType]CommandExecutor[T]
|
||||
@@ -293,7 +293,7 @@ func (p *Plugin[T]) SkipCommandAutoGen() *Plugin[T] {
|
||||
//
|
||||
// Call this before Bot.AddPlugins. If the plugin is already registered, changing
|
||||
// the original *Plugin does not update the Bot's internal copy.
|
||||
func (p *Plugin[T]) SetLogger(l *slog.Logger) *Plugin[T] {
|
||||
func (p *Plugin[T]) SetLogger(l *sneklog.Logger) *Plugin[T] {
|
||||
p.logger = l
|
||||
return p
|
||||
}
|
||||
|
||||
+13
-13
@@ -10,7 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
func TestRequirePolicyStopsExecutionOnDeniedPolicy(t *testing.T) {
|
||||
@@ -49,7 +49,7 @@ func TestRequirePolicyStopsExecutionOnDeniedPolicy(t *testing.T) {
|
||||
ctx := &MsgContext{
|
||||
Api: api,
|
||||
Msg: &tgapi.Message{Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate}},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
errorTemplate: "Error: %s",
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestRequirePrivateChatAllowsPrivateChat(t *testing.T) {
|
||||
Msg: &tgapi.Message{
|
||||
Chat: &tgapi.Chat{ID: 42, Type: tgapi.ChatTypePrivate},
|
||||
},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
}
|
||||
|
||||
if err := RequirePrivateChat[NoData]()(ctx, NoData{}); err != nil {
|
||||
@@ -86,7 +86,7 @@ func TestRequirePrivateChatDeniesNonPrivateChat(t *testing.T) {
|
||||
Msg: &tgapi.Message{
|
||||
Chat: &tgapi.Chat{ID: -100, Type: tgapi.ChatTypeSupergroup},
|
||||
},
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
}
|
||||
|
||||
err := RequirePrivateChat[NoData]()(ctx, NoData{})
|
||||
@@ -140,7 +140,7 @@ func TestRequireChatAdminUsesNormalizedIDs(t *testing.T) {
|
||||
Api: api,
|
||||
ChatID: -2001,
|
||||
FromID: 55,
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
}
|
||||
|
||||
if err := RequireChatAdmin[NoData]()(ctx, NoData{}); err != nil {
|
||||
@@ -168,7 +168,7 @@ func TestAllPoliciesReturnsFirstError(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
err := policy(&MsgContext{Logger: slog.CreateLogger()}, NoData{})
|
||||
err := policy(&MsgContext{Logger: sneklog.CreateLogger()}, NoData{})
|
||||
if !errors.Is(err, want) {
|
||||
t.Fatalf("expected first policy error, got %v", err)
|
||||
}
|
||||
@@ -180,7 +180,7 @@ func TestAnyPolicyAllowsLaterSuccessAfterInternalError(t *testing.T) {
|
||||
func(ctx *MsgContext, data NoData) error { return nil },
|
||||
)
|
||||
|
||||
if err := policy(&MsgContext{Logger: slog.CreateLogger()}, NoData{}); err != nil {
|
||||
if err := policy(&MsgContext{Logger: sneklog.CreateLogger()}, NoData{}); err != nil {
|
||||
t.Fatalf("expected later success to allow access, got %v", err)
|
||||
}
|
||||
}
|
||||
@@ -192,7 +192,7 @@ func TestAnyPolicyReturnsInternalErrorWhenNonePass(t *testing.T) {
|
||||
func(ctx *MsgContext, data NoData) error { return internal },
|
||||
)
|
||||
|
||||
err := policy(&MsgContext{Logger: slog.CreateLogger()}, NoData{})
|
||||
err := policy(&MsgContext{Logger: sneklog.CreateLogger()}, NoData{})
|
||||
if !errors.Is(err, internal) {
|
||||
t.Fatalf("expected internal error, got %v", err)
|
||||
}
|
||||
@@ -205,7 +205,7 @@ func TestAnyPolicyReturnsFirstDenyWhenNoPolicyPasses(t *testing.T) {
|
||||
func(ctx *MsgContext, data NoData) error { return AsUserError(errors.New("second deny")) },
|
||||
)
|
||||
|
||||
err := policy(&MsgContext{Logger: slog.CreateLogger()}, NoData{})
|
||||
err := policy(&MsgContext{Logger: sneklog.CreateLogger()}, NoData{})
|
||||
if !errors.Is(err, first) {
|
||||
t.Fatalf("expected first deny error, got %v", err)
|
||||
}
|
||||
@@ -215,7 +215,7 @@ func TestNotPolicyInvertsUserDenyButPreservesInternalErrors(t *testing.T) {
|
||||
inverted := NotPolicy(func(ctx *MsgContext, data NoData) error {
|
||||
return AsUserError(errors.New("denied"))
|
||||
})
|
||||
if err := inverted(&MsgContext{Logger: slog.CreateLogger()}, NoData{}); err != nil {
|
||||
if err := inverted(&MsgContext{Logger: sneklog.CreateLogger()}, NoData{}); err != nil {
|
||||
t.Fatalf("expected inverted deny to succeed, got %v", err)
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ func TestNotPolicyInvertsUserDenyButPreservesInternalErrors(t *testing.T) {
|
||||
preserve := NotPolicy(func(ctx *MsgContext, data NoData) error {
|
||||
return internal
|
||||
})
|
||||
err := preserve(&MsgContext{Logger: slog.CreateLogger()}, NoData{})
|
||||
err := preserve(&MsgContext{Logger: sneklog.CreateLogger()}, NoData{})
|
||||
if !errors.Is(err, internal) {
|
||||
t.Fatalf("expected internal error to be preserved, got %v", err)
|
||||
}
|
||||
@@ -233,7 +233,7 @@ func TestRequirePolicyEmitsObserverEvents(t *testing.T) {
|
||||
t.Run("allow", func(t *testing.T) {
|
||||
observer := &recordingObserver{}
|
||||
ctx := &MsgContext{
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
ctx: context.Background(),
|
||||
observer: observer,
|
||||
FromID: 10,
|
||||
@@ -258,7 +258,7 @@ func TestRequirePolicyEmitsObserverEvents(t *testing.T) {
|
||||
t.Run("deny", func(t *testing.T) {
|
||||
observer := &recordingObserver{}
|
||||
ctx := &MsgContext{
|
||||
Logger: slog.CreateLogger(),
|
||||
Logger: sneklog.CreateLogger(),
|
||||
ctx: context.Background(),
|
||||
observer: observer,
|
||||
errorTemplate: "%s",
|
||||
|
||||
+4
-4
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
type runnerObserver struct {
|
||||
@@ -17,7 +17,7 @@ type runnerObserver struct {
|
||||
func TestExecRunnersRunsOnetimeSyncRunner(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
runners: []Runner[NoData]{
|
||||
NewRunner("sync-once", func(*Bot[NoData]) error {
|
||||
calls.Add(1)
|
||||
@@ -39,7 +39,7 @@ func TestExecRunnersStopsBackgroundRunnerOnCancel(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
runners: []Runner[NoData]{
|
||||
NewRunner("background", func(*Bot[NoData]) error {
|
||||
if calls.Add(1) == 1 {
|
||||
@@ -71,7 +71,7 @@ func TestExecRunnersEmitObserverEvents(t *testing.T) {
|
||||
wantErr := errors.New("runner failed")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
observer: observer,
|
||||
runners: []Runner[NoData]{
|
||||
NewRunner("sync-once", func(*Bot[NoData]) error {
|
||||
|
||||
+17
-17
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
type failingSessionStore struct {
|
||||
@@ -56,7 +56,7 @@ func TestBotAddPluginsPreservesScenesAndHandlesThem(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -149,7 +149,7 @@ func TestEnterSceneRejectsMissingEntryConfiguration(t *testing.T) {
|
||||
plugin.NewScene("signup")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
}
|
||||
@@ -172,7 +172,7 @@ func TestEnterSceneRejectsMissingEntryConfiguration(t *testing.T) {
|
||||
plugin.NewScene("signup").SetEntry("start")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
}
|
||||
@@ -231,7 +231,7 @@ func TestSceneCommandHandlerRunsBeforeStep(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -279,7 +279,7 @@ func TestSceneCommandObserverEmitsLifecycleEvents(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -331,7 +331,7 @@ func TestSceneStepObserverEmitsLifecycleEvents(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -386,7 +386,7 @@ func TestSceneMessageObserverEmitsLifecycleEvents(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -453,7 +453,7 @@ func TestScenePayloadHandlerRunsBeforeStep(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -509,7 +509,7 @@ func TestScenePayloadObserverEmitsLifecycleEvents(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -572,7 +572,7 @@ func TestSceneUnmatchedPayloadFallsThroughWithoutRunningStep(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
payloadType: BotPayloadJson,
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -648,7 +648,7 @@ func TestScenePassDoesNotPersistSessionData(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -724,7 +724,7 @@ func TestSceneUnmatchedCommandFallsThroughWithoutRunningStep(t *testing.T) {
|
||||
}, "ping")
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -793,7 +793,7 @@ func TestSceneMessageFallbackRunsWhenNoCommandOrStepMatch(t *testing.T) {
|
||||
})
|
||||
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
prefixes: []string{"/"},
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
@@ -838,7 +838,7 @@ func TestSceneMessageFallbackRunsWhenNoCommandOrStepMatch(t *testing.T) {
|
||||
|
||||
func TestFindSceneSessionSupportsUserScopeWithoutMessage(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
sessionStore: NewMemorySessionStore(),
|
||||
sceneScopePriority: []SceneScope{SceneScopeUser, SceneScopeChat, SceneScopeUserChat},
|
||||
}
|
||||
@@ -865,7 +865,7 @@ func TestSceneStoreErrorsPropagate(t *testing.T) {
|
||||
|
||||
t.Run("find scene session get error", func(t *testing.T) {
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
sessionStore: failingSessionStore{getErr: getErr},
|
||||
sceneScopePriority: []SceneScope{SceneScopeUser},
|
||||
}
|
||||
@@ -881,7 +881,7 @@ func TestSceneStoreErrorsPropagate(t *testing.T) {
|
||||
return ctx.Stay(), nil
|
||||
})
|
||||
bot := &Bot[NoData]{
|
||||
logger: slog.CreateLogger(),
|
||||
logger: sneklog.CreateLogger(),
|
||||
sessionStore: failingSessionStore{setErr: setErr},
|
||||
sceneScopePriority: []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser},
|
||||
}
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/utils"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
// APIOpts holds configuration options for initializing the Telegram API client.
|
||||
@@ -85,7 +85,7 @@ func (opts *APIOpts) SetLimiterDrop(b bool) *APIOpts {
|
||||
type API struct {
|
||||
token string
|
||||
client *http.Client
|
||||
logger *slog.Logger
|
||||
logger *sneklog.Logger
|
||||
useTestServer bool
|
||||
apiUrl string
|
||||
|
||||
@@ -137,7 +137,7 @@ func (api *API) Close() error {
|
||||
|
||||
// GetLogger returns the internal logger for custom logging.
|
||||
// See https://core.telegram.org/bots/api
|
||||
func (api *API) GetLogger() *slog.Logger {
|
||||
func (api *API) GetLogger() *sneklog.Logger {
|
||||
return api.logger
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/laniakea/utils"
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -65,7 +65,7 @@ func (f UploaderFile) SetType(t UploaderFileType) UploaderFile {
|
||||
// (InputFile/multipart). For JSON-only calls (file_id, URL, plain params), use API.
|
||||
type Uploader struct {
|
||||
api *API
|
||||
logger *slog.Logger
|
||||
logger *sneklog.Logger
|
||||
}
|
||||
|
||||
// NewUploader creates a multipart uploader bound to an API client.
|
||||
@@ -85,7 +85,7 @@ func (u *Uploader) Close() error { return u.logger.Close() }
|
||||
|
||||
// GetLogger returns uploader logger instance.
|
||||
// See https://core.telegram.org/bots/api
|
||||
func (u *Uploader) GetLogger() *slog.Logger { return u.logger }
|
||||
func (u *Uploader) GetLogger() *sneklog.Logger { return u.logger }
|
||||
|
||||
// UploaderRequest is a low-level multipart upload request wrapper.
|
||||
//
|
||||
|
||||
+7
-7
@@ -3,22 +3,22 @@ package utils
|
||||
import (
|
||||
"os"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
// GetLoggerLevel returns DEBUG when DEBUG=true in env, otherwise FATAL.
|
||||
func GetLoggerLevel() slog.LogLevel {
|
||||
level := slog.FATAL
|
||||
func GetLoggerLevel() sneklog.LogLevel {
|
||||
level := sneklog.FATAL
|
||||
if os.Getenv("DEBUG") == "true" {
|
||||
level = slog.DEBUG
|
||||
level = sneklog.DEBUG
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
// CreateLogger creates a logger with the shared default policy:
|
||||
// JSON stdout output, provided prefix, and provided level.
|
||||
func CreateLogger(prefix string, level slog.LogLevel) *slog.Logger {
|
||||
logger := slog.CreateLogger().Level(level)
|
||||
func CreateLogger(prefix string, level sneklog.LogLevel) *sneklog.Logger {
|
||||
logger := sneklog.CreateLogger().Level(level)
|
||||
if prefix != "" {
|
||||
logger.Prefix(prefix)
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func CreateLogger(prefix string, level slog.LogLevel) *slog.Logger {
|
||||
//
|
||||
// The returned logger is always non-nil. When file writer creation fails, the
|
||||
// logger still writes to stdout and the error is returned to the caller.
|
||||
func CreateFileLogger(prefix string, level slog.LogLevel, filePath string) (*slog.Logger, error) {
|
||||
func CreateFileLogger(prefix string, level sneklog.LogLevel, filePath string) (*sneklog.Logger, error) {
|
||||
logger := CreateLogger(prefix, level)
|
||||
fileWriter, err := logger.CreateTextFileWriter(filePath)
|
||||
if err != nil {
|
||||
|
||||
+3
-3
@@ -6,13 +6,13 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.scuroneko.dev/scuroneko/slog"
|
||||
"git.scuroneko.dev/scuroneko/sneklog/v2"
|
||||
)
|
||||
|
||||
func TestCreateFileLoggerWritesToConfiguredFile(t *testing.T) {
|
||||
logPath := filepath.Join(t.TempDir(), "main.log")
|
||||
|
||||
logger, err := CreateFileLogger("TEST", slog.DEBUG, logPath)
|
||||
logger, err := CreateFileLogger("TEST", sneklog.DEBUG, logPath)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateFileLogger returned error: %v", err)
|
||||
}
|
||||
@@ -28,7 +28,7 @@ func TestCreateFileLoggerWritesToConfiguredFile(t *testing.T) {
|
||||
if !strings.Contains(string(data), "hello from file logger") {
|
||||
t.Fatalf("expected log message in file, got %q", string(data))
|
||||
}
|
||||
if !strings.Contains(string(data), "[TEST]") {
|
||||
if !strings.Contains(string(data), "TEST:") {
|
||||
t.Fatalf("expected prefix in file, got %q", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user