서버를 운영할때에는 로그가 굉장히 중요해진다.
버그가 발생했을 때나 CS요청이 들어왔을 때,
에러로그와 API 요청 로그를 통해 당시의 상황을 추적하고 원인을 파악할 수 있다.
이번 게시글에서는
서버에서 로그 파일을 생성하고 관리해보려고 한다.
[Response Pipeline 생성]
기존에 구현되어 있던 암호화/복호화 기능과
새롭게 추가될 로그 파일 기능에서는 모두 Response값을 캡처해서 사용해야 합니다.
또한 추후에 모니터링과 같은 기능이 추가되는 경우도 Response 값을 활용해야 할 수 있습니다.
하지만 두 개 이상의 기능에서 각각 Response값을 캡처하려고 하면,
응답 스트림이 한 번만 읽힐 수 있다는 특성 때문에
한쪽에서는 빈 값을 바라보는 문제가 발생할 수 있습니다.
이러한 문제를 방지하기 위해 Response 캡처는 한 곳에서만 수행하는 것이 바람직 합니다.
따라서 Response를 한 번만 캡처한 뒤,
캡처된 값을 여러 기능에서 안전하게 사용할 수 있도록
Pipeline-Handler 구조로 리팩토링을 진행 합니다.

Response Pipeline Middleware를 생성한 후, Response 캡처하는 코드를 이곳으로 옮깁니다.

Handler들에서 실행한 후, 변경된 Response Body가 있다면 기존 Response값에 덮어씁니다.
[IResponseHandler 생성]

Response와 관련된 모든 기능을 일관되게 관리하기 위해 공통 인터페이스인 IResponseHandler를 생성합니다.
이를 통해 Response 처리 로직을 하나의 규약으로 통일하고, 각 기능을 독립적인 컴포넌트로 분리할 수 있습니다.

기존에 하나의 미들웨어로 되어있던 암호화/복호화를 분리합니다.
1. Request 복호화
: Response 캡처할 필요가 없으므로 전용 Middleware로 복호화 역할만 수행한다.
2. Response
: Response 값을 기반으로 동작하므로 Handler로 분리한다.

분리한 Response 암호화 기능에 IResponseHandler를 상속하여 파이프라인에 참여하도록 하며,
_env와 _secret 사용하기 위하여 의존성도 주입하여 줍니다.
최종적인 처리 흐름은 다음과 같습니다.
| Request 복호화 -> Controller -> Response 파이프라인 -> Response 암호화 |
[Serilog 설치]


로그 관리를 위해 Serilog를 사용합니다.
Serilog를 사용하기 위해 아래 패키지를 프로젝트에 설치합니다.
| Serilog.AspNetCore, Serilog.Sinks.File |
//Selilog 추가
builder.AddSerilogLogging();
builder.Logging.AddConsole();
패키지 설치 후, Selilog를 애플리케이션 전역 로거로 사용하기 위해 Program.cs파일에 설정을 추가합니다.
[LogExtensions로 로그 파일 설정]
현재 서버에 남기고자 하는 로그는 아래와 같습니다.
● API 요청 로그
: Request, Response와 요청 시간을 남긴 API 요청 로그
● 에러 로그
: 프로젝트 실행 중 발생한 에러 및 오류를 기록하는 로그
1. 로그 파일 및 에러 로그 파일 PATH 지정

var logPath = Path.Combine(
AppContext.BaseDirectory,
"Logs/api",
"api-.log"
);
"api-.log" : 파일명에 - 를 사용하면 Selilog에서 일자별로 파일을 생성해줍니다.
2. 로그 파일과 에러 로그 파일에 각각 필터를 적용

