penambahan loger tersimpan

This commit is contained in:
2025-08-25 05:22:46 +07:00
parent 40af041bc9
commit f31924050f
4 changed files with 464 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
package main
import (
"fmt"
"log"
"time"
"api-service/pkg/logger"
)
func main() {
fmt.Println("Testing Dynamic Logging Functions...")
fmt.Println("====================================")
// Test fungsi penyimpanan log dinamis
testDynamicLogging()
// Tunggu sebentar untuk memastikan goroutine selesai
time.Sleep(500 * time.Millisecond)
fmt.Println("\n====================================")
fmt.Println("Dynamic logging test completed!")
fmt.Println("Check the log files in pkg/logger/data/ directory")
}
func testDynamicLogging() {
// Buat logger instance
loggerInstance := logger.New("test-app", logger.DEBUG, false)
// Test 1: Log dengan penyimpanan otomatis
fmt.Println("\n1. Testing automatic log saving...")
loggerInstance.LogAndSave(logger.INFO, "Application started successfully", map[string]interface{}{
"version": "1.0.0",
"build_date": time.Now().Format("2006-01-02"),
"environment": "development",
})
// Test 2: Log dengan request context
fmt.Println("\n2. Testing log with request context...")
requestLogger := loggerInstance.WithRequestID("req-001").WithCorrelationID("corr-001")
requestLogger.LogAndSave(logger.INFO, "User login attempt", map[string]interface{}{
"username": "john_doe",
"ip": "192.168.1.100",
"success": true,
})
// Test 3: Error logging
fmt.Println("\n3. Testing error logging...")
loggerInstance.LogAndSave(logger.ERROR, "Database connection failed", map[string]interface{}{
"error": "connection timeout",
"retry_count": 3,
"host": "db.example.com:5432",
})
// Test 4: Manual log entry saving
fmt.Println("\n4. Testing manual log entry saving...")
manualEntry := logger.LogEntry{
Timestamp: time.Now().Format(time.RFC3339),
Level: "DEBUG",
Service: "manual-test",
Message: "Manual log entry created",
RequestID: "manual-req-001",
CorrelationID: "manual-corr-001",
File: "main.go",
Line: 42,
Fields: map[string]interface{}{
"custom_field": "test_value",
"number": 123,
"active": true,
},
}
// Simpan manual ke berbagai format
if err := logger.SaveLogText(manualEntry); err != nil {
log.Printf("Error saving text log: %v", err)
} else {
fmt.Println("✓ Text log saved successfully")
}
if err := logger.SaveLogJSON(manualEntry); err != nil {
log.Printf("Error saving JSON log: %v", err)
} else {
fmt.Println("✓ JSON log saved successfully")
}
if err := logger.SaveLogToDatabase(manualEntry); err != nil {
log.Printf("Error saving database log: %v", err)
} else {
fmt.Println("✓ Database log saved successfully")
}
// Test 5: Performance logging dengan durasi
fmt.Println("\n5. Testing performance logging...")
start := time.Now()
// Simulasi proses yang memakan waktu
time.Sleep(200 * time.Millisecond)
duration := time.Since(start)
loggerInstance.LogAndSave(logger.INFO, "Data processing completed", map[string]interface{}{
"operation": "data_import",
"duration": duration.String(),
"duration_ms": duration.Milliseconds(),
"records": 1000,
"throughput": fmt.Sprintf("%.2f records/ms", 1000/float64(duration.Milliseconds())),
})
fmt.Println("\n✓ All logging tests completed successfully!")
}

View File

