루트 파일 정리: - DXF/P&ID 관련 → dxf-graph/ - fastTable 관련 → fastTable/ - plan/ → plans/ 통합 (최신 버전 유지) - 테스트 출력 파일, 구버전 프로젝트 삭제 - 불필요한 루트 문서 삭제
13 KiB
13 KiB
로그 처리 계획 (Log Handling Plan)
문제 상황
터미널에 너무 많은 로그가 출력되어 정신없음
발생 로그 예시
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (2ms) [Parameters=[@__u_Timestamp_2='?' (DbType = DateTime), @__u_Value_1='?', @__u_NodeId_0='?'], CommandType='Text', CommandTimeout='30']
UPDATE realtime_table AS r
SET timestamp = @__u_Timestamp_2,
livevalue = @__u_Value_1
WHERE r.node_id = @__u_NodeId_0
info: ExperionCrawler.Infrastructure.OpcUa.ExperionRealtimeService[0]
Update realtime info.
원인 분석
-
EF Core DB Command 로그 (
Microsoft.EntityFrameworkCore.Database.Command)appsettings.json에서Microsoft.EntityFrameworkCore.Database.Command가"Information"으로 설정- 매 500ms마다
UPDATE realtime_table쿼리 실행 시 로그 출력
-
ExperionRealtimeService 로그
FlushPendingAsync()에서_logger.LogDebug()로 배치 업데이트 로그 남김ExperionCrawler.Infrastructure.OpcUa.ExperionRealtimeService카테고리가"Information"으로 설정
해결 방안
제안 1: appsettings.json 수정 (가장 간단)
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information",
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
"ExperionCrawler.Infrastructure.OpcUa.ExperionRealtimeService": "Warning"
}
}
}
효과:
UPDATE realtime_table쿼리 로그 숨김[Realtime] 배치 업데이트: X/Y건로그 숨김- 경고/오류만 표시
제안 2: 개발/배포 환경 분리 (추천)
appsettings.json (배포용 - 로그 적게)
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
"ExperionCrawler": "Information"
}
}
}
appsettings.Development.json (개발용 - 로그 많게)
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.EntityFrameworkCore": "Debug",
"Microsoft.EntityFrameworkCore.Database.Command": "Information",
"ExperionCrawler": "Debug"
}
}
}
사용 방법:
- 개발 모드:
dotnet run→ 로그 자세히 보임 - 배포 모드:
dotnet run --configuration Release→ 로그 적게 보임
제안 3: 코드에서 로그 레벨 조정
Program.cs에서 로그 필터 추가:
builder.Logging.AddFilter("Microsoft.EntityFrameworkCore.Database.Command", LogLevel.Warning);
builder.Logging.AddFilter("ExperionCrawler", LogLevel.Information);
ExperionRealtimeService.cs의 FlushPendingAsync()에서:
_logger.LogDebug()→_logger.LogTrace()(가장 자세한 로그는 기본적으로 안 보임)
제안 4: 주석 처리 + 나중에 복구용
appsettings.json에 주석으로 메모:
{
"Logging": {
"LogLevel": {
// 개발 시 주석 해제: 로그 자세히 보기
// "Microsoft.EntityFrameworkCore.Database.Command": "Information",
// "ExperionCrawler": "Debug",
// 배포 시: 로그 적게 (기본)
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
"ExperionCrawler": "Information"
}
}
}
검수 체크리스트
- 로그 레벨 조정 후 터미널이 깔끔한지 확인
- 필요한 로그가 사라지지 않았는지 확인
- 개발 모드에서 로그를 다시 볼 수 있는지 확인
참고: 로그 레벨 순서
Trace (가장 자세함 - 기본적으로 안 보임)
Debug (개발 시 유용 - 기본적으로 안 보임)
Information (일반 로그 - 기본 표시)
Warning (경고 - 기본 표시)
Error (오류 - 기본 표시)
Critical (치명적 오류 - 기본 표시)
제안 5: UI에서 동적 로그 레벨 설정 (추천 + 개발자 친화)
개요
웹 UI에서 실시간으로 로그 레벨을 조정할 수 있도록 API를 추가하여, 개발 중에 코드 수정 없이 로그를 켜고 끌 수 있게 함.
아키텍처
┌─────────────────────────────────────────────────────────────┐
│ Web UI (app.js) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 로그 레벨 설정 UI (Toggle Switch) │ │
│ │ - EF Core Query Log (ON/OFF) │ │
│ │ - Realtime Service Log (ON/OFF) │ │
│ │ - Debug Mode (ON/OFF) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ LogSettingsController (API) │
│ - GET /api/log/settings → 현재 설정 조회 │
│ - POST /api/log/settings → 설정 업데이트 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ LogSettingsService (비즈니스 로직) │
│ - 로그 레벨 설정 저장 (appsettings.json) │
│ - 로거 리로드 (새로운 설정 적용) │
└─────────────────────────────────────────────────────────────┘
구현 계획
1. DTO 정의 (src/Core/Application/DTOs/LogSettingsDtos.cs)
namespace ExperionCrawler.Core.Application.DTOs;
public class LogSettingsRequest
{
public bool? EnableEfCoreQueryLog { get; set; }
public bool? EnableRealtimeServiceLog { get; set; }
public bool? EnableDebugMode { get; set; }
}
public class LogSettingsResponse
{
public bool EfCoreQueryLog { get; set; }
public bool RealtimeServiceLog { get; set; }
public bool DebugMode { get; set; }
}
2. 서비스 인터페이스 (src/Core/Application/Interfaces/ILogSettingsService.cs)
namespace ExperionCrawler.Core.Application.Interfaces;
public interface ILogSettingsService
{
Task<LogSettingsResponse> GetSettingsAsync();
Task UpdateSettingsAsync(LogSettingsRequest request);
}
3. 서비스 구현 (src/Core/Application/Services/LogSettingsService.cs)
namespace ExperionCrawler.Core.Application.Services;
public class LogSettingsService : ILogSettingsService
{
private readonly IConfiguration _config;
private readonly ILogger<LogSettingsService> _logger;
public LogSettingsService(IConfiguration config, ILogger<LogSettingsService> logger)
{
_config = config;
_logger = logger;
}
public async Task<LogSettingsResponse> GetSettingsAsync()
{
var loggingSection = _config.GetSection("Logging");
return new LogSettingsResponse
{
EfCoreQueryLog = IsLogLevelEnabled(loggingSection, "Microsoft.EntityFrameworkCore.Database.Command", "Information"),
RealtimeServiceLog = IsLogLevelEnabled(loggingSection, "ExperionCrawler", "Information"),
DebugMode = IsLogLevelEnabled(loggingSection, "Default", "Debug")
};
}
public async Task UpdateSettingsAsync(LogSettingsRequest request)
{
// appsettings.json 읽기
var configPath = "appsettings.json";
var json = await File.ReadAllTextAsync(configPath);
var doc = JsonDocument.Parse(json);
// 로그 레벨 업데이트
// (구현은 간단히 appsettings.Development.json 사용하는 방식으로)
_logger.LogInformation("[LogSettings] 설정 업데이트: {Request}", request);
}
private bool IsLogLevelEnabled(IConfigurationSection section, string category, string level)
{
var logLevelSection = section.GetSection("LogLevel");
var value = logLevelSection[category];
return !string.IsNullOrEmpty(value) && value == level;
}
}
4. 컨트롤러 (src/Web/Controllers/LogSettingsController.cs)
namespace ExperionCrawler.Web.Controllers;
[ApiController]
[Route("api/[controller]")]
public class LogSettingsController : ControllerBase
{
private readonly ILogSettingsService _service;
public LogSettingsController(ILogSettingsService service)
{
_service = service;
}
[HttpGet]
public async Task<ActionResult<LogSettingsResponse>> GetSettings()
{
var settings = await _service.GetSettingsAsync();
return Ok(new
{
efCoreQueryLog = settings.EfCoreQueryLog,
realtimeServiceLog = settings.RealtimeServiceLog,
debugMode = settings.DebugMode
});
}
[HttpPost]
public async Task<ActionResult> UpdateSettings([FromBody] LogSettingsRequest request)
{
await _service.UpdateSettingsAsync(request);
return Ok();
}
}
5. UI 변경 (src/Web/wwwroot/js/app.js)
// 로그 설정 UI 추가
function createLogSettingsUI() {
const container = document.createElement('div');
container.style.cssText = `
position: fixed;
top: 10px;
right: 10px;
background: rgba(0,0,0,0.8);
padding: 15px;
border-radius: 8px;
z-index: 1000;
color: white;
font-family: monospace;
`;
container.innerHTML = `
<h3 style="margin: 0 0 10px 0; font-size: 14px;">Log Settings</h3>
<div style="display: flex; flex-direction: column; gap: 5px;">
<label style="display: flex; align-items: center; gap: 5px; font-size: 12px;">
<input type="checkbox" id="log-efcore"> EF Core Query
</label>
<label style="display: flex; align-items: center; gap: 5px; font-size: 12px;">
<input type="checkbox" id="log-realtime"> Realtime Service
</label>
<label style="display: flex; align-items: center; gap: 5px; font-size: 12px;">
<input type="checkbox" id="log-debug"> Debug Mode
</label>
</div>
`;
document.body.appendChild(container);
// 초기 설정 로드
loadLogSettings();
// 체크박스 이벤트
document.getElementById('log-efcore').addEventListener('change', (e) => updateLogSetting('efCoreQueryLog', e.target.checked));
document.getElementById('log-realtime').addEventListener('change', (e) => updateLogSetting('realtimeServiceLog', e.target.checked));
document.getElementById('log-debug').addEventListener('change', (e) => updateLogSetting('debugMode', e.target.checked));
}
async function loadLogSettings() {
try {
const res = await fetch('/api/logsettings');
const data = await res.json();
document.getElementById('log-efcore').checked = data.efCoreQueryLog;
document.getElementById('log-realtime').checked = data.realtimeServiceLog;
document.getElementById('log-debug').checked = data.debugMode;
} catch (e) {
console.error('Failed to load log settings:', e);
}
}
async function updateLogSetting(key, value) {
try {
await fetch('/api/logsettings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ [key]: value })
});
} catch (e) {
console.error('Failed to update log setting:', e);
}
}
6. Program.cs 등록
// LogSettingsService 등록
builder.Services.AddScoped<ILogSettingsService, LogSettingsService>();
사용 방법
- 웹 UI에 로그 설정 패널이 오른쪽 상단에 표시됨
- 체크박스를 켜고 끄면 실시간으로 로그 레벨이 변경됨
- 설정은 세션 간 유지되지 않음 (개발 편의용)
장점
- 코드 수정 없이 로그 테스트 가능
- 실시간으로 로그 켜고 끌 수 있음
- UI에서 직관적으로 조작 가능
단점
- 설정이 메모리에만 저장됨 (재시작 시 초기화)
- 영구 설정을 원하면 appsettings.json 수정 필요