841 lines
22 KiB
Go
841 lines
22 KiB
Go
package main
|
||
|
||
import "C"
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
"path/filepath"
|
||
"runtime"
|
||
"syscall"
|
||
"time"
|
||
"unsafe"
|
||
|
||
"golang.org/x/sys/windows"
|
||
)
|
||
|
||
// LoggerWrapper 封装DLL调用
|
||
type LoggerWrapper struct {
|
||
dllHandle windows.Handle
|
||
createLogger uintptr
|
||
createContext uintptr
|
||
logInfo uintptr
|
||
logError uintptr
|
||
logWarning uintptr
|
||
logSuccess uintptr
|
||
freeString uintptr
|
||
closeAllLoggers uintptr
|
||
// cui
|
||
getLogs uintptr
|
||
getLogFiles uintptr
|
||
}
|
||
|
||
// 全局变量来跟踪创建的logger数量
|
||
var (
|
||
createdLoggers []string
|
||
loggerCount int
|
||
)
|
||
|
||
func NewLoggerWrapper(dllPath string) (*LoggerWrapper, error) {
|
||
if _, err := os.Stat(dllPath); os.IsNotExist(err) {
|
||
return nil, fmt.Errorf("DLL文件不存在: %s", dllPath)
|
||
}
|
||
|
||
dllHandle, err := windows.LoadLibrary(dllPath)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("加载DLL失败: %v", err)
|
||
}
|
||
|
||
wrapper := &LoggerWrapper{
|
||
dllHandle: dllHandle,
|
||
}
|
||
|
||
if err := wrapper.loadFunctions(); err != nil {
|
||
windows.FreeLibrary(dllHandle)
|
||
return nil, err
|
||
}
|
||
return wrapper, nil
|
||
}
|
||
|
||
func (lw *LoggerWrapper) loadFunctions() error {
|
||
var err error
|
||
|
||
lw.createLogger, err = windows.GetProcAddress(lw.dllHandle, "CreateLogger")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
lw.createContext, err = windows.GetProcAddress(lw.dllHandle, "CreateContextWithTaskType")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
lw.logInfo, err = windows.GetProcAddress(lw.dllHandle, "LogInfo")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
lw.logError, err = windows.GetProcAddress(lw.dllHandle, "LogError")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
lw.logWarning, err = windows.GetProcAddress(lw.dllHandle, "LogWarning")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
lw.logSuccess, err = windows.GetProcAddress(lw.dllHandle, "LogSuccess")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
lw.freeString, err = windows.GetProcAddress(lw.dllHandle, "FreeString")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
lw.closeAllLoggers, err = windows.GetProcAddress(lw.dllHandle, "CloseAllLoggers")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// cui
|
||
lw.getLogs, err = windows.GetProcAddress(lw.dllHandle, "GetLogs")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// cui
|
||
lw.getLogFiles, err = windows.GetProcAddress(lw.dllHandle, "GetLogFiles")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (lw *LoggerWrapper) CreateLogger(configJSON string) (string, error) {
|
||
configCStr, err := syscall.BytePtrFromString(configJSON)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
resultPtr, _, err := syscall.SyscallN(lw.createLogger, uintptr(unsafe.Pointer(configCStr)))
|
||
|
||
if err != syscall.Errno(0) {
|
||
return "", fmt.Errorf("CreateLogger调用失败: %v", err)
|
||
}
|
||
|
||
if resultPtr == 0 {
|
||
return "", fmt.Errorf("CreateLogger返回空指针")
|
||
}
|
||
|
||
result := readNullTerminatedString(resultPtr)
|
||
lw.FreeStringByPtr(resultPtr)
|
||
|
||
// 记录创建的logger
|
||
createdLoggers = append(createdLoggers, result)
|
||
loggerCount++
|
||
|
||
return result, nil
|
||
}
|
||
|
||
func (lw *LoggerWrapper) CreateContextWithTaskType(loggerHandle, taskType string) (string, error) {
|
||
loggerHandleCStr, err := syscall.BytePtrFromString(loggerHandle)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
taskTypeCStr, err := syscall.BytePtrFromString(taskType)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
resultPtr, _, err := syscall.SyscallN(
|
||
lw.createContext,
|
||
uintptr(unsafe.Pointer(loggerHandleCStr)),
|
||
uintptr(unsafe.Pointer(taskTypeCStr)),
|
||
)
|
||
|
||
if err != syscall.Errno(0) {
|
||
return "", fmt.Errorf("CreateContextWithTaskType调用失败: %v", err)
|
||
}
|
||
|
||
if resultPtr == 0 {
|
||
return "", fmt.Errorf("CreateContextWithTaskType返回空指针")
|
||
}
|
||
|
||
result := readNullTerminatedString(resultPtr)
|
||
lw.FreeStringByPtr(resultPtr)
|
||
return result, nil
|
||
}
|
||
|
||
func (lw *LoggerWrapper) LogInfo(ctxHandle, message string) error {
|
||
return lw.logMessage(ctxHandle, message, lw.logInfo)
|
||
}
|
||
|
||
func (lw *LoggerWrapper) LogError(ctxHandle, message string) error {
|
||
return lw.logMessage(ctxHandle, message, lw.logError)
|
||
}
|
||
|
||
func (lw *LoggerWrapper) LogWarning(ctxHandle, message string) error {
|
||
return lw.logMessage(ctxHandle, message, lw.logWarning)
|
||
}
|
||
|
||
func (lw *LoggerWrapper) LogSuccess(ctxHandle, message string) error {
|
||
return lw.logMessage(ctxHandle, message, lw.logSuccess)
|
||
}
|
||
|
||
func (lw *LoggerWrapper) logMessage(ctxHandle, message string, logFunc uintptr) error {
|
||
ctxHandleCStr, err := syscall.BytePtrFromString(ctxHandle)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
messageCStr, err := syscall.BytePtrFromString(message)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
_, _, err = syscall.SyscallN(
|
||
logFunc,
|
||
uintptr(unsafe.Pointer(ctxHandleCStr)),
|
||
uintptr(unsafe.Pointer(messageCStr)),
|
||
)
|
||
|
||
if err != syscall.Errno(0) {
|
||
return fmt.Errorf("日志记录失败: %v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// cui
|
||
func (lw *LoggerWrapper) GetLogs(loggerHandle, configJSON string) (string, error) {
|
||
loggerHandleCStr, err := syscall.BytePtrFromString(loggerHandle)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
configCStr, err := syscall.BytePtrFromString(configJSON)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
resultPtr, _, err := syscall.SyscallN(
|
||
lw.getLogs,
|
||
uintptr(unsafe.Pointer(loggerHandleCStr)),
|
||
uintptr(unsafe.Pointer(configCStr)),
|
||
)
|
||
|
||
if err != syscall.Errno(0) {
|
||
return "", fmt.Errorf("GetLogs调用失败: %v", err)
|
||
}
|
||
|
||
if resultPtr == 0 {
|
||
return "", fmt.Errorf("GetLogs返回空指针")
|
||
}
|
||
|
||
result := ptrToString(resultPtr)
|
||
lw.FreeStringByPtr(resultPtr)
|
||
return result, nil
|
||
}
|
||
|
||
// cui
|
||
func (lw *LoggerWrapper) GetLogFiles(loggerHandle string) (string, error) {
|
||
loggerHandleCStr, err := syscall.BytePtrFromString(loggerHandle)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
resultPtr, _, err := syscall.SyscallN(
|
||
lw.getLogFiles,
|
||
uintptr(unsafe.Pointer(loggerHandleCStr)),
|
||
)
|
||
|
||
if err != syscall.Errno(0) {
|
||
return "", fmt.Errorf("GetLogFiles调用失败: %v", err)
|
||
}
|
||
|
||
if resultPtr == 0 {
|
||
return "", fmt.Errorf("GetLogFiles返回空指针")
|
||
}
|
||
|
||
result := ptrToString(resultPtr)
|
||
lw.FreeStringByPtr(resultPtr)
|
||
return result, nil
|
||
}
|
||
|
||
func ptrToString(ptr uintptr) string {
|
||
if ptr == 0 {
|
||
return ""
|
||
}
|
||
// 先找到字符串长度
|
||
var length int
|
||
for {
|
||
b := *(*byte)(unsafe.Pointer(ptr + uintptr(length)))
|
||
if b == 0 {
|
||
break
|
||
}
|
||
length++
|
||
if length > 64*1024 { // 64KB限制
|
||
break
|
||
}
|
||
}
|
||
if length == 0 {
|
||
return ""
|
||
}
|
||
// 创建适当大小的切片
|
||
data := make([]byte, length)
|
||
for i := 0; i < length; i++ {
|
||
data[i] = *(*byte)(unsafe.Pointer(ptr + uintptr(i)))
|
||
}
|
||
return string(data)
|
||
}
|
||
|
||
func (lw *LoggerWrapper) FreeStringByPtr(ptr uintptr) {
|
||
if ptr != 0 {
|
||
syscall.SyscallN(lw.freeString, ptr)
|
||
}
|
||
}
|
||
|
||
func (lw *LoggerWrapper) CloseAllLoggers() (string, error) {
|
||
resultPtr, _, err := syscall.SyscallN(lw.closeAllLoggers)
|
||
if err != syscall.Errno(0) {
|
||
return "", fmt.Errorf("CloseAllLoggers调用失败: %v", err)
|
||
}
|
||
|
||
if resultPtr == 0 {
|
||
return "", fmt.Errorf("CloseAllLoggers返回空指针")
|
||
}
|
||
|
||
result := readNullTerminatedString(resultPtr)
|
||
lw.FreeStringByPtr(resultPtr)
|
||
return result, nil
|
||
}
|
||
|
||
func readNullTerminatedString(ptr uintptr) string {
|
||
if ptr == 0 {
|
||
return ""
|
||
}
|
||
|
||
var bytes []byte
|
||
for i := 0; i < 256; i++ {
|
||
b := *(*byte)(unsafe.Pointer(ptr + uintptr(i)))
|
||
if b == 0 {
|
||
break
|
||
}
|
||
bytes = append(bytes, b)
|
||
}
|
||
return string(bytes)
|
||
}
|
||
|
||
func (lw *LoggerWrapper) Close() error {
|
||
return windows.FreeLibrary(lw.dllHandle)
|
||
}
|
||
|
||
func checkError(result string) error {
|
||
if len(result) >= 6 && result[:6] == "错误:" {
|
||
return fmt.Errorf(result)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 监控内存
|
||
func monitorResources() {
|
||
var m runtime.MemStats
|
||
runtime.ReadMemStats(&m)
|
||
fmt.Printf("📊 内存使用: Alloc=%.2fMB, TotalAlloc=%.2fMB, Sys=%.2fMB, NumGC=%d, Goroutines=%d\n",
|
||
float64(m.Alloc)/1024/1024,
|
||
float64(m.TotalAlloc)/1024/1024,
|
||
float64(m.Sys)/1024/1024,
|
||
m.NumGC,
|
||
runtime.NumGoroutine())
|
||
}
|
||
|
||
// 测试日志读取功能 cui
|
||
func testLogReadingFunctions(wrapper *LoggerWrapper) {
|
||
fmt.Println("\n📖 ========== 开始日志读取功能测试 ==========")
|
||
|
||
// 创建测试logger
|
||
config := `{
|
||
"log_dir": "./test_logs_reading",
|
||
"level": 1,
|
||
"split_type": 1,
|
||
"max_size": 1048576,
|
||
"max_count": 5,
|
||
"enable_caller": true,
|
||
"default_task_type": "reading_test"
|
||
}`
|
||
|
||
loggerHandle, err := wrapper.CreateLogger(config)
|
||
if err != nil {
|
||
log.Printf("创建测试logger失败: %v", err)
|
||
return
|
||
}
|
||
fmt.Printf("✅ 创建测试logger: %s\n", loggerHandle)
|
||
|
||
// 创建不同任务类型的上下文
|
||
taskTypes := []string{"task_a", "task_b", "task_c"}
|
||
ctxHandles := make(map[string]string)
|
||
|
||
for _, taskType := range taskTypes {
|
||
ctxHandle, err := wrapper.CreateContextWithTaskType(loggerHandle, taskType)
|
||
if err != nil {
|
||
log.Printf("创建上下文失败: %v", err)
|
||
continue
|
||
}
|
||
ctxHandles[taskType] = ctxHandle
|
||
fmt.Printf("✅ 创建上下文: %s -> %s\n", taskType, ctxHandle)
|
||
}
|
||
|
||
// 记录测试日志
|
||
fmt.Println("\n📝 记录测试日志数据...")
|
||
messages := []struct {
|
||
level string
|
||
message string
|
||
task string
|
||
}{
|
||
{"INFO", "这是INFO级别的测试消息", "task_a"},
|
||
{"ERROR", "这是ERROR级别的错误消息", "task_b"},
|
||
{"WARNING", "这是WARNING级别的警告消息", "task_c"},
|
||
{"SUCCESS", "这是SUCCESS级别的成功消息", "task_a"},
|
||
{"INFO", "另一条INFO消息", "task_b"},
|
||
}
|
||
|
||
for i, msg := range messages {
|
||
var err error
|
||
switch msg.level {
|
||
case "INFO":
|
||
err = wrapper.LogInfo(ctxHandles[msg.task], fmt.Sprintf("%s - 序号: %d", msg.message, i))
|
||
case "ERROR":
|
||
err = wrapper.LogError(ctxHandles[msg.task], fmt.Sprintf("%s - 序号: %d", msg.message, i))
|
||
case "WARNING":
|
||
err = wrapper.LogWarning(ctxHandles[msg.task], fmt.Sprintf("%s - 序号: %d", msg.message, i))
|
||
case "SUCCESS":
|
||
err = wrapper.LogSuccess(ctxHandles[msg.task], fmt.Sprintf("%s - 序号: %d", msg.message, i))
|
||
}
|
||
if err != nil {
|
||
log.Printf("记录日志失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 记录%s日志: %s\n", msg.level, msg.message)
|
||
}
|
||
}
|
||
|
||
// 等待一下确保日志写入完成
|
||
time.Sleep(100 * time.Millisecond)
|
||
|
||
// 测试1: 获取日志文件列表
|
||
fmt.Println("\n📁 测试1: 获取日志文件列表")
|
||
filesResult, err := wrapper.GetLogFiles(loggerHandle)
|
||
if err != nil {
|
||
log.Printf("获取日志文件列表失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 获取日志文件列表成功:\n%s\n", formatJSON(filesResult))
|
||
}
|
||
|
||
// 测试2: 获取所有日志
|
||
fmt.Println("\n📄 测试2: 获取所有日志")
|
||
allLogsConfig := `{
|
||
"level": -1,
|
||
"max_entries": 50
|
||
}`
|
||
allLogsResult, err := wrapper.GetLogs(loggerHandle, allLogsConfig)
|
||
if err != nil {
|
||
log.Printf("获取所有日志失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 获取所有日志成功:\n%s\n", formatJSON(allLogsResult))
|
||
}
|
||
|
||
// 测试3: 按级别过滤日志
|
||
fmt.Println("\n🔍 测试3: 按级别过滤日志(INFO)")
|
||
infoLogsConfig := `{
|
||
"level": 1,
|
||
"max_entries": 10
|
||
}`
|
||
infoLogsResult, err := wrapper.GetLogs(loggerHandle, infoLogsConfig)
|
||
if err != nil {
|
||
log.Printf("获取INFO日志失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 获取INFO日志成功:\n%s\n", formatJSON(infoLogsResult))
|
||
}
|
||
|
||
// 测试4: 按任务类型过滤日志
|
||
fmt.Println("\n🔍 测试4: 按任务类型过滤日志(task_a)")
|
||
taskALogsConfig := `{
|
||
"level": -1,
|
||
"task_type": "task_a",
|
||
"max_entries": 10
|
||
}`
|
||
taskALogsResult, err := wrapper.GetLogs(loggerHandle, taskALogsConfig)
|
||
if err != nil {
|
||
log.Printf("获取task_a日志失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 获取task_a日志成功:\n%s\n", formatJSON(taskALogsResult))
|
||
}
|
||
|
||
// 测试5: 限制返回条目数
|
||
fmt.Println("\n🔍 测试5: 限制返回条目数(2条)")
|
||
limitedLogsConfig := `{
|
||
"level": -1,
|
||
"max_entries": 2
|
||
}`
|
||
limitedLogsResult, err := wrapper.GetLogs(loggerHandle, limitedLogsConfig)
|
||
if err != nil {
|
||
log.Printf("获取限制条目日志失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 获取限制条目日志成功:\n%s\n", formatJSON(limitedLogsResult))
|
||
}
|
||
|
||
// 测试6: 组合条件查询
|
||
fmt.Println("\n🔍 测试6: 组合条件查询(ERROR级别 + task_b)")
|
||
combinedConfig := `{
|
||
"level": 3,
|
||
"task_type": "task_b",
|
||
"max_entries": 10
|
||
}`
|
||
combinedResult, err := wrapper.GetLogs(loggerHandle, combinedConfig)
|
||
if err != nil {
|
||
log.Printf("组合条件查询失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 组合条件查询成功:\n%s\n", formatJSON(combinedResult))
|
||
}
|
||
|
||
// 测试7: 组合条件查询
|
||
fmt.Println("\n🔍 测试7: 组合条件查询(task_b)")
|
||
combinedTimeConfig := `{
|
||
"level": -1,
|
||
"task_type": "task_b",
|
||
"start_time": "2025-11-25 15:03:31",
|
||
"end_time": "2025-11-25 15:04:31",
|
||
"max_entries": 10
|
||
}`
|
||
combinedTimeResult, err := wrapper.GetLogs(loggerHandle, combinedTimeConfig)
|
||
if err != nil {
|
||
log.Printf("组合条件查询失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ 组合条件查询成功:\n%s\n", formatJSON(combinedTimeResult))
|
||
}
|
||
|
||
// 解析并分析结果
|
||
fmt.Println("\n📊 日志读取功能测试分析:")
|
||
analyzeLogReadingResults(allLogsResult)
|
||
|
||
fmt.Println("✅ 日志读取功能测试完成")
|
||
}
|
||
|
||
// 分析日志读取结果 cui
|
||
func analyzeLogReadingResults(logsResult string) {
|
||
var result map[string]interface{}
|
||
if err := json.Unmarshal([]byte(logsResult), &result); err != nil {
|
||
log.Printf("解析日志结果失败: %v", err)
|
||
return
|
||
}
|
||
|
||
if errorMsg, exists := result["error"]; exists {
|
||
fmt.Printf("❌ 错误: %v\n", errorMsg)
|
||
return
|
||
}
|
||
|
||
count, _ := result["count"].(float64)
|
||
entries, _ := result["entries"].([]interface{})
|
||
|
||
fmt.Printf(" 总日志条目数: %.0f\n", count)
|
||
|
||
// 统计各级别日志数量
|
||
levelCount := make(map[string]int)
|
||
taskCount := make(map[string]int)
|
||
|
||
for _, entry := range entries {
|
||
if entryMap, ok := entry.(map[string]interface{}); ok {
|
||
level, _ := entryMap["level"].(string)
|
||
taskType, _ := entryMap["task_type"].(string)
|
||
levelCount[level]++
|
||
taskCount[taskType]++
|
||
}
|
||
}
|
||
|
||
fmt.Println(" 日志级别分布:")
|
||
for level, count := range levelCount {
|
||
fmt.Printf(" - %s: %d条\n", level, count)
|
||
}
|
||
|
||
fmt.Println(" 任务类型分布:")
|
||
for taskType, count := range taskCount {
|
||
fmt.Printf(" - %s: %d条\n", taskType, count)
|
||
}
|
||
}
|
||
|
||
// 格式化JSON输出 cui
|
||
func formatJSON(jsonStr string) string {
|
||
var result map[string]interface{}
|
||
if err := json.Unmarshal([]byte(jsonStr), &result); err != nil {
|
||
return jsonStr // 返回原始字符串如果解析失败
|
||
}
|
||
|
||
formatted, err := json.MarshalIndent(result, " ", " ")
|
||
if err != nil {
|
||
return jsonStr
|
||
}
|
||
return string(formatted)
|
||
}
|
||
|
||
// 测试资源回收的核心函数
|
||
func testResourceCleanup(wrapper *LoggerWrapper) {
|
||
fmt.Println("🧪 开始资源回收验证测试")
|
||
|
||
// 测试配置
|
||
config := `{
|
||
"log_dir": "./resource_cleanup_test",
|
||
"level": 1,
|
||
"split_type": 1,
|
||
"max_size": 1048576,
|
||
"max_count": 3,
|
||
"enable_caller": false,
|
||
"default_task_type": "cleanup_test"
|
||
}`
|
||
|
||
// 阶段1: 创建多个logger并记录初始状态
|
||
fmt.Println("\n📝 阶段1: 创建测试logger")
|
||
activeLoggers := make([]string, 0)
|
||
idleLoggers := make([]string, 0)
|
||
|
||
// 创建6个logger,3个活跃,3个闲置
|
||
for i := 0; i < 6; i++ {
|
||
loggerHandle, err := wrapper.CreateLogger(config)
|
||
if err != nil {
|
||
log.Printf("创建logger %d 失败: %v", i, err)
|
||
continue
|
||
}
|
||
|
||
if i < 3 {
|
||
activeLoggers = append(activeLoggers, loggerHandle)
|
||
fmt.Printf("✅ 创建活跃logger %d: %s\n", i, loggerHandle)
|
||
} else {
|
||
idleLoggers = append(idleLoggers, loggerHandle)
|
||
fmt.Printf("✅ 创建闲置logger %d: %s\n", i, loggerHandle)
|
||
}
|
||
}
|
||
|
||
fmt.Printf("\n📊 创建统计: 活跃logger=%d, 闲置logger=%d, 总计=%d\n",
|
||
len(activeLoggers), len(idleLoggers), len(activeLoggers)+len(idleLoggers))
|
||
|
||
// 阶段2: 使用活跃logger,让闲置logger保持不使用状态
|
||
fmt.Println("\n📝 阶段2: 使用活跃logger")
|
||
for i, loggerHandle := range activeLoggers {
|
||
ctxHandle, err := wrapper.CreateContextWithTaskType(loggerHandle, fmt.Sprintf("active_task_%d", i))
|
||
if err != nil {
|
||
log.Printf("创建上下文失败: %v", err)
|
||
continue
|
||
}
|
||
|
||
// 记录多条日志确保活跃状态
|
||
for j := 0; j < 5; j++ {
|
||
message := fmt.Sprintf("活跃logger %d - 消息 %d - 时间: %s", i, j, time.Now().Format("15:04:05"))
|
||
err = wrapper.LogInfo(ctxHandle, message)
|
||
if err != nil {
|
||
log.Printf("记录日志失败: %v", err)
|
||
}
|
||
}
|
||
fmt.Printf("✅ 活跃logger %d 已使用: %s\n", i, loggerHandle)
|
||
}
|
||
|
||
// 记录当前资源状态
|
||
fmt.Println("\n📊 资源使用前状态:")
|
||
monitorResources()
|
||
|
||
// 阶段3: 模拟时间流逝并验证资源回收
|
||
fmt.Println("\n⏰ 阶段3: 模拟时间流逝等待资源回收")
|
||
fmt.Println(" 自动清理机制: 每30分钟运行一次,清理2小时未使用的资源")
|
||
fmt.Println(" 由于测试时间限制,我们将观察资源使用模式...")
|
||
|
||
// 多次采样资源使用情况来观察趋势
|
||
fmt.Println("\n📈 资源使用趋势观察:")
|
||
initialMemory := getMemoryUsage()
|
||
|
||
for i := 0; i < 3; i++ {
|
||
fmt.Printf("\n 采样 %d:\n", i+1)
|
||
monitorResources()
|
||
|
||
// 继续使用活跃logger以保持其活跃状态
|
||
for _, loggerHandle := range activeLoggers {
|
||
ctxHandle, err := wrapper.CreateContextWithTaskType(loggerHandle, "keep_alive")
|
||
if err == nil {
|
||
wrapper.LogInfo(ctxHandle, fmt.Sprintf("保持活跃 - 采样 %d", i+1))
|
||
}
|
||
}
|
||
|
||
time.Sleep(2 * time.Second)
|
||
}
|
||
|
||
finalMemory := getMemoryUsage()
|
||
memoryChange := finalMemory - initialMemory
|
||
|
||
fmt.Printf("\n📊 内存变化: %.2fMB\n", memoryChange)
|
||
|
||
// 阶段4: 验证闲置logger的状态
|
||
fmt.Println("\n🔍 阶段4: 验证闲置logger状态")
|
||
stillWorkingCount := 0
|
||
for i, loggerHandle := range idleLoggers {
|
||
ctxHandle, err := wrapper.CreateContextWithTaskType(loggerHandle, "test_after_idle")
|
||
if err != nil {
|
||
fmt.Printf("❌ 闲置logger %d 可能已被回收: %s -> %v\n", i, loggerHandle, err)
|
||
} else {
|
||
// 尝试记录日志
|
||
err = wrapper.LogInfo(ctxHandle, "测试闲置logger是否仍然工作")
|
||
if err != nil {
|
||
fmt.Printf("❌ 闲置logger %d 记录日志失败: %s -> %v\n", i, loggerHandle, err)
|
||
} else {
|
||
fmt.Printf("✅ 闲置logger %d 仍然工作: %s\n", i, loggerHandle)
|
||
stillWorkingCount++
|
||
}
|
||
}
|
||
}
|
||
|
||
// 阶段5: 验证活跃logger的状态
|
||
fmt.Println("\n🔍 阶段5: 验证活跃logger状态")
|
||
activeWorkingCount := 0
|
||
for i, loggerHandle := range activeLoggers {
|
||
ctxHandle, err := wrapper.CreateContextWithTaskType(loggerHandle, "test_active")
|
||
if err != nil {
|
||
fmt.Printf("❌ 活跃logger %d 异常: %s -> %v\n", i, loggerHandle, err)
|
||
} else {
|
||
err = wrapper.LogInfo(ctxHandle, "测试活跃logger是否正常工作")
|
||
if err != nil {
|
||
fmt.Printf("❌ 活跃logger %d 记录日志失败: %s -> %v\n", i, loggerHandle, err)
|
||
} else {
|
||
fmt.Printf("✅ 活跃logger %d 正常工作: %s\n", i, loggerHandle)
|
||
activeWorkingCount++
|
||
}
|
||
}
|
||
}
|
||
|
||
// 阶段6: 分析测试结果
|
||
fmt.Println("\n📋 阶段6: 资源回收测试结果分析")
|
||
fmt.Printf(" 初始创建: %d 个logger\n", len(activeLoggers)+len(idleLoggers))
|
||
fmt.Printf(" 活跃logger正常: %d/%d\n", activeWorkingCount, len(activeLoggers))
|
||
fmt.Printf(" 闲置logger仍然工作: %d/%d\n", stillWorkingCount, len(idleLoggers))
|
||
fmt.Printf(" 内存变化: %.2fMB\n", memoryChange)
|
||
|
||
// 资源回收效果评估
|
||
if stillWorkingCount < len(idleLoggers) {
|
||
fmt.Println("🎯 资源回收效果: ✅ 检测到可能的资源回收")
|
||
fmt.Println(" 说明: 部分闲置logger无法使用,可能已被自动清理机制回收")
|
||
} else {
|
||
fmt.Println("🎯 资源回收效果: ⚠️ 未检测到明显的资源回收")
|
||
fmt.Println(" 说明: 所有logger仍然可用,可能因为:")
|
||
fmt.Println(" - 测试时间不足以触发自动清理")
|
||
fmt.Println(" - 自动清理机制配置时间较长")
|
||
fmt.Println(" - 所有logger仍被认定为活跃状态")
|
||
}
|
||
|
||
// 阶段7: 显式清理
|
||
fmt.Println("\n🧹 阶段7: 显式清理所有资源")
|
||
result, err := wrapper.CloseAllLoggers()
|
||
if err != nil {
|
||
log.Printf("关闭所有logger失败: %v", err)
|
||
} else {
|
||
fmt.Printf("✅ %s\n", result)
|
||
}
|
||
|
||
// 最终资源状态
|
||
fmt.Println("\n📊 最终资源状态:")
|
||
monitorResources()
|
||
|
||
fmt.Println("🧪 资源回收验证测试完成")
|
||
}
|
||
|
||
func getMemoryUsage() float64 {
|
||
var m runtime.MemStats
|
||
runtime.ReadMemStats(&m)
|
||
return float64(m.Alloc) / 1024 / 1024
|
||
}
|
||
|
||
// 文件系统资源检查
|
||
func checkFileSystemResources() {
|
||
fmt.Println("\n📁 文件系统资源检查:")
|
||
|
||
// 检查日志目录
|
||
dirs := []string{"./resource_cleanup_test", "./test_logs"}
|
||
for _, dir := range dirs {
|
||
if _, err := os.Stat(dir); !os.IsNotExist(err) {
|
||
files, _ := filepath.Glob(filepath.Join(dir, "*", "*.log"))
|
||
fmt.Printf(" 目录 %s: %d 个日志文件\n", dir, len(files))
|
||
|
||
// 显示文件详情
|
||
for _, file := range files {
|
||
info, err := os.Stat(file)
|
||
if err == nil {
|
||
fmt.Printf(" - %s (大小: %.2fKB, 修改时间: %s)\n",
|
||
filepath.Base(file),
|
||
float64(info.Size())/1024,
|
||
info.ModTime().Format("15:04:05"))
|
||
}
|
||
}
|
||
} else {
|
||
fmt.Printf(" 目录 %s: 不存在\n", dir)
|
||
}
|
||
}
|
||
}
|
||
|
||
func main() {
|
||
config := `{
|
||
"log_dir": "./test_logs_reading",
|
||
"level": 1,
|
||
"split_type": 1,
|
||
"max_size": 1048576,
|
||
"max_count": 5,
|
||
"enable_caller": true,
|
||
"default_task_type": "reading_test"
|
||
}`
|
||
var configs Config
|
||
err2 := json.Unmarshal([]byte(config), &configs)
|
||
if err2 != nil {
|
||
fmt.Println(err2)
|
||
}
|
||
logger, err := NewLogger(configs)
|
||
if err != nil {
|
||
fmt.Println(err)
|
||
}
|
||
fmt.Println(logger)
|
||
|
||
fmt.Println("🚀 开始资源回收验证测试")
|
||
|
||
// 确定DLL路径
|
||
dllPath := "logger.dll"
|
||
if _, err := os.Stat(dllPath); os.IsNotExist(err) {
|
||
log.Fatalf("DLL文件不存在: %s", dllPath)
|
||
}
|
||
|
||
// 创建包装器
|
||
wrapper, err := NewLoggerWrapper(dllPath)
|
||
if err != nil {
|
||
log.Fatalf("创建日志包装器失败: %v", err)
|
||
}
|
||
defer wrapper.Close()
|
||
|
||
fmt.Println("✅ DLL加载成功")
|
||
|
||
// 初始资源状态
|
||
fmt.Println("\n📈 初始资源状态:")
|
||
monitorResources()
|
||
|
||
// 运行日志读取功能测试
|
||
testLogReadingFunctions(wrapper)
|
||
|
||
// 运行资源回收测试
|
||
testResourceCleanup(wrapper)
|
||
|
||
// 检查文件系统资源
|
||
checkFileSystemResources()
|
||
|
||
fmt.Println("\n🎉 资源回收验证完成!")
|
||
fmt.Println("\n💡 测试说明:")
|
||
fmt.Println(" - 本测试创建了活跃和闲置的logger来模拟真实使用场景")
|
||
fmt.Println(" - 通过观察闲置logger的可用性来验证自动回收机制")
|
||
fmt.Println(" - 内存使用趋势可以帮助识别资源泄漏")
|
||
fmt.Println(" - 实际自动清理需要较长时间(2小时未使用)")
|
||
}
|