Logging
Go menyediakan package log untuk logging. Selain itu, ada banyak third-party logging package yang populer seperti logrus dan zap.
Contoh Masalah
Bagaimana cara:
- Menggunakan standard logger
- Membuat custom logger
- Mengatur log level
- Menulis log ke file
Penyelesaian
package main
import (
"fmt"
"io"
"log"
"os"
"path/filepath"
"runtime"
"sync"
"time"
)
// 1. Custom logger
type Logger struct {
*log.Logger
level LogLevel
}
type LogLevel int
const (
DEBUG LogLevel = iota
INFO
WARNING
ERROR
FATAL
)
var levelNames = map[LogLevel]string{
DEBUG: "DEBUG",
INFO: "INFO",
WARNING: "WARN",
ERROR: "ERROR",
FATAL: "FATAL",
}
// 2. Custom log formatter
func (l *Logger) log(level LogLevel, format string, v ...interface{}) {
if level < l.level {
return
}
// Get caller info
_, file, line, ok := runtime.Caller(2)
if !ok {
file = "???"
line = 0
}
file = filepath.Base(file)
// Format message
msg := fmt.Sprintf(format, v...)
l.Printf("[%s] %s:%d: %s",
levelNames[level], file, line, msg)
}
// 3. Logger methods
func (l *Logger) Debug(format string, v ...interface{}) {
l.log(DEBUG, format, v...)
}
func (l *Logger) Info(format string, v ...interface{}) {
l.log(INFO, format, v...)
}
func (l *Logger) Warn(format string, v ...interface{}) {
l.log(WARNING, format, v...)
}
func (l *Logger) Error(format string, v ...interface{}) {
l.log(ERROR, format, v...)
}
func (l *Logger) Fatal(format string, v ...interface{}) {
l.log(FATAL, format, v...)
os.Exit(1)
}
// 4. Logger factory
func NewLogger(out io.Writer, prefix string, level LogLevel) *Logger {
return &Logger{
Logger: log.New(out, prefix,
log.Ldate|log.Ltime|log.Lmicroseconds),
level: level,
}
}
// 5. Rotating file writer
type RotatingFileWriter struct {
sync.Mutex
filename string
maxSize int64
currentSize int64
file *os.File
}
func NewRotatingFileWriter(filename string, maxSize int64) (*RotatingFileWriter, error) {
file, err := os.OpenFile(filename,
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return nil, err
}
info, err := file.Stat()
if err != nil {
return nil, err
}
return &RotatingFileWriter{
filename: filename,
maxSize: maxSize,
currentSize: info.Size(),
file: file,
}, nil
}
func (w *RotatingFileWriter) Write(p []byte) (n int, err error) {
w.Lock()
defer w.Unlock()
if w.currentSize+int64(len(p)) > w.maxSize {
w.file.Close()
// Rotate file
backup := fmt.Sprintf("%s.%s",
w.filename,
time.Now().Format("2006-01-02-15-04-05"))
os.Rename(w.filename, backup)
// Create new file
w.file, err = os.OpenFile(w.filename,
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return 0, err
}
w.currentSize = 0
}
n, err = w.file.Write(p)
w.currentSize += int64(n)
return
}
func (w *RotatingFileWriter) Close() error {
w.Lock()
defer w.Unlock()
return w.file.Close()
}
// 6. Example application
type App struct {
logger *Logger
}
func (a *App) doSomething() {
a.logger.Debug("Debug message: %d", 42)
a.logger.Info("Info message: %s", "hello")
a.logger.Warn("Warning message: %v", true)
err := fmt.Errorf("something went wrong")
if err != nil {
a.logger.Error("Error occurred: %v", err)
}
}
func main() {
// Contoh 1: Standard logger
fmt.Println("Standard Logger Example:")
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.Println("This is a standard log message")
// Contoh 2: Custom logger with console output
fmt.Println("\nCustom Console Logger Example:")
consoleLogger := NewLogger(os.Stdout, "", DEBUG)
app := &App{logger: consoleLogger}
app.doSomething()
// Contoh 3: File logger with rotation
fmt.Println("\nRotating File Logger Example:")
rotatingWriter, err := NewRotatingFileWriter("app.log", 1024) // 1KB
if err != nil {
log.Fatal(err)
}
defer rotatingWriter.Close()
fileLogger := NewLogger(rotatingWriter, "", INFO)
app = &App{logger: fileLogger}
// Generate some log entries
for i := 0; i < 5; i++ {
app.doSomething()
time.Sleep(time.Millisecond * 100)
}
// Contoh 4: Multi-writer logger
fmt.Println("\nMulti-writer Logger Example:")
multiWriter := io.MultiWriter(os.Stdout, rotatingWriter)
multiLogger := NewLogger(multiWriter, "", WARNING)
app = &App{logger: multiLogger}
app.doSomething()
// Contoh 5: Different log levels
fmt.Println("\nLog Levels Example:")
levels := []LogLevel{DEBUG, INFO, WARNING, ERROR}
for _, level := range levels {
logger := NewLogger(os.Stdout, "", level)
fmt.Printf("\nLogger with level %s:\n", levelNames[level])
app = &App{logger: logger}
app.doSomething()
}
// Cleanup
os.Remove("app.log")
}
Penjelasan Kode
Basic Logging
- Standard logger
- Log levels
- Formatting
Advanced Features
- Custom logger
- File rotation
- Multi-writer
Best Practices
- Structured logging
- Error handling
- Performance
Output
Standard Logger Example:
2024/01/21 11:57:22 main.go:42: This is a standard log message
Custom Console Logger Example:
2024/01/21 11:57:22.123456 [DEBUG] main.go:42: Debug message: 42
2024/01/21 11:57:22.123456 [INFO] main.go:43: Info message: hello
2024/01/21 11:57:22.123456 [WARN] main.go:44: Warning message: true
2024/01/21 11:57:22.123456 [ERROR] main.go:47: Error occurred: something went wrong
Rotating File Logger Example:
[Writing to app.log...]
Multi-writer Logger Example:
2024/01/21 11:57:22.123456 [WARN] main.go:44: Warning message: true
2024/01/21 11:57:22.123456 [ERROR] main.go:47: Error occurred: something went wrong
Log Levels Example:
Logger with level DEBUG:
2024/01/21 11:57:22.123456 [DEBUG] main.go:42: Debug message: 42
2024/01/21 11:57:22.123456 [INFO] main.go:43: Info message: hello
2024/01/21 11:57:22.123456 [WARN] main.go:44: Warning message: true
2024/01/21 11:57:22.123456 [ERROR] main.go:47: Error occurred: something went wrong
Logger with level INFO:
2024/01/21 11:57:22.123456 [INFO] main.go:43: Info message: hello
2024/01/21 11:57:22.123456 [WARN] main.go:44: Warning message: true
2024/01/21 11:57:22.123456 [ERROR] main.go:47: Error occurred: something went wrong
Logger with level WARNING:
2024/01/21 11:57:22.123456 [WARN] main.go:44: Warning message: true
2024/01/21 11:57:22.123456 [ERROR] main.go:47: Error occurred: something went wrong
Logger with level ERROR:
2024/01/21 11:57:22.123456 [ERROR] main.go:47: Error occurred: something went wrong
Tips
- Gunakan log level yang sesuai
- Implementasi file rotation
- Log error dengan detail
- Pertimbangkan performance
- Backup log files