@@ -0,0 +1,94 @@
package logger
import (
"os"
"testing"
"time"
)
func TestDynamicLogging(t *testing.T) {
// Pastikan direktori data ada
os.RemoveAll("pkg/logger/data")
t.Run("TestSaveLogText", testSaveLogText)
t.Run("TestSaveLogJSON", testSaveLogJSON)
t.Run("TestSaveLogToDatabase", testSaveLogToDatabase)
t.Run("TestLogAndSave", testLogAndSave)
}
func testSaveLogText(t *testing.T) {
logger := New("test-service", INFO, false)
entry := LogEntry{
Timestamp: time.Now().Format(time.RFC3339),
Level: "INFO",
Service: "test-service",
Message: "Test log message",
File: "test.go",
Line: 10,
Fields: map[string]interface{}{
"test_field": "test_value",
"number": 42,
},
}
err := logger.SaveLogText(entry)
if err != nil {
t.Errorf("SaveLogText failed: %v", err)
}
// Verifikasi file dibuat
if _, err := os.Stat("pkg/logger/data/logs.txt"); os.IsNotExist(err) {
t.Error("Text log file was not created")
}
}
func testSaveLogJSON(t *testing.T) {
logger := New("test-service", INFO, false)
entry := LogEntry{
Timestamp: time.Now().Format(time.RFC3339),
Level: "INFO",
Service: "test-service",
Message: "Test JSON log message",
File: "test.go",
Line: 20,
Fields: map[string]interface{}{
"json_field": "json_value",
"count": 100,
},
}
err := logger.SaveLogJSON(entry)
if err != nil {
t.Errorf("SaveLogJSON failed: %v", err)
}
// Verifikasi file dibuat
if _, err := os.Stat("pkg/logger/data/logs.json"); os.IsNotExist(err) {
t.Error("JSON log file was not created")
}
}
func testSaveLogToDatabase(t *testing.T) {
logger := New("test-service", INFO, false)
entry := LogEntry{
Timestamp: time.Now().Format(time.RFC3339),
Level: "INFO",
Service: "test-service",
Message: "Test database log message",
File: "test.go",
Line: 30,
}
err := logger.SaveLogToDatabase(entry)
if err != nil {
t.Errorf("SaveLogToDatabase failed: %v", err)
}
// Verifikasi file dibuat (placeholder untuk database)
if _, err := os.Stat("pkg/logger/data/database_logs.txt"); os.IsNotExist(err) {
t.Error("Database log file was not created")
}
}

View File

@@ -0,0 +1,105 @@
package logger
import (
"fmt"
"time"
)
// ExampleDynamicLogging menunjukkan cara menggunakan fungsi penyimpanan log dinamis
func ExampleDynamicLogging() {
// Buat logger instance
logger := New("test-service", DEBUG, false)
// Contoh 1: Log biasa dengan penyimpanan otomatis
fmt.Println("=== Contoh 1: Log biasa dengan penyimpanan otomatis ===")
logger.LogAndSave(INFO, "Aplikasi dimulai", map[string]interface{}{
"version": "1.0.0",
"mode": "development",
})
// Contoh 2: Log dengan request ID
fmt.Println("\n=== Contoh 2: Log dengan request ID ===")
reqLogger := logger.WithRequestID("req-123456")
reqLogger.LogAndSave(INFO, "Request diproses", map[string]interface{}{
"endpoint": "/api/v1/users",
"method": "GET",
"user_id": 1001,
})
// Contoh 3: Log error
fmt.Println("\n=== Contoh 3: Log error ===")
logger.LogAndSave(ERROR, "Database connection failed", map[string]interface{}{
"error": "connection timeout",
"timeout": "30s",
"host": "localhost:5432",
})
// Contoh 4: Manual save ke berbagai format
fmt.Println("\n=== Contoh 4: Manual save ke berbagai format ===")
manualEntry := LogEntry{
Timestamp: time.Now().Format(time.RFC3339),
Level: "INFO",
Service: "manual-service",
Message: "Manual log entry",
RequestID: "manual-req-001",
File: "example.go",
Line: 42,
Fields: map[string]interface{}{
"custom_field": "custom_value",
"number": 42,
},
}
// Simpan manual ke berbagai format
if err := SaveLogText(manualEntry); err != nil {
fmt.Printf("Error saving text log: %v\n", err)
}
if err := SaveLogJSON(manualEntry); err != nil {
fmt.Printf("Error saving JSON log: %v\n", err)
}
if err := SaveLogToDatabase(manualEntry); err != nil {
fmt.Printf("Error saving to database log: %v\n", err)
}
// Contoh 5: Log dengan durasi
fmt.Println("\n=== Contoh 5: Log dengan durasi ===")
start := time.Now()
time.Sleep(100 * time.Millisecond) // Simulasi proses
duration := time.Since(start)
logger.LogAndSave(INFO, "Process completed", map[string]interface{}{
"operation": "data_processing",
"duration": duration.String(),
"items": 150,
})
fmt.Println("\n=== Semua log telah disimpan dalam berbagai format ===")
fmt.Println("1. Format teks dengan pemisah |: pkg/logger/data/logs.txt")
fmt.Println("2. Format JSON: pkg/logger/data/logs.json")
fmt.Println("3. Format database (placeholder): pkg/logger/data/database_logs.txt")
}
// ExampleMiddlewareLogging menunjukkan penggunaan dalam middleware
func ExampleMiddlewareLogging() {
fmt.Println("\n=== Contoh Penggunaan dalam Middleware ===")
middlewareLogger := New("middleware-service", INFO, false)
// Simulasi request processing
middlewareLogger.LogAndSave(INFO, "Request received", map[string]interface{}{
"method": "POST",
"path": "/api/v1/auth/login",
"client_ip": "192.168.1.100",
"user_agent": "Mozilla/5.0",
"content_type": "application/json",
})
// Simulasi response
middlewareLogger.LogAndSave(INFO, "Response sent", map[string]interface{}{
"status_code": 200,
"duration": "150ms",
"response_size": "2.5KB",
})
}

