using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using WIDESEAWCS_Core;
|
using WIDESEAWCS_Core.BaseServices;
|
using WIDESEAWCS_ISystemRepository;
|
using WIDESEAWCS_ISystemServices;
|
using WIDESEAWCS_Model.Models;
|
|
namespace WIDESEAWCS_SystemServices
|
{
|
public class Sys_LogService : ServiceBase<Sys_Log, ISys_LogRepository>, ISys_LogService
|
{
|
private readonly string[] LogFolders = new[] { "Log", "Log_PLCReadWrite" };
|
private int fileId = 2020;
|
public Sys_LogService(ISys_LogRepository BaseDal) : base(BaseDal)
|
{
|
}
|
|
public WebResponseContent GetLogName()
|
{
|
WebResponseContent content = new WebResponseContent();
|
try
|
{
|
var data = new List<object>();
|
fileId = 2020; // 重置ID
|
|
foreach (string folderName in LogFolders)
|
{
|
var folderPath = Path.Combine(AppContext.BaseDirectory, folderName);
|
var folderInfo = new DirectoryInfo(folderPath);
|
|
if (!folderInfo.Exists)
|
{
|
continue;
|
}
|
|
var folderData = BuildFolderTree(folderInfo, folderName);
|
data.Add(folderData);
|
}
|
|
return data.Any()
|
? WebResponseContent.Instance.OK(data: data)
|
: WebResponseContent.Instance.Error("未找到日志文件夹");
|
}
|
catch (Exception ex)
|
{
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
|
|
public WebResponseContent GetLog(string fileName)
|
{
|
try
|
{
|
if (string.IsNullOrEmpty(fileName))
|
{
|
return WebResponseContent.Instance.Error("文件名不能为空");
|
}
|
|
FileSearchResult searchResult = null;
|
|
foreach (string folderName in LogFolders)
|
{
|
var folderPath = Path.Combine(AppContext.BaseDirectory, folderName);
|
var folderInfo = new DirectoryInfo(folderPath);
|
|
if (!folderInfo.Exists)
|
{
|
continue;
|
}
|
|
searchResult = FindFileWithInfo(folderInfo, fileName, folderName);
|
if (searchResult != null)
|
{
|
break;
|
}
|
}
|
|
if (searchResult == null)
|
{
|
return WebResponseContent.Instance.Error($"未找到日志文件: {fileName}");
|
}
|
|
// 读取文件内容
|
var fileContent = ReadLogFileContent(searchResult.File.FullName);
|
|
// 返回包含元数据的结果
|
var result = new
|
{
|
fileName = searchResult.File.Name,
|
fullPath = searchResult.File.FullName,
|
fatherNode = searchResult.SourceFolder,
|
fileSize = GetFileSize(searchResult.File.Length),
|
lastWriteTime = searchResult.File.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
content = fileContent,
|
lineCount = fileContent.Count
|
};
|
|
return WebResponseContent.Instance.OK(data: result);
|
}
|
catch (IOException ex)
|
{
|
if (IsFileLockedException(ex))
|
{
|
return WebResponseContent.Instance.Error($"日志文件正在被系统写入,请稍后再试");
|
}
|
return WebResponseContent.Instance.Error($"打开日志文件错误,{ex.Message}");
|
}
|
catch (Exception ex)
|
{
|
return WebResponseContent.Instance.Error($"打开日志文件错误,{ex.Message}");
|
}
|
}
|
|
#region MyRegion
|
private object BuildFolderTree(DirectoryInfo folder, string displayName)
|
{
|
var children = new List<object>();
|
|
// 处理子目录
|
foreach (var subDir in folder.GetDirectories().Where(x => x.Name != "Info").OrderByDescending(x => x.CreationTime))
|
{
|
var files = subDir.GetFiles()
|
.Select(file => new
|
{
|
label = file.Name,
|
id = fileId++,
|
hidden = true,
|
fatherNode = subDir.Name,
|
fullPath = file.FullName,
|
lastWriteTime = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
|
})
|
.ToList();
|
|
if (files.Any())
|
{
|
children.Add(new
|
{
|
label = subDir.Name,
|
children = files,
|
id = subDir.Name.GetHashCode(),
|
hidden = false
|
});
|
}
|
}
|
|
// 处理根目录文件
|
var rootFiles = folder.GetFiles()
|
.Select(file => new
|
{
|
label = file.Name,
|
id = fileId++,
|
hidden = true,
|
fatherNode = folder.Name,
|
fullPath = file.FullName,
|
lastWriteTime = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
|
})
|
.ToList();
|
|
if (rootFiles.Any())
|
{
|
children.Add(new
|
{
|
label = folder.Name,
|
children = rootFiles,
|
id = folder.Name.GetHashCode(),
|
hidden = false
|
});
|
}
|
|
return new
|
{
|
label = displayName,
|
children = children,
|
id = displayName.GetHashCode(),
|
hidden = false,
|
fatherNode = folder.Name,
|
isRoot = true
|
};
|
}
|
|
private List<string> ReadLogFileContent(string filePath)
|
{
|
var lines = new List<string>();
|
|
using (FileStream stream = new FileStream(
|
filePath,
|
FileMode.Open,
|
FileAccess.Read,
|
FileShare.ReadWrite))
|
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
{
|
// 如果文件太大,只读取最后1000行(可选)
|
var fileInfo = new FileInfo(filePath);
|
if (fileInfo.Length > 5 * 1024 * 1024) // 大于5MB
|
{
|
return ReadLastLines(reader, 1000);
|
}
|
|
// 读取全部内容
|
while (!reader.EndOfStream)
|
{
|
var line = reader.ReadLine();
|
lines.Add(line);
|
}
|
}
|
|
return lines;
|
}
|
|
private List<string> ReadLastLines(StreamReader reader, int lineCount)
|
{
|
var lines = new Queue<string>();
|
string line;
|
|
while ((line = reader.ReadLine()) != null)
|
{
|
lines.Enqueue(line);
|
if (lines.Count > lineCount)
|
{
|
lines.Dequeue();
|
}
|
}
|
|
return lines.ToList();
|
}
|
|
/// <summary>
|
/// 文件查找结果
|
/// </summary>
|
private class FileSearchResult
|
{
|
public FileInfo File { get; set; }
|
public string SourceFolder { get; set; }
|
}
|
|
/// <summary>
|
/// 查找文件并返回详细信息
|
/// </summary>
|
private FileSearchResult FindFileWithInfo(DirectoryInfo folder, string fileName, string sourceFolder)
|
{
|
// 查找当前目录
|
var file = folder.GetFiles().FirstOrDefault(x => x.Name == fileName);
|
if (file != null)
|
{
|
return new FileSearchResult
|
{
|
File = file,
|
SourceFolder = sourceFolder
|
};
|
}
|
|
// 递归查找子目录
|
foreach (var subDir in folder.GetDirectories().Where(x => x.Name != "Info"))
|
{
|
var result = FindFileWithInfo(subDir, fileName, sourceFolder);
|
if (result != null)
|
{
|
return result;
|
}
|
}
|
|
return null;
|
}
|
|
/// <summary>
|
/// 获取可读的文件大小
|
/// </summary>
|
private string GetFileSize(long bytes)
|
{
|
string[] sizes = { "B", "KB", "MB", "GB" };
|
double len = bytes;
|
int order = 0;
|
while (len >= 1024 && order < sizes.Length - 1)
|
{
|
order++;
|
len = len / 1024;
|
}
|
return $"{len:0.##} {sizes[order]}";
|
}
|
|
private bool IsFileLockedException(IOException ex)
|
{
|
int errorCode = ex.HResult & 0xFFFF;
|
return errorCode == 32 || errorCode == 33; // ERROR_SHARING_VIOLATION or ERROR_LOCK_VIOLATION
|
}
|
#endregion
|
}
|
}
|