> For the complete documentation index, see [llms.txt](https://docs.axuslab.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.axuslab.com/1.-common-structures/logging.md).

# 로깅 - Logging

Logging

#### 설명

`Axs Framework`를 `Castle`인터페이스를 구현한 `Serilog`의 로깅 기능을 기본으로 사용하며 **Log4Net, NLog**등 다영한 로깅라이브러로 변경 할 수 있습니다.

#### 예제

먼저 로그를 작성하기 위해 Logger 객체를 가져와야합니다.

```csharp
// 네임스페이스 선언
using Castle.Core.Logging;

public class SampleAppController : ISampleAppController
{
    // 객체 속성 주입을 위해 선언
    public ILogger Logger { get; set; }

    public TaskAppController()
    {
        // 기본값 선언
        Logger = NullLogger.Instance;
    }

    public void CreateSample(CreateSampleDto input)
    {
        // 로그 저장
        Logger.Info("샘플 코드 저장 description : " + input.Description);

        //TODO: 기타 작업 코드 작성
    }
}
```

위 코드가 실행이 되고 로그 파일을 확인하면 아래와 같이 확인이 가능합니다.

```txt
08:09:35,556 [INF] 샘플 코드 저장 description : Description!
{"SourceContext": "SampleAppController", "CorrelationId": "9dade8b9-de5a-4e70-a79c-788148daa86a", "ThreadId": 23}
08:09:39,015 [ERR] 에러 로깅 테스트
{"SourceContext": "SampleAppController", "CorrelationId": "9dade8b9-de5a-4e70-a79c-788148daa86a", "ThreadId": 21, "ExceptionDetail": {"Type": "System.ApplicationException", "HResult": -2146232832, "Message": "에러 로깅 테스트", "Source": "MyCompanyName.MyProjectName.Web.Mvc", "TargetSite": "Void MoveNext()"}}
System.ApplicationException: 에러 로깅 테스트
   at MyCompanyName.MyProjectName.Web.Areas.App.Pages.Users.IndexModel.OnGetAsync() in ...\Index.cshtml.cs:line 29
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.NonGenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
```

#### 로그 관련 환경 설정

기본 구성의 로그 형식은 다음과 같습니다.

* **날짜 및 시간** : 로그 라인이 작성된 시간입니다.
* **로그 수준** : DBG, INF, WRN, ERR, FTL.
* **로그 텍스트** : 작성하는 실제 로그 텍스트입니다.
* **Properties** : 출력의 다른 곳에 표시되지 않는 모든 이벤트 속성 값입니다.
  * **로거 이름** : 일반적으로 로그 라인을 작성하는 클래스 이름입니다.
  * **상관관계 ID** : 현재 웹 요청에 대한 로그를 추적하기 위해 Correlation Id 추가합니다.
  * **스레드 번호** : 로그 라인을 작성한 스레드 번호입니다.
  * **예외 상세** : 예외가 발생할경우 구조화된 예외정보 노출
* **예외** : 예외가 발생할경우 메세지 원문

아래와 같이 응용 프로그램의 **Program.cs**와 **appsettings.json** 파일에 정의되어 있습니다.

* `Program.cs`로 기본 `DEBUG`시 Console 로깅이 동작하면 `appsettings.json`에 정의를 통해서 `Override`된 설정으로 최종 구성된다.

```csharp
public class Program
{
    public static void Main(string[] args) {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Warning()
            .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
            .Enrich.FromLogContext()
            .Enrich.WithCorrelationIdHeader()
            .Enrich.WithAxsThreadId()
#if DEBUG
            .Enrich.WithExceptionDetails()
            .WriteTo.Async(config => config
                .Console(outputTemplate: "{Timestamp:HH:mm:ss,fff} [{Level:u3}] {Message:lj}{NewLine}{Properties:j}{NewLine}{Exception}",
                    theme: Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme.Code)
            )
#endif
            .ReadFrom.Configuration(configuration)
            .CreateLogger();        
        // some code...
    }  
}
```

```json
{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Warning",
      "Override": {
        "Microsoft.Hosting.Lifetime": "Information"
      }
    },
    "Properties": {
      "Application": "Axs WebApp"
    },
    "WriteTo": [
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "File",
              "Args": {
                "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Properties:j}{NewLine}{Exception}",
                "path": "Logs\\App-.log",       // 파일명 - App-yyyyMMdd.log
                "fileSizeLimitBytes": 10240000, // 파일 사이즈
                "rollingInterval": "Day",       // 롤링 기준 - 하루 단위로 구별
                "rollOnFileSizeLimit": true,    // 파일 사이즈 제한 여부
                "retainedFileCountLimit": 5,    // 파일 갯수
                "buffered": false,
                "shared": true,
                "encoding": "System.Text.Encoding::UTF8"
              }
            }
          ]
        }
      }
    ]
  }  
}
```

Serilog은 강력한 로깅 라이브러리입니다. 다른 형식과 다른 대상 (텍스트 파일, 데이터베이스 ...)으로 로그를 저장할 수 있습니다. 최소 로그 수준을 설정하여 로그 저장의 횟수를 지정할 수 있습니다. 자세한 내용은 Serilog의 환경설정 문서([documentation](https://github.com/serilog/serilog-settings-configuration))를 참조하십시오.

마지막으로 Startup.cs 파일에서 appsettings.json 파일과 함께 Serilog의 환경 설정 정보를 사용하도록 합니다.

```csharp
services.AddAxs<MyProjectNameWebMvcModule>(options => {
    options.IocManager.IocContainer.AddFacility<LoggingFacility>(
        f => f.UseAxSerilog()
    );
```

웹과 호스트 프로젝트에서 초기화 코드를 추가하면 됩니다.

#### 확인

appsettings.json에서 serilog 세셕에서 아래 정보를 확인하고 폴더에서 해당 로그 파일을 확인하면 된다.

```json
// 파일로그 옵션
{
  "Name": "File",
  "Args": {
    "path": "Logs\\App.log"
  }
}
```

로그 파일을 열어 보면 아래와 같은 패턴으로 저장이 되는 것을 확인 할 수 있습니다.

```log
2023-09-19 08:09:19.192 [INF] Starting web server...
{"ThreadId":1}
2023-09-19 08:09:20.883 [INF] Web Server Booting Up...
{"SourceContext":"Default","ThreadId":1}
2023-09-19 08:07:20.563 [INF] Initialize Seed Db.
{"SourceContext":"MyCompanyName.MyProjectName.Persistence.MyProjectNamePersistenceModule","ThreadId":1}
2023-09-19 08:07:20.566 [INF] >>  Configuration.Modules.AxsEfCore().AddDbContext ....
{"SourceContext":"MyCompanyName.MyProjectName.Persistence.MyProjectNamePersistenceModule","ThreadId":1}
2023-09-19 08:07:20.972 [INF] Executed DbCommand (3ms) [Parameters=[@__language_Name_1='ko' (Size = 128)], CommandType='Text', CommandTimeout='30']
SELECT CASE
    WHEN EXISTS (
        SELECT 1
        FROM [AxsLanguages] AS [a]
        WHERE [a].[TenantId] IS NULL AND ([a].[Name] = @__language_Name_1)) THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END
{"SourceContext":"Microsoft.EntityFrameworkCore.Database.Command","ThreadId":1}
2023-09-19 08:09:35.834 [DBG] Debug!!!!!
{"SourceContext":"MyCompanyName.MyProjectName.Web.Areas.App.Pages.Users.IndexModel","CorrelationId":"87449cf6-c4bf-40d4-9390-116ea4cd35fe","ThreadId":21}
2023-09-19 08:09:35.834 [INF] Info!!!!!
{"SourceContext":"MyCompanyName.MyProjectName.Web.Areas.App.Pages.Users.IndexModel","CorrelationId":"87449cf6-c4bf-40d4-9390-116ea4cd35fe","ThreadId":21}
2023-09-19 08:09:35.834 [WRN] Warn!!!!!
{"SourceContext":"MyCompanyName.MyProjectName.Web.Areas.App.Pages.Users.IndexModel","CorrelationId":"87449cf6-c4bf-40d4-9390-116ea4cd35fe","ThreadId":21}
2023-09-19 08:09:39.015 [ERR] 에러 로깅 테스트
{"SourceContext":"Axs.AspNetCore.Mvc.ExceptionHandling.AxsExceptionPageFilter","CorrelationId":"87449cf6-c4bf-40d4-9390-116ea4cd35fe","ThreadId":21,"ExceptionDetail":{"Type":"System.ApplicationException","HResult":-2146232832,"Message":"에러 로깅 테스트","Source":"MyCompanyName.MyProjectName.Web.Mvc","TargetSite":"Void MoveNext()"}}
System.ApplicationException: 에러 로깅 테스트
   at MyCompanyName.MyProjectName.Web.Areas.App.Pages.Users.IndexModel.OnGetAsync() in ...\Index.cshtml.cs:line 29
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.NonGenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
```

#### 웹 요청에 대한 로그를 추적하기

* CorrelationId: **297e08af-3194-4700-973c-b93a3d030a92**
* API 호출시 관계된 로그를 분석할수 있습니다.

![API추적](/files/jjPnrqtGFYDk0lKiQBhs)

```
2023-09-19 08:44:54.018 [INF] GetLanguages 언어조회
{"SourceContext": "SampleAppController", "CorrelationId": "297e08af-3194-4700-973c-b93a3d030a92", "ThreadId": 23}

2023-09-19 08:44:54.018 [INF] >>  Configuration.Modules.AxsEfCore().AddDbContext ....
{"SourceContext":"MyProjectNamePersistenceModule","CorrelationId":"297e08af-3194-4700-973c-b93a3d030a92","ThreadId":34}

2023-09-19 08:44:54.025 [INF] Executed DbCommand (2ms) [Parameters=[@p0='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31' (Size = 512), @p1='::1' (Size = 64), @p2=NULL (Size = 128), @p3=NULL (Size = 2000), @p4=NULL (Size = 2000), @p5='28', @p6='2023-09-19T08:44:53', @p7=NULL (DbType = Int32), @p8=NULL (DbType = Int64), @p9='GetLanguages' (Size = 256), @p10='{}' (Size = 1024), @p11=NULL (Size = 4000), @p12='Axs.Starter.Localization.LanguageAppService' (Size = 256), @p13=NULL (DbType = Int32), @p14='1' (Nullable = true)], CommandType='Text', CommandTimeout='30']
SELECT *
FROM [AxsLanguages]
{"SourceContext":"Microsoft.EntityFrameworkCore.Database.Command","CorrelationId":"297e08af-3194-4700-973c-b93a3d030a92","ThreadId":31}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.axuslab.com/1.-common-structures/logging.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