View File

@@ -376,3 +376,159 @@ func Fatal(msg string, fields ...map[string]interface{}) {
func Fatalf(format string, args ...interface{}) {
globalLogger.Fatalf(format, args...)
}
// SaveLogText menyimpan log dalam format teks dengan pemisah |
func (l *Logger) SaveLogText(entry LogEntry) error {
// Format log dengan pemisah |
logLine := fmt.Sprintf("%s|%s|%s|%s|%s|%s|%s|%s:%d",
entry.Timestamp,
entry.Level,
entry.Service,
entry.Message,
entry.RequestID,
entry.CorrelationID,
entry.Duration,
entry.File,
entry.Line)
// Tambahkan fields jika ada
if len(entry.Fields) > 0 {
fieldsStr := ""
for k, v := range entry.Fields {
fieldsStr += fmt.Sprintf("|%s=%v", k, v)
}
logLine += fieldsStr
}
logLine += "\n"
// Buat direktori jika belum ada
dirPath := "pkg/logger/data"
if err := os.MkdirAll(dirPath, 0755); err != nil {
return err
}
// Tulis ke file
filePath := dirPath + "/logs.txt"
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
if _, err := f.WriteString(logLine); err != nil {
return err
}
return nil
}
// SaveLogJSON menyimpan log dalam format JSON
func (l *Logger) SaveLogJSON(entry LogEntry) error {
jsonData, err := json.Marshal(entry)
if err != nil {
return err
}
// Buat direktori jika belum ada
dirPath := "pkg/logger/data"
if err := os.MkdirAll(dirPath, 0755); err != nil {
return err
}
// Tulis ke file
filePath := dirPath + "/logs.json"
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
if _, err := f.WriteString(string(jsonData) + "\n"); err != nil {
return err
}
return nil
}
// SaveLogToDatabase menyimpan log ke database
func (l *Logger) SaveLogToDatabase(entry LogEntry) error {
// Implementasi penyimpanan ke database
// Ini adalah contoh implementasi, sesuaikan dengan struktur database Anda
// Untuk saat ini, kita akan simpan ke file sebagai placeholder
// Anda dapat mengganti ini dengan koneksi database yang sesuai
dbLogLine := fmt.Sprintf("DB_LOG: %s|%s|%s|%s\n",
entry.Timestamp, entry.Level, entry.Service, entry.Message)
dirPath := "pkg/logger/data"
if err := os.MkdirAll(dirPath, 0755); err != nil {
return err
}
filePath := dirPath + "/database_logs.txt"
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
if _, err := f.WriteString(dbLogLine); err != nil {
return err
}
return nil
}
// LogAndSave melakukan logging dan menyimpan ke semua format
func (l *Logger) LogAndSave(level LogLevel, msg string, fields ...map[string]interface{}) {
// Panggil fungsi log biasa
l.log(level, msg, nil, fields...)
// Dapatkan entry log yang baru dibuat
_, file, line, ok := runtime.Caller(2)
var callerFile string
var callerLine int
if ok {
parts := strings.Split(file, "/")
if len(parts) > 2 {
callerFile = strings.Join(parts[len(parts)-2:], "/")
} else {
callerFile = file
}
callerLine = line
}
mergedFields := make(map[string]interface{})
for _, f := range fields {
for k, v := range f {
mergedFields[k] = v
}
}
entry := LogEntry{
Timestamp: time.Now().Format(time.RFC3339),
Level: levelStrings[level],
Service: l.serviceName,
Message: msg,
File: callerFile,
Line: callerLine,
Fields: mergedFields,
}
// Simpan ke semua format
go func() {
l.SaveLogText(entry)
l.SaveLogJSON(entry)
l.SaveLogToDatabase(entry)
}()
}
// Global fungsi untuk menyimpan log
func SaveLogText(entry LogEntry) error {
return globalLogger.SaveLogText(entry)
}
func SaveLogJSON(entry LogEntry) error {
return globalLogger.SaveLogJSON(entry)
}
func SaveLogToDatabase(entry LogEntry) error {
return globalLogger.SaveLogToDatabase(entry)
}