분석 로그를 1MB 롤링과 14일 보관 기준으로 정리한다

- app/perf/audit/workflow 로그에 공통 RollingTextLogStore를 적용해 날짜별 파일이 1MB를 넘지 않도록 오래된 내용을 밀어내며 저장한다.

- 공통 로그, 성능 로그, 감사 로그는 14일 보관으로 맞추고 워크플로우 상세 로그는 기존 설정을 따르되 최대 14일 상한을 적용한다.

- RollingTextLogStoreTests 3건을 추가해 파일 크기 상한과 오래된 파일/날짜 디렉터리 정리 동작을 검증한다.

- 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_logroll\\ -p:IntermediateOutputPath=obj\\verify_logroll\\ 경고 0 / 오류 0

- 검증: dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter RollingTextLogStoreTests -p:OutputPath=bin\\verify_logroll_tests\\ -p:IntermediateOutputPath=obj\\verify_logroll_tests\\ 통과 3 (기존 WorkspaceContextGeneratorTests.cs(76) nullable 경고 1건 유지)
This commit is contained in:
2026-04-14 18:51:55 +09:00
parent 4746d2834b
commit 3747a92c12
9 changed files with 263 additions and 35 deletions

View File

@@ -0,0 +1,96 @@
using System.IO;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class RollingTextLogStoreTests
{
[Fact]
public void AppendLine_ShouldKeepNewestContentWithinMaxBytes()
{
var root = CreateTempDirectory();
try
{
var path = Path.Combine(root, "sample.log");
for (var i = 0; i < 12; i++)
AxCopilot.Services.RollingTextLogStore.AppendLine(path, $"line-{i:00}-abcdefghijklmnopqrstuvwxyz", 120);
var text = File.ReadAllText(path);
var bytes = new FileInfo(path).Length;
bytes.Should().BeLessOrEqualTo(120);
text.Should().Contain("line-11");
text.Should().NotContain("line-00");
}
finally
{
TryDelete(root);
}
}
[Fact]
public void PurgeOldFiles_ShouldDeleteFilesOutsideRetentionWindow()
{
var root = CreateTempDirectory();
try
{
var oldFile = Path.Combine(root, "old.log");
var newFile = Path.Combine(root, "new.log");
File.WriteAllText(oldFile, "old");
File.WriteAllText(newFile, "new");
File.SetLastWriteTime(oldFile, DateTime.Now.AddDays(-20));
File.SetLastWriteTime(newFile, DateTime.Now.AddDays(-1));
AxCopilot.Services.RollingTextLogStore.PurgeOldFiles(root, "*.log", 14);
File.Exists(oldFile).Should().BeFalse();
File.Exists(newFile).Should().BeTrue();
}
finally
{
TryDelete(root);
}
}
[Fact]
public void PurgeOldDirectoriesByDateName_ShouldDeleteOldDateDirectories()
{
var root = CreateTempDirectory();
try
{
var oldDir = Path.Combine(root, DateTime.Now.AddDays(-16).ToString("yyyy-MM-dd"));
var newDir = Path.Combine(root, DateTime.Now.AddDays(-2).ToString("yyyy-MM-dd"));
Directory.CreateDirectory(oldDir);
Directory.CreateDirectory(newDir);
AxCopilot.Services.RollingTextLogStore.PurgeOldDirectoriesByDateName(root, 14);
Directory.Exists(oldDir).Should().BeFalse();
Directory.Exists(newDir).Should().BeTrue();
}
finally
{
TryDelete(root);
}
}
private static string CreateTempDirectory()
{
var path = Path.Combine(Path.GetTempPath(), "AxCopilot.Tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(path);
return path;
}
private static void TryDelete(string path)
{
try
{
if (Directory.Exists(path))
Directory.Delete(path, recursive: true);
}
catch
{
}
}
}