.MinimumLevel.Information() // 전체 로그 필터
Information 레벨 이하의 로그만 기록하도록 설정합니다.
//로그 파일
.WriteTo.Logger(loggerConfig =>
loggerConfig
// ApiLoggingMiddleware에서 나온 로그만 작성
.Filter.ByIncludingOnly(e =>
e.Properties.ContainsKey("SourceContext")
&& e.Properties["SourceContext"].ToString()
.Contains("ResponseLoggingHandler"))
.WriteTo.File(
logPath, // 파일명
rollingInterval: RollingInterval.Day, //일 단위 작성
restrictedToMinimumLevel: LogEventLevel.Information // 현재 파일 필터
)
)
API 요청 로그의 경우,
ResponseLoggingHandler에서 발생한 로그만 필터링하여
logPath 내에
일 단위로 로그 파일을 생성하여 작성합니다.
//에러 파일
.WriteTo.File(
errorPath, // 파일명
rollingInterval: RollingInterval.Day, //일 단위 작성
restrictedToMinimumLevel: LogEventLevel.Error // 현재 파일 필터
)
에러의 경우
Error 레벨 이상의 로그만을 대상으로 하여
일 단위로 파일을 생성하여 작성합니다.
[Request]
Request의 경우,
이후 다른 Middleware나 기능에 의해 Request.Body.Position이 변경될 가능성을 고려하여
초기에 Request Body를 별도로 저장해두려고 합니다.

context.Items[Define.PLAIN_REQ_BODY] = requestBody;
이렇게 context.Item에 저장해두면 추후 Request가 이미 소비되었거나 Position이 변경되었더라도 원본 Request를 안전하게 참조할 수 있습니다.
[Response]

암호화 되기 전의 평문 response와
저장해두었던 request를 함께 사용하여 로그를 기록합니다.
var logFormat = "HTTP {Method} {Path} | {StatusCode} | Request : {Request} | Response: {Response}";
_logger.LogInformation(
logFormat,
context.Request.Method,
context.Request.Path,
context.Response.StatusCode,
OnLineJson(requestBody),
OnLineJson(plainResponse));
_logger.LogInformation(); 을 사용하여
API요청에 대한 인포메이션 레벨 로그를 남길 수 있습니다.
해당 로그는 LogExtensions에서 설정한 필터에 의해 API 요청 로그로 분류되어 파일에 기록됩니다.
[Program.cs]
마지막으로 Program.cs에
지금까지 구현한 기능들을 순서에 맞게 등록합니다.

//Middleware DL등록
builder.Services.AddScoped<IResponseHandler, ResponseEncryptionHandler>();
builder.Services.AddScoped<IResponseHandler, ResponseLoggingHandler>();
각 IResponseHandler 구현체에 대해
필요한 의존성을 주입하여 Response 파이프라인에서 사용할 수 있도록 합니다.
//MiddleWare
app.UseMiddleware<ExceptionLoggingMiddleware>();
app.UseMiddleware<RequestDecryptionMiddleware>();
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseMiddleware<GameSessionMiddleware>();
app.UseMiddleware<ResponsePipelineMiddleware>();
미들웨어는 흐름을 고려하여 순서에 맞게 등록해줍니다.
1. 에러로그 기록
2. 암호화된 Body 복호화
3. RequestBody 저장
4. 세션 검증 처리
5. Response캡처 및 암호화/로깅처리
[소스코드]
● PE
https://github.com/Minoritygames2/WebServerPortfolio/pull/2#issue-3769458764
● 소스 코드 전문
'게임 웹서버 만들기' 카테고리의 다른 글
| 일일 미션(데일리미션) - 게임 웹서버 만들기 13 (0) | 2026.01.14 |
|---|---|
| 유저 재화 - 게임 웹서버 만들기 12 (0) | 2026.01.06 |
| 유저 프로필 - 게임 웹서버 만들기 10 (0) | 2025.12.23 |
| 구글 Windows 로그인 - 게임 웹서버 만들기 9 (0) | 2025.12.12 |
| Redis연결, 세션키 생성 - 게임 웹서버 만들기 8 (0) | 2025.12.12 |