-
Notifications
You must be signed in to change notification settings - Fork 0
/
logger.go
133 lines (114 loc) · 4.56 KB
/
logger.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package navigator
import (
"fmt"
"sync"
"time"
"github.com/H0llyW00dzZ/K8sBlackPearl/language"
"go.uber.org/zap"
"golang.org/x/time/rate"
)
// LogFieldOption is a type that represents a function which returns a zap.Field.
// It's used to pass custom field generators to functions that create a slice of zap.Fields for logging.
// This allows for deferred creation of zap.Fields, which can be useful when the value of the field
// is not immediately available or when you want to include custom logic to determine the value of the field.
//
// Example usage:
//
// fields := navigator.CreateLogFields("sailing", "the high seas", navigator.WithAnyZapField(zap.Int("treasure chests", 5)))
// navigator.LogInfoWithEmoji("🏴☠️", "Pirates ahoy!", fields...)
type LogFieldOption func() zap.Field
// Logger is a package-level variable to access the zap logger throughout the worker package.
var Logger *zap.Logger
// mu is used to protect access to the Logger variable to make it safe for concurrent use.
var mu sync.Mutex
// logLimiter controls the rate of log output.
var logLimiter *rate.Limiter
// Initialize the rate limiter with a limit of 1 event per second and a burst size of 5.
func init() {
logLimiter = rate.NewLimiter(rate.Every(time.Second), 5)
}
// tryLog attempts to log a message if the rate limiter allows it.
func tryLog(logFunc func(string, ...zap.Field), emoji string, context string, fields ...zap.Field) {
if logLimiter.Allow() {
logFunc(emoji+" "+context, fields...)
}
}
// LogInfoWithEmojiRateLimited logs an informational message with rate limiting.
func LogInfoWithEmojiRateLimited(emoji string, context string, fields ...zap.Field) {
mu.Lock()
defer mu.Unlock()
if Logger == nil {
fmt.Printf(language.ErrorLoggerIsNotSet, context)
return
}
tryLog(Logger.Info, emoji, context, fields...)
}
// LogErrorWithEmojiRateLimited logs an error message with rate limiting.
func LogErrorWithEmojiRateLimited(emoji string, context string, fields ...zap.Field) {
mu.Lock()
defer mu.Unlock()
if Logger == nil {
fmt.Printf(language.ErrorLoggerIsNotSet, context)
return
}
tryLog(Logger.Info, emoji, context, fields...)
}
// SetLogger sets the logger instance for the package in a thread-safe manner.
func SetLogger(logger *zap.Logger) {
mu.Lock()
Logger = logger
mu.Unlock()
}
// LogInfoWithEmoji logs an informational message with a given emoji, context, and fields.
// It checks if the Logger is not nil before logging to prevent panics.
func LogInfoWithEmoji(emoji string, context string, fields ...zap.Field) {
mu.Lock()
defer mu.Unlock()
if Logger == nil {
fmt.Printf(language.ErrorLoggerIsNotSet, context)
return
}
Logger.Info(emoji+" "+context, fields...)
}
// logErrorWithEmoji logs an error message with a given emoji, context, and fields.
// It checks if the Logger is not nil before logging to prevent panics.
func LogErrorWithEmoji(emoji string, context string, fields ...zap.Field) {
mu.Lock()
defer mu.Unlock()
if Logger == nil {
fmt.Printf(language.ErrorLoggerIsNotSet, context)
return
}
Logger.Info(emoji+" "+context, fields...)
}
// WithAnyZapField creates a LogFieldOption that encapsulates a zap.Field for deferred addition to a log entry.
// This function is particularly handy when you have a custom field to add to your log that isn't
// already covered by existing "With*" functions. It allows for a more flexible and dynamic approach
// to logging, akin to how a pirate might prefer the freedom to navigate the open seas.
//
// Example:
//
// Let's say we want to log an event related to a pirate's treasure map. We have a custom binary field
// that represents the map, and we want to include this in our log fields. We can use WithAnyZapField
// to add this custom field to our logs as follows:
//
// treasureMap := []byte{0x0A, 0x0B, 0x0C, 0x0D} // This represents our treasure map in binary form.
// fields := navigator.CreateLogFields("sailing", "find treasure", navigator.WithAnyZapField(zap.Binary("treasureMap", treasureMap)))
// navigator.LogInfoWithEmoji("🏴☠️", "Found a treasure map!", fields...)
func WithAnyZapField(field zap.Field) LogFieldOption {
return func() zap.Field {
return field
}
}
// createLogFields creates a slice of zap.Field with the operation and additional info.
// It can be used to add structured context to logs.
func CreateLogFields(sailing string, shipsnamespace string, fieldOpts ...LogFieldOption) []zap.Field {
fields := []zap.Field{
zap.String("sailing", sailing),
zap.String("shipsnamespace", shipsnamespace),
}
for _, opt := range fieldOpts {
fields = append(fields, opt())
}
return fields
}