zlog: added notification support for log functions

This commit is contained in:
Tigor Hutasuhut 2024-08-27 17:31:32 +07:00
parent ab159d9426
commit 63c429285e
4 changed files with 107 additions and 44 deletions

View file

@ -193,8 +193,6 @@ func (mu *Err) GetTime() time.Time {
// ID sets the error ID. // ID sets the error ID.
// //
// ID is used to identify the error. Used by Zen to consider if an error is the same as another. // ID is used to identify the error. Used by Zen to consider if an error is the same as another.
//
// Current implementation
func (mu *Err) ID(msg string, args ...any) Error { func (mu *Err) ID(msg string, args ...any) Error {
mu.id = fmt.Sprintf(msg, args...) mu.id = fmt.Sprintf(msg, args...)
return mu return mu

View file

@ -12,140 +12,153 @@ import (
var Logger = New(os.Stderr, defaultOpts) var Logger = New(os.Stderr, defaultOpts)
func Info(ctx context.Context, msg string) { func Info(ctx context.Context, msg string) Notifier {
if !Logger.Enabled(ctx, slog.LevelInfo) { if !Logger.Enabled(ctx, slog.LevelInfo) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelInfo) return Log(ctx, msg, pc, t, slog.LevelInfo)
} }
func Infof(ctx context.Context, msg string, args ...any) { func Infof(ctx context.Context, msg string, args ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelInfo) { if !Logger.Enabled(ctx, slog.LevelInfo) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
msg = fmt.Sprintf(msg, args...) msg = fmt.Sprintf(msg, args...)
Log(ctx, msg, pc, t, slog.LevelInfo) return Log(ctx, msg, pc, t, slog.LevelInfo)
} }
func Infow(ctx context.Context, msg string, fields ...any) { func Infow(ctx context.Context, msg string, fields ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelInfo) { if !Logger.Enabled(ctx, slog.LevelInfo) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelInfo, fields...) return Log(ctx, msg, pc, t, slog.LevelInfo, fields...)
} }
func Debug(ctx context.Context, msg string) { func Debug(ctx context.Context, msg string) Notifier {
if !Logger.Enabled(ctx, slog.LevelDebug) { if !Logger.Enabled(ctx, slog.LevelDebug) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelDebug) return Log(ctx, msg, pc, t, slog.LevelDebug)
} }
func Debugf(ctx context.Context, msg string, args ...any) { func Debugf(ctx context.Context, msg string, args ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelDebug) { if !Logger.Enabled(ctx, slog.LevelDebug) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
msg = fmt.Sprintf(msg, args...) msg = fmt.Sprintf(msg, args...)
Log(ctx, msg, pc, t, slog.LevelDebug) return Log(ctx, msg, pc, t, slog.LevelDebug)
} }
func Debugw(ctx context.Context, msg string, fields ...any) { func Debugw(ctx context.Context, msg string, fields ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelDebug) { if !Logger.Enabled(ctx, slog.LevelDebug) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelDebug, fields...) return Log(ctx, msg, pc, t, slog.LevelDebug, fields...)
} }
func Warn(ctx context.Context, msg string) { func Warn(ctx context.Context, msg string) Notifier {
if !Logger.Enabled(ctx, slog.LevelWarn) { if !Logger.Enabled(ctx, slog.LevelWarn) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelWarn) return Log(ctx, msg, pc, t, slog.LevelWarn)
} }
func Warnf(ctx context.Context, msg string, args ...any) { func Warnf(ctx context.Context, msg string, args ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelWarn) { if !Logger.Enabled(ctx, slog.LevelWarn) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
msg = fmt.Sprintf(msg, args...) msg = fmt.Sprintf(msg, args...)
Log(ctx, msg, pc, t, slog.LevelWarn) return Log(ctx, msg, pc, t, slog.LevelWarn)
} }
func Warnw(ctx context.Context, msg string, fields ...any) { func Warnw(ctx context.Context, msg string, fields ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelWarn) { if !Logger.Enabled(ctx, slog.LevelWarn) {
return return notifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelWarn, fields...) return Log(ctx, msg, pc, t, slog.LevelWarn, fields...)
} }
func Error(ctx context.Context, msg string) { func Error(ctx context.Context, msg string) Notifier {
if !Logger.Enabled(ctx, slog.LevelError) { if !Logger.Enabled(ctx, slog.LevelError) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelError) return Log(ctx, msg, pc, t, slog.LevelError)
} }
func Errorf(ctx context.Context, msg string, args ...any) { func Errorf(ctx context.Context, msg string, args ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelError) { if !Logger.Enabled(ctx, slog.LevelError) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
msg = fmt.Sprintf(msg, args...) msg = fmt.Sprintf(msg, args...)
Log(ctx, msg, pc, t, slog.LevelError) return Log(ctx, msg, pc, t, slog.LevelError)
} }
func Errorw(ctx context.Context, msg string, fields ...any) { func Errorw(ctx context.Context, msg string, fields ...any) Notifier {
if !Logger.Enabled(ctx, slog.LevelError) { if !Logger.Enabled(ctx, slog.LevelError) {
return return nullNotifier{}
} }
pc := zcaller.Get(3) pc := zcaller.Get(3)
t := time.Now() t := time.Now()
Log(ctx, msg, pc, t, slog.LevelError, fields...) return Log(ctx, msg, pc, t, slog.LevelError, fields...)
} }
func LogRecord(ctx context.Context, record slog.Record) { func LogRecord(ctx context.Context, record slog.Record) Notifier {
if !Logger.Enabled(ctx, record.Level) { if !Logger.Enabled(ctx, record.Level) {
return return nullNotifier{}
} }
Logger.Handle(ctx, record) if err := Logger.Handle(ctx, record); err != nil {
slog.ErrorContext(ctx, "failed to log", "error", err)
}
notifier := &notifier{
ctx: ctx,
notifier: Logger.opts.NotificationHandler,
record: record,
}
return notifier
} }
func Log(ctx context.Context, msg string, pc uintptr, t time.Time, level slog.Level, fields ...any) { func Log(ctx context.Context, msg string, pc uintptr, t time.Time, level slog.Level, fields ...any) Notifier {
record := slog.NewRecord(t, level, msg, pc) record := slog.NewRecord(t, level, msg, pc)
record.Add(fields...) record.Add(fields...)
// error is only returned if the output writer fails. // error is only returned if the output writer fails.
if err := Logger.Handle(ctx, record); err != nil { if err := Logger.Handle(ctx, record); err != nil {
slog.ErrorContext(ctx, "failed to log", "error", err) slog.ErrorContext(ctx, "failed to log", "error", err)
} }
return &notifier{
ctx: ctx,
notifier: Logger.opts.NotificationHandler,
record: record,
}
} }
func SetDefault(log *ZLog) { func SetDefault(log *ZLog) {

View file

@ -8,11 +8,27 @@ import (
) )
type Notifier interface { type Notifier interface {
// Notify sends a notification from this Log Entry.
Notify(options ...zoptions.NotifyOption) Notify(options ...zoptions.NotifyOption)
} }
type NotificationHandler interface { type NotificationHandler interface {
NotifyLog(ctx context.Context, record slog.Record) NotifyLog(ctx context.Context, record slog.Record, options ...zoptions.NotifyOption)
} }
type notifyHandler struct{} type notifier struct {
ctx context.Context
notifier NotificationHandler
record slog.Record
}
func (no notifier) Notify(options ...zoptions.NotifyOption) {
if no.notifier == nil {
return
}
no.notifier.NotifyLog(no.ctx, no.record, options...)
}
type nullNotifier struct{}
func (nullNotifier) Notify(options ...zoptions.NotifyOption) {}

36
log.go
View file

@ -13,6 +13,9 @@ var (
// Use Infof to log with a format. // Use Infof to log with a format.
// //
// Use Infow to log with additional json fields. // Use Infow to log with additional json fields.
//
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
Info = zlog.Info Info = zlog.Info
// Infof logs a message at level Info with format. // Infof logs a message at level Info with format.
@ -24,6 +27,9 @@ var (
// Use Infow to print structs and maps since they will // Use Infow to print structs and maps since they will
// be rendered as json. // be rendered as json.
// //
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
//
// Example: // Example:
// //
// zen.Infof(ctx, "user '%s' logged in", user) // zen.Infof(ctx, "user '%s' logged in", user)
@ -50,6 +56,9 @@ var (
// //
// Note that primitive values are already optimized and will not use heavy reflection. // Note that primitive values are already optimized and will not use heavy reflection.
// //
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
//
// Example: // Example:
// //
// zen.Infow(ctx, "API called without error", // zen.Infow(ctx, "API called without error",
@ -68,6 +77,9 @@ var (
// Use [Debugf] to log with a format. // Use [Debugf] to log with a format.
// //
// Use [Debugw] to log with additional json fields. // Use [Debugw] to log with additional json fields.
//
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
Debug = zlog.Debug Debug = zlog.Debug
// Debugf logs a message at level Debug with format. // Debugf logs a message at level Debug with format.
@ -79,6 +91,9 @@ var (
// Use Debugw to print structs and maps since they will // Use Debugw to print structs and maps since they will
// be rendered as json. // be rendered as json.
// //
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
//
// Example: // Example:
// //
// zen.Debugf(ctx, "user '%s' logged in", user) // zen.Debugf(ctx, "user '%s' logged in", user)
@ -103,6 +118,9 @@ var (
// use it to serialize. // use it to serialize.
// Then for the last resort, use normal json.Marshal. // Then for the last resort, use normal json.Marshal.
// //
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
//
// Example: // Example:
// //
// zen.Debugw(ctx, "database query", // zen.Debugw(ctx, "database query",
@ -119,6 +137,9 @@ var (
// Use Warnf to log with a format. // Use Warnf to log with a format.
// //
// Use Warnw to log with additional json fields. // Use Warnw to log with additional json fields.
//
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
Warn = zlog.Warn Warn = zlog.Warn
// Warnf logs a message at level Warn with format. // Warnf logs a message at level Warn with format.
@ -130,6 +151,9 @@ var (
// Use Warnw to print structs and maps since they will // Use Warnw to print structs and maps since they will
// be rendered as json. // be rendered as json.
// //
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
//
// Example: // Example:
// //
// zen.Warnf(ctx, "user '%s' logged in", user) // zen.Warnf(ctx, "user '%s' logged in", user)
@ -153,6 +177,9 @@ var (
// If does not, it will look if it implements [json.Marshaler] interface and // If does not, it will look if it implements [json.Marshaler] interface and
// use it to serialize. // use it to serialize.
// Then for the last resort, use normal json.Marshal. // Then for the last resort, use normal json.Marshal.
//
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
Warnw = zlog.Warnw Warnw = zlog.Warnw
// Error logs a message at level Error. // Error logs a message at level Error.
@ -163,6 +190,9 @@ var (
// Use Errorf to log with a format. // Use Errorf to log with a format.
// //
// Use Errorw to log with additional json fields. // Use Errorw to log with additional json fields.
//
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
Error = zlog.Error Error = zlog.Error
// Errorf logs a message at level Error with format. // Errorf logs a message at level Error with format.
@ -174,6 +204,9 @@ var (
// Use Errorw to print structs and maps since they will // Use Errorw to print structs and maps since they will
// be rendered as json. // be rendered as json.
// //
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
//
// Example: // Example:
// //
// zen.Errorf(ctx, "user '%s' logged in", user) // zen.Errorf(ctx, "user '%s' logged in", user)
@ -198,6 +231,9 @@ var (
// use it to serialize. // use it to serialize.
// Then for the last resort, use normal json.Marshal. // Then for the last resort, use normal json.Marshal.
// //
// You can call .Notify on the returned Notifier to send a notification
// for this log entry.
//
// Example: // Example:
// //
// zlog.Errorw(ctx, "RPC Error", // zlog.Errorw(ctx, "RPC Error",