.NET Core 및 ASP.NET Core 로그인

작성자: Kirk Larkin, Juergen GutschRick Anderson

이 문서에서는 ASP.NET Core 앱에 적용되는 .NET의 로깅에 대해 설명합니다. .NET의 로깅에 대한 자세한 내용은 .NET의 로깅을 참조하세요. Blazor 앱의 로깅에 대한 자세한 내용은 ASP.NET Core Blazor 로깅을 참조하세요.

로깅 공급자

로그를 표시하는 Console 공급자를 제외하고 로깅 공급자는 로그를 저장합니다. 예를 들어 Azure Application Insights 공급자는 Azure Application Insights에 로그를 저장합니다. 여러 공급자를 사용하도록 설정할 수 있습니다.

기본 ASP.NET Core 웹앱 템플릿 호출 WebApplication.CreateBuilder은 다음 로깅 공급자를 추가합니다.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

위의 코드는 ASP.NET Core 웹앱 템플릿을 사용하여 만든 Program.cs 파일을 보여 줍니다. 다음 몇 가지 섹션에서는 ASP.NET Core 웹앱 템플릿을 기반으로 샘플을 제공합니다.

다음 코드는 WebApplication.CreateBuilder에 의해 추가된 로깅 공급자의 기본 집합을 재정의합니다.

var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole();

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

또는 앞의 로깅 코드를 다음과 같이 작성할 수 있습니다.

var builder = WebApplication.CreateBuilder();
builder.Host.ConfigureLogging(logging =>
{
    logging.ClearProviders();
    logging.AddConsole();
});

추가 공급자는 다음을 참조하세요.

로그 만들기

로그를 만들려면 DI(종속성 주입)ILogger<TCategoryName> 개체를 사용합니다.

다음 예제를 참조하세요.

  • 형식이 AboutModel인 정규화된 이름의 로그 ‘범주’를 사용하는 ILogger<AboutModel> 로거를 만듭니다. 로그 범주는 각 로그와 연결된 문자열입니다.
  • LogInformation을 호출하여 Information 수준에 로그합니다. 로그 수준은 기록된 이벤트의 심각도를 나타냅니다.
public class AboutModel : PageModel
{
    private readonly ILogger _logger;

    public AboutModel(ILogger<AboutModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        _logger.LogInformation("About page visited at {DT}", 
            DateTime.UtcNow.ToLongTimeString());
    }
}

수준범주는 이 문서의 뒷부분에 자세히 설명되어 있습니다.

Blazor에 대한 자세한 내용은 ASP.NET Core Blazor 로깅을 참조하세요.

로깅 구성

로깅 구성은 일반적으로 appsettings.{ENVIRONMENT}.json 파일의 Logging 섹션에서 제공됩니다. 여기서 {ENVIRONMENT} 자리 표시자는 환경입니다. 다음 appsettings.Development.json 파일은 ASP.NET Core 웹앱 템플릿에서 생성됩니다.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

위의 JSON에서

  • "Default""Microsoft.AspNetCore" 범주가 지정되었습니다.
  • "Microsoft.AspNetCore" 범주는 "Microsoft.AspNetCore"로 시작하는 모든 범주에 적용됩니다. 예를 들어 이 설정은 "Microsoft.AspNetCore.Routing.EndpointMiddleware" 범주에 적용됩니다.
  • "Microsoft.AspNetCore" 범주는 로그 수준 Warning 이상에 로그됩니다.
  • 특정 로그 공급자를 지정하지 않았으므로 LogLevelWindows EventLog를 제외하고 사용하도록 설정한 모든 로깅 공급자에 적용됩니다.

Logging 속성은 LogLevel 및 로그 공급자 속성을 포함할 수 있습니다. LogLevel 속성은 선택한 범주에 대해 로그할 최소 수준을 지정합니다. 위의 JSON에서는 InformationWarning 로그 수준을 지정했습니다. LogLevel 로그의 심각도를 나타내며 0에서 6 사이의 범위입니다.

Trace = 0, Debug = 1, Information = 2, Warning = 3, Error = 4, Critical = 5 및 None = 6

LogLevel을 지정하면 지정된 수준 이상의 메시지에 대해 로깅을 사용하도록 설정됩니다. 위의 JSON에서 Default 범주는 Information 이상에 대해 로그됩니다. 예를 들어 Information, Warning, ErrorCritical 메시지가 로그됩니다. LogLevel 지정하지 않으면 로깅은 Information 수준으로 기본 설정됩니다. 자세한 내용은 로그 수준을 참조하세요.

공급자 속성에서 LogLevel 속성을 지정할 수 있습니다. 공급자 아래의 LogLevel은 해당 공급자에 대해 로그할 수준을 지정하고 공급자 이외의 로그 설정을 재정의합니다. 다음 appsettings.json 파일을 살펴보세요.

{
  "Logging": {
    "LogLevel": { // All providers, LogLevel applies to all the enabled providers.
      "Default": "Error", // Default logging, Error and higher.
      "Microsoft": "Warning" // All Microsoft* categories, Warning and higher.
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information", // Overrides preceding LogLevel:Default setting.
        "Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.
      }
    },
    "EventSource": { // EventSource provider
      "LogLevel": {
        "Default": "Warning" // All categories of EventSource provider.
      }
    }
  }
}

Logging.{PROVIDER NAME}.LogLevel의 설정은 Logging.LogLevel의 설정을 재정의합니다. 여기서 {PROVIDER NAME} 자리 표시자는 공급자 이름입니다. 위의 JSON에서는 Debug 공급자의 기본 로그 수준이 Information으로 설정되었습니다.

Logging:Debug:LogLevel:Default:Information

위 설정은 Microsoft.Hosting을 제외하고 모든 Logging:Debug: 범주에 대해 Information 로그 수준을 지정합니다. 특정 범주를 나열하면 특정 범주로 기본 범주가 재정의됩니다. 위의 JSON에서 Logging:Debug:LogLevel 범주 "Microsoft.Hosting""Default"Logging:LogLevel의 설정을 재정의합니다.

최소 로그 수준은 다음에 대해 지정할 수 있습니다.

  • 특정 공급자: 예를 들면 Logging:EventSource:LogLevel:Default:Information과 같습니다.
  • 특정 범주: 예를 들어 Logging:LogLevel:Microsoft:Warning
  • 모든 공급자와 모든 범주: Logging:LogLevel:Default:Warning

최소 수준 이하의 모든 로그는 다음과 같이 되지 않습니다.

  • 공급자에 전달됩니다.
  • 로그되거나 표시됩니다.

모든 로그를 표시하지 않으려면 LogLevel.None을 지정합니다. LogLevel.None의 값은 LogLevel.Critical(5)보다 높은 6입니다.

공급자가 로그 범위를 지원하는 경우 IncludeScopes는 사용 가능 여부를 나타냅니다. 자세한 내용은 로그 범위를 참조하세요.

다음 appsettings.json 파일에는 기본적으로 사용하도록 설정되는 모든 공급자가 포함되어 있습니다.

{
  "Logging": {
    "LogLevel": { // No provider, LogLevel applies to all the enabled providers.
      "Default": "Error",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Warning"
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information" // Overrides preceding LogLevel:Default setting.
      }
    },
    "Console": {
      "IncludeScopes": true,
      "LogLevel": {
        "Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
        "Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
        "Microsoft.AspNetCore.Mvc.Razor": "Error",
        "Default": "Information"
      }
    },
    "EventSource": {
      "LogLevel": {
        "Microsoft": "Information"
      }
    },
    "EventLog": {
      "LogLevel": {
        "Microsoft": "Information"
      }
    },
    "AzureAppServicesFile": {
      "IncludeScopes": true,
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "AzureAppServicesBlob": {
      "IncludeScopes": true,
      "LogLevel": {
        "Microsoft": "Information"
      }
    },
    "ApplicationInsights": {
      "LogLevel": {
        "Default": "Information"
      }
    }
  }
}

앞의 예제에서:

  • 범주 및 수준은 제안된 값이 아닙니다. 샘플은 모든 기본 공급자를 표시하기 위해 제공됩니다.
  • Logging.{PROVIDER NAME}.LogLevel의 설정은 Logging.LogLevel의 설정을 재정의합니다. 여기서 {PROVIDER NAME} 자리 표시자는 공급자 이름입니다. 예를 들어 Debug.LogLevel.Default 수준은 LogLevel.Default수준을 재정의합니다.
  • 각 기본 공급자 ‘별칭’을 사용합니다. 각 공급자는 정규화된 형식 이름 대신 구성에서 사용할 수 있는 별칭을 정의합니다. 기본 제공 공급자 별칭은 다음과 같습니다.
    • Console
    • Debug
    • EventSource
    • EventLog
    • AzureAppServicesFile
    • AzureAppServicesBlob
    • ApplicationInsights

Program.cs의 로그

다음 예제는 Program.cs 및 로그 정보 메시지에서 Builder.WebApplication.Logger를 호출합니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Logger.LogInformation("Adding Routes");
app.MapGet("/", () => "Hello World!");
app.Logger.LogInformation("Starting the app");
app.Run();

다음 예제는 Program.cs에서 AddConsole을 호출하고 /Test 엔드포인트를 로그합니다.

var builder = WebApplication.CreateBuilder(args);

builder.Logging.AddConsole();

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.MapGet("/Test", async (ILogger<Program> logger, HttpResponse response) =>
{
    logger.LogInformation("Testing logging in Program.cs");
    await response.WriteAsync("Testing");
});

app.Run();

다음 예제는 Program.cs에서 AddSimpleConsole을 호출하고, 색상 출력을 비활성화하며, /Test 엔드포인트를 로그합니다.

using Microsoft.Extensions.Logging.Console;

var builder = WebApplication.CreateBuilder(args);

builder.Logging.AddSimpleConsole(i => i.ColorBehavior = LoggerColorBehavior.Disabled);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.MapGet("/Test", async (ILogger<Program> logger, HttpResponse response) =>
{
    logger.LogInformation("Testing logging in Program.cs");
    await response.WriteAsync("Testing");
});

app.Run();

명령줄, 환경 변수 및 기타 구성으로 로그 수준 설정

로그 수준은 구성 공급자 중 하나로 설정할 수 있습니다.

: 구분 기호는 모든 플랫폼의 환경 변수 계층적 키에서 작동하지 않습니다. 이중 밑줄 __은 다음과 같습니다.

  • 모든 플랫폼에서 지원됩니다. 예를 들어 : 구분 기호는 Bash에서 지원되지 않지만 __은 지원됩니다.
  • 자동으로 :으로 대체

다음 명령은,

  • Windows에서 환경 키 Logging:LogLevel:MicrosoftInformation 값으로 설정합니다.
  • ASP.NET Core 웹 애플리케이션 템플릿을 사용하여 만든 앱을 사용할 때 설정을 테스트합니다. dotnet run 명령은 set을 사용한 후 프로젝트 디렉터리에서 실행해야 합니다.
set Logging__LogLevel__Microsoft=Information
dotnet run

위의 환경 설정은,

  • 설정된 명령 창에서 시작된 프로세스에서만 설정됩니다.
  • Visual Studio에서 시작된 브라우저에서는 읽을 수 없습니다.

다음 setx 명령은 Windows에서 환경 키 및 값도 설정합니다. set와 달리, setx 설정은 유지됩니다. /M 스위치는 시스템 환경에서 변수를 설정합니다. /M을 사용하지 않으면 사용자 환경 변수가 설정됩니다.

setx Logging__LogLevel__Microsoft Information /M

다음 appsettings.json 파일을 살펴보세요.

"Logging": {
  "Console": {
    "LogLevel": {
      "Microsoft.Hosting.Lifetime": "Trace"
    }
  }
}

다음 명령은 환경에서 위의 구성을 설정합니다.

setx Logging__Console__LogLevel__Microsoft.Hosting.Lifetime Trace /M

참고 항목

macOS 및 Linux에서 마침표(마침표)가 포함된 . 이름으로 환경 변수를 구성할 때는 "점(.)을 사용하여 변수 내보내기(.) Stack Exchange 및 해당 수락된 답변에 대한 "in it" 질문입니다.

Azure App Service설정 > 구성 페이지에서 새 애플리케이션 설정을 선택합니다. Azure App Service 애플리케이션 설정은,

  • 미사용 시 암호화되고 암호화된 채널을 통해 전송됩니다.
  • 환경 변수로 노출됩니다.

자세한 내용은 Azure 앱: Azure Portal을 사용하여 앱 구성 재정의를 참조하세요.

환경 변수를 사용하여 ASP.NET Core 구성 값을 설정하는 방법에 대한 자세한 내용은 환경 변수를 참조하세요. 명령줄, Azure Key Vault, Azure App Configuration, 기타 파일 형식 등을 포함하여 다른 구성 원본을 사용하는 방법에 대한 자세한 내용은 ASP.NET Core의 구성을 참조하세요.

필터링 규칙 적용 방식

ILogger<TCategoryName> 개체를 만들 때 ILoggerFactory 개체는 공급자마다 해당 로거에 적용할 단일 규칙을 선택합니다. ILogger 인스턴스에서 작성된 모든 메시지는 선택한 규칙에 따라 필터링됩니다. 사용 가능한 규칙 중에서 각 공급자 및 범주 쌍과 가장 관련이 많은 규칙이 선택됩니다.

지정된 범주에 대한 ILogger가 생성되면 다음 알고리즘이 각 공급자에 사용됩니다.

  • 공급자 또는 공급자의 별칭과 일치하는 모든 규칙을 선택합니다. 일치하는 규칙이 없는 경우 빈 공급자가 있는 모든 규칙을 선택합니다.
  • 앞 단계의 결과에서 일치하는 범주 접두사가 가장 긴 규칙을 선택합니다. 일치하는 규칙이 없는 경우 범주를 지정하지 않는 규칙을 모두 선택합니다.
  • 여러 규칙을 선택하는 경우 마지막 규칙을 사용합니다.
  • 규칙을 선택하지 않는 경우 MinimumLevel을 사용합니다.

dotnet run 및 Visual Studio의 로깅 출력

기본 로깅 공급자를 사용하여 만든 로그는 다음과 같이 표시됩니다.

  • Visual Studio에서
    • 디버그할 때 디버그 출력 창에 표시됨
    • ASP.NET Core 웹 서버 창에 표시됨
  • dotnet run을 사용하여 앱을 실행할 때 콘솔 창에 표시됨

“Microsoft” 범주로 시작하는 로그는 ASP.NET Core 프레임워크 코드에서 온 것입니다. ASP.NET Core 및 애플리케이션 코드는 동일한 로깅 API와 공급자를 사용합니다.

로그 범주

ILogger 개체가 생성되면 ‘범주’가 지정됩니다. 해당 범주는 ILogger의 해당 인스턴스에서 만든 각 로그 메시지에 포함됩니다. 범주 문자열은 임의이지만 규칙은 정규화된 클래스 이름을 사용하는 것입니다. 예를 들어 컨트롤러에서 이름은 "TodoApi.Controllers.TodoController"일 수 있습니다. ASP.NET Core 웹앱은 ILogger<T>를 사용하여 T의 정규화된 형식 이름을 범주로 사용하는 ILogger 인스턴스를 자동으로 가져옵니다.

public class PrivacyModel : PageModel
{
    private readonly ILogger<PrivacyModel> _logger;

    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.PrivacyModel called.");
    }
}

추가 분류가 필요한 경우 규칙은 정규화된 클래스 이름에 하위 범주를 추가하여 계층적 이름을 사용하고 다음을 사용하여 ILoggerFactory.CreateLogger범주를 명시적으로 지정하는 것입니다.

public class ContactModel : PageModel
{
    private readonly ILogger _logger;

    public ContactModel(ILoggerFactory logger)
    {
        _logger = logger.CreateLogger("TodoApi.Pages.ContactModel.MyCategory");
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.ContactModel called.");
    }

고정 이름을 사용하여 CreateLogger를 호출하면 여러 메서드에서 사용할 때 유용할 수 있으므로 이벤트를 범주별로 구성할 수 있습니다.

ILogger<T>T의 정규화된 형식 이름으로 CreateLogger를 호출하는 것과 동일합니다.

로그 수준

다음 표에서는 LogLevel 값, 편리한 Log{LogLevel} 확장 메서드 및 추천 사용법을 설명합니다.

LogLevel 메서드 설명
Trace 0 LogTrace 가장 자세한 메시지를 포함합니다. 해당 메시지는 중요한 앱 데이터를 포함할 수 있습니다. 해당 메시지는 기본적으로 사용하지 않도록 설정되며 프로덕션에서 사용하도록 설정하면 안 됩니다.
Debug 1 LogDebug 디버깅 및 개발을 위한 수준입니다. 너무 많으므로 프로덕션에서는 주의해서 사용합니다.
Information 2 LogInformation 앱의 일반적인 흐름을 추적합니다. 장기적인 값이 있을 수 있습니다.
Warning 3 LogWarning 비정상적이거나 예기치 않은 이벤트를 위한 수준입니다. 일반적으로 앱의 오류를 발생시키지 않는 오류 또는 조건을 포함합니다.
Error 4 LogError 처리할 수 없는 오류 및 예외입니다. 해당 메시지는 전체 앱 오류가 아닌 현재 작업 또는 요청의 오류를 의미합니다.
Critical 5 LogCritical 즉각적인 대응이 필요한 오류를 위한 수준입니다. 예: 데이터 손실 시나리오, 디스크 공간 부족.
None 6 로깅 범주에서 메시지를 쓰지 않도록 지정합니다.

위의 표에서는 LogLevel이 심각도가 낮은 것에서 높은 것 순으로 표시됩니다.

Log 메서드의 첫 번째 매개 변수인 LogLevel은 로그의 심각도를 나타냅니다. 대부분의 개발자는 Log(LogLevel, ...)를 호출하는 대신, Log{LOG LEVEL} 확장 메서드를 호출합니다. 여기서 {LOG LEVEL} 자리 표시자는 로그 수준입니다. 예를 들어 다음 두 로깅 호출은 기능이 동일하며 같은 로그를 생성합니다.

[HttpGet]
public IActionResult Test1(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);

    _logger.Log(LogLevel.Information, MyLogEvents.TestItem, routeInfo);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    return ControllerContext.MyDisplayRouteInfo();
}

MyLogEvents.TestItem은 이벤트 ID입니다. MyLogEvents는 샘플 앱의 일부이며 로그 이벤트 ID 섹션에 표시됩니다.

MyDisplayRouteInfo 및 ToCtxStringRick.Docs.Samples.RouteInfo NuGet 패키지가 제공합니다. 이 메서드는 ControllerRazor Page 경로 정보를 표시합니다.

다음 코드는 InformationWarning 로그를 만듭니다.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

위의 코드에서 첫 번째 Log{LOG LEVEL} 매개 변수 MyLogEvents.GetItem로그 이벤트 ID입니다. 두 번째 매개 변수는 나머지 메서드 매개 변수가 제공하는 인수 값에 대한 자리 표시자를 포함하고 있는 메시지 템플릿입니다. 메서드 매개 변수는 이 문서의 뒷부분에 있는 메시지 템플릿 섹션에 설명되어 있습니다.

적절한 Log{LOG LEVEL} 메서드를 호출하여 특정 스토리지 매체에 기록되는 로그 출력의 양을 제어합니다. 예시:

  • 프로덕션:
    • 또는 DebugInformation 수준에서 로깅Trace하면 많은 양의 자세한 로그 메시지가 생성됩니다. 비용을 제어하고 데이터 스토리지 한도, 로그 TraceDebug또는 Information 수준 메시지를 대용량 저비용 데이터 저장소에 초과하지 않도록 합니다. 또는 DebugInformation 특정 범주를 Trace제한하는 것이 좋습니다.
    • Warning~Critical 수준의 로깅은 적은 로그 메시지를 생성합니다.
      • 비용과 스토리지 제한이 일반적으로 문제가 되지 않습니다.
      • 로그가 적으므로 데이터 저장소를 더 유연하게 선택할 수 있습니다.
  • 개발 중:
    • Warning로 설정합니다.
    • 문제 해결 시 추가 또는 DebugInformation 메시지를 추가Trace합니다. 출력을 제한하려면 조사 중인 범주에 대해서만 설정하거나 Information 설정합니다TraceDebug.

ASP.NET Core는 프레임워크 이벤트에 대한 로그를 작성합니다. 예를 들어 다음의 로그 출력을 고려하세요.

  • ASP.NET Core 템플릿을 사용하여 만든 Razor Pages 앱
  • 로깅을 Logging:Console:LogLevel:Microsoft:Information으로 설정
  • Privacy 페이지 탐색:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 GET https://localhost:5001/Privacy
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint '/Privacy'
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
      Route matched with {page = "/Privacy"}. Executing page /Privacy
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[101]
      Executing handler method DefaultRP.Pages.PrivacyModel.OnGet - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[102]
      Executed handler method OnGet, returned result .
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
      Executing an implicit handler method - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
      Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
      Executed page /Privacy in 74.5188ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint '/Privacy'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 149.3023ms 200 text/html; charset=utf-8

다음 JSON은 Logging:Console:LogLevel:Microsoft:Information을 설정합니다.

{
  "Logging": {      // Default, all providers.
    "LogLevel": {
      "Microsoft": "Warning"
    },
    "Console": { // Console provider.
      "LogLevel": {
        "Microsoft": "Information"
      }
    }
  }
}

로그 이벤트 ID

각 로그는 이벤트 ID를 지정할 수 있습니다. 샘플 앱에서는 MyLogEvents 클래스를 사용하여 이벤트 ID를 정의합니다.

public class MyLogEvents
{
    public const int GenerateItems = 1000;
    public const int ListItems     = 1001;
    public const int GetItem       = 1002;
    public const int InsertItem    = 1003;
    public const int UpdateItem    = 1004;
    public const int DeleteItem    = 1005;

    public const int TestItem      = 3000;

    public const int GetItemNotFound    = 4000;
    public const int UpdateItemNotFound = 4001;
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

이벤트 ID는 이벤트 집합을 연결합니다. 예를 들어 페이지에서 항목 목록을 표시하는 것과 관련된 모든 로그는 1001일 수 있습니다.

로깅 공급자는 이벤트 ID를 ID 필드, 로그 메시지에 저장하거나 또는 전혀 저장하지 않을 수도 있습니다. 디버그 공급자는 이벤트 ID를 표시하지 않습니다. 콘솔 공급자는 범주 뒤에 대괄호로 이벤트 ID를 표시합니다.

info: TodoApi.Controllers.TodoItemsController[1002]
      Getting item 1
warn: TodoApi.Controllers.TodoItemsController[4000]
      Get(1) NOT FOUND

일부 로깅 공급자는 ID에 대한 필터링을 허용하는 필드에 이벤트 ID를 저장합니다.

로그 메시지 템플릿

각 로그 API는 메시지 템플릿을 사용합니다. 메시지 템플릿에는 인수가 제공되는 자리 표시자를 포함할 수 있습니다. 번호가 아닌 자리 표시자의 이름을 사용합니다.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

해당 자리 표시자 이름이 아니라 매개 변수의 순서가 로그 메시지에 자리 표시자 값을 제공하는 데 사용되는 매개 변수를 결정합니다. 다음 코드에서는 매개 변수 이름의 순서가 메시지 템플릿 내 자리 표시자의 순서와 일치하지 않습니다.

var apples = 1;
var pears = 2;
var bananas = 3;

_logger.LogInformation("Parameters: {Pears}, {Bananas}, {Apples}", apples, pears, bananas);

그러나 매개 변수는 apples, pears, bananas의 순서로 자리 표시자에 할당됩니다. 로그 메시지는 매개 변수의 순서를 반영합니다.

Parameters: 1, 2, 3

해당 접근 방식을 통해 로깅 공급자는 의미 체계 또는 구조적 로깅를 구현할 수 있습니다. 인수 자체는 서식이 지정된 메시지 템플릿뿐만 아니라 로깅 시스템에 전달됩니다. 따라서 로깅 공급자는 매개 변수 값을 필드로 저장할 수 있습니다. 예를 들어 다음 로거 메서드를 살펴보세요.

_logger.LogInformation("Getting item {Id} at {RequestTime}", id, DateTime.Now);

Azure Table Storage에 로그할 경우를 예로 듭니다.

  • 각 Azure Table 엔터티에는 IDRequestTime 속성이 있을 수 있습니다.
  • 속성이 있는 테이블은 로그된 데이터의 쿼리를 쉽게 합니다. 예를 들어 문자 메시지의 시간 초과를 구문 분석하지 않고도 특정 RequestTime 범위 내에 있는 모든 로그를 쿼리를 통해 찾을 수 있습니다.

예외 기록

로거 메서드에는 예외 매개 변수를 사용하는 오버로드가 있습니다.

[HttpGet("{id}")]
public IActionResult TestExp(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    try
    {
        if (id == 3)
        {
            throw new Exception("Test exception");
        }
    }
    catch (Exception ex)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, ex, "TestExp({Id})", id);
        return NotFound();
    }

    return ControllerContext.MyDisplayRouteInfo();
}

MyDisplayRouteInfo 및 ToCtxStringRick.Docs.Samples.RouteInfo NuGet 패키지가 제공합니다. 이 메서드는 ControllerRazor Page 경로 정보를 표시합니다.

예외 로깅은 공급자별로 다릅니다.

기본 로그 수준

기본 로그 수준을 설정하지 않으면 기본 로그 수준 값은 Information입니다.

예를 들어 다음 웹앱을 고려하세요.

  • ASP.NET 웹앱 템플릿을 사용하여 만들었습니다.
  • appsettings.jsonappsettings.Development.json이 삭제되었거나 이름이 변경되었습니다.

이전 설정을 사용하여 개인정보처리방침이나 홈페이지로 이동하면 범주 이름에 Microsoft가 포함된 Trace, DebugInformation 메시지가 많이 생성됩니다.

다음 코드에서는 구성에 기본 로그 수준이 설정되어 있지 않은 경우 기본 로그 수준을 설정합니다.

var builder = WebApplication.CreateBuilder();
builder.Logging.SetMinimumLevel(LogLevel.Warning);

일반적으로 로그 수준은 코드에서가 아니라 구성에서 지정해야 합니다.

필터 함수

필터 함수는 구성 또는 코드를 통해 규칙이 할당되지 않은 모든 공급자와 범주에 대해 호출됩니다.

var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter((provider, category, logLevel) =>
{
    if (provider.Contains("ConsoleLoggerProvider")
        && category.Contains("Controller")
        && logLevel >= LogLevel.Information)
    {
        return true;
    }
    else if (provider.Contains("ConsoleLoggerProvider")
        && category.Contains("Microsoft")
        && logLevel >= LogLevel.Information)
    {
        return true;
    }
    else
    {
        return false;
    }
});

앞의 코드는 범주에 Controller 또는 Microsoft가 포함되어 있고 로그 수준이 Information 이상인 경우 콘솔 로그를 표시합니다.

일반적으로 로그 수준은 코드에서가 아니라 구성에서 지정해야 합니다.

ASP.NET Core 및 EF Core 범주

다음 표에는 ASP.NET Core 및 Entity Framework Core에서 사용되는 몇 가지 범주와 로그에 관한 참고 사항이 나와 있습니다.

범주 주의
Microsoft.AspNetCore 일반 ASP.NET Core 진단.
Microsoft.AspNetCore.DataProtection 고려되고, 발견되고, 사용된 키.
Microsoft.AspNetCore.HostFiltering 허용되는 호스트.
Microsoft.AspNetCore.Hosting HTTP 요청을 완료하는 데 걸린 시간과 시작 시간. 로드된 호스팅 시작 어셈블리.
Microsoft.AspNetCore.Mvc MVC 및 Razor 진단. 모델 바인딩, 필터 실행, 뷰 컴파일 작업 선택.
Microsoft.AspNetCore.Routing 경로 일치 정보.
Microsoft.AspNetCore.Server 연결 시작, 중지 및 활성 응답 유지. HTTPS 인증서 정보.
Microsoft.AspNetCore.StaticFiles 제공된 파일.
Microsoft.EntityFrameworkCore 일반 Entity Framework Core 진단. 데이터베이스 작업 및 구성, 변경 내용 검색, 마이그레이션.

콘솔 창에서 더 많은 범주를 보려면 appsettings.Development.json을 다음으로 설정합니다.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Trace",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

로그 점수

범위는 논리적 작업 집합을 그룹화할 수 있습니다. 이 그룹화는 집합의 일부로 생성된 각 로그에 동일한 데이터를 연결하는 데 사용될 수 있습니다. 예를 들어 트랜잭션 처리의 일부로 생성되는 모든 로그에는 트랜잭션 ID가 포함될 수 있습니다.

범위:

  • BeginScope 메서드에서 반환하는 IDisposable 형식입니다.
  • 삭제될 때까지 유지됩니다.

범위를 지원하는 공급자는 다음과 같습니다.

using 블록에 로거 호출을 래핑하여 범위를 사용합니다.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    TodoItem todoItem;
    var transactionId = Guid.NewGuid().ToString();
    using (_logger.BeginScope(new List<KeyValuePair<string, object>>
        {
            new KeyValuePair<string, object>("TransactionId", transactionId),
        }))
    {
        _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

        todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            _logger.LogWarning(MyLogEvents.GetItemNotFound, 
                "Get({Id}) NOT FOUND", id);
            return NotFound();
        }
    }

    return ItemToDTO(todoItem);
}

기본 제공 로깅 공급자

ASP.NET Core에는 공유 프레임워크의 일부로 다음과 같은 로깅 공급자가 포함되어 있습니다.

다음 로깅 공급자는 Microsoft에서 제공하지만 공유 프레임워크의 일부로 제공하는 것은 아닙니다. 추가 NuGet으로 설치해야 합니다.

ASP.NET Core에는 파일에 로그를 기록하기 위한 로깅 공급자가 포함되지 않습니다. ASP.NET Core 앱에서 파일에 로그를 쓰려면 타사 로깅 공급자를 사용하는 것이 좋습니다.

ASP.NET Core 모듈을 사용한 stdout 및 디버그 로깅에 대한 자세한 내용은 Azure App Service 및 IIS에서 ASP.NET Core 문제 해결IIS용 ANCM(ASP.NET Core 모듈)을 참조하세요.

콘솔

Console 공급자는 콘솔에 출력을 로그합니다. 개발 중인 Console 로그를 보는 방법에 대한 자세한 내용은 dotnet run 및 Visual Studio의 로깅 출력을 참조하세요.

디버그

Debug 공급자는 System.Diagnostics.Debug 클래스를 사용하여 로그 출력을 기록합니다. System.Diagnostics.Debug.WriteLine을 호출하여 Debug 공급자에 기록합니다.

Linux에서 Debug 공급자 로그 위치는 배포판마다 다르며 다음 중 하나일 수 있습니다.

  • /var/log/message
  • /var/log/syslog

이벤트 원본

EventSource 공급자는 이름이 Microsoft-Extensions-Logging인 플랫폼 간 이벤트 원본에 기록합니다. Windows에서 공급자는 ETW를 사용합니다.

dotnet-trace 도구

dotnet-trace 도구는 실행 중인 프로세스의 .NET Core 추적을 수집할 수 있도록 하는 플랫폼 간 CLI 전역 도구입니다. 이 도구는 LoggingEventSource를 사용하여 Microsoft.Extensions.Logging.EventSource 공급자 데이터를 수집합니다.

설치 지침은 .를 참조하세요 dotnet-trace.

dotnet-trace 도구를 사용하여 앱에서 추적을 수집합니다.

  1. dotnet run 명령으로 앱을 실행합니다.

  2. .NET Core 앱의 PID(프로세스 식별자)를 확인합니다.

    dotnet-trace ps
    

    앱의 어셈블리와 동일한 이름의 프로세스에 대한 PID를 찾습니다.

  3. dotnet-trace 명령을 실행합니다.

    일반 명령 구문:

    dotnet-trace collect -p {PID} 
        --providers Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"
    

    PowerShell 명령 셸을 사용하는 경우 --providers 값을 작은따옴표(')로 묶습니다.

    dotnet-trace collect -p {PID} 
        --providers 'Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"'
    

    Windows가 아닌 플랫폼에서는 출력 추적 파일의 형식을 speedscope로 변경하는 -f speedscope 옵션을 추가합니다.

    다음 표에서는 키워드를 정의합니다.

    키워드 설명
    1 LoggingEventSource에 대한 로그 메타 이벤트입니다. ILogger에서 이벤트를 로깅하지 않습니다.
    2 ILogger.Log()가 호출될 때 Message 이벤트 설정을 켭니다. 서식 지정되지 않은 프로그래밍 방식으로 정보를 제공합니다.
    4 ILogger.Log()가 호출될 때 FormatMessage 이벤트 설정을 켭니다. 서식 지정된 문자열 버전의 정보를 제공합니다.
    8 ILogger.Log()가 호출될 때 MessageJson 이벤트 설정을 켭니다. 인수의 JSON 표현을 제공합니다.

    다음 표에는 공급자 수준이 나열되어 있습니다.

    공급자 수준 설명
    0 LogAlways
    1 Critical
    2 Error
    3 Warning
    4 Informational
    5 Verbose

    범주 수준에 대한 구문 분석은 문자열 또는 숫자일 수 있습니다.

    범주 명명된 값 숫자 값
    Trace 0
    Debug 1
    Information 2
    Warning 3
    Error 4
    Critical 5

    공급자 수준 및 범주 수준:

    • 역순입니다.
    • 문자열 상수가 모두 동일하지는 않습니다.

    FilterSpecs를 지정하지 않을 경우 EventSourceLogger 구현이 공급자 수준을 범주 수준으로 변환하고 모든 범주에 적용합니다.

    공급자 수준 범주 수준
    Verbose(5) Debug(1)
    Informational(4) Information(2)
    Warning(3) Warning(3)
    Error(2) Error(4)
    Critical(1) Critical(5)

    FilterSpecs를 제공하는 경우 목록에 포함된 모든 범주가 인코딩된 범주 수준을 사용합니다. 다른 모든 범주는 필터링됩니다.

    다음 예제에서는 다음과 같이 가정합니다.

    • 앱이 실행 중이고 logger.LogDebug("12345")를 호출합니다.
    • PID(프로세스 ID)가 set PID=12345를 통해 설정되었습니다. 여기서 12345는 실제 PID입니다.

    다음 명령을 생각해 볼 수 있습니다.

    dotnet-trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5
    

    이전 명령:

    • 디버그 메시지를 캡처합니다.
    • FilterSpecs를 적용하지 않습니다.
    • 범주 디버그를 매핑하는 수준 5를 지정합니다.

    다음 명령을 생각해 볼 수 있습니다.

    dotnet-trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:5\"
    

    이전 명령:

    • 디버그 메시지를 캡처하지 않습니다. 범주 수준 5가 Critical이기 때문입니다.
    • FilterSpecs를 제공합니다.

    다음 명령은 디버그 메시지를 캡처합니다. 범주 수준 1이 Debug이기 때문입니다.

    dotnet-trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:1\"
    

    다음 명령은 디버그 메시지를 캡처합니다. 범주가 Debug를 지정하기 때문입니다.

    dotnet-trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:Debug\"
    

    FilterSpecs{Logger Category}{Category Level}에 대한 항목은 추가 로그 필터링 조건을 나타냅니다. ; 세미콜론 문자를 사용하여 FilterSpecs 항목을 구분합니다.

    Windows 명령 셸을 사용하는 예제:

    dotnet-trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:2:FilterSpecs=\"Microsoft.AspNetCore.Hosting*:4\"
    

    이전 명령은 다음과 같이 활성화됩니다.

    • (2) 오류에 대해 형식이 지정된 문자열(4)을 생성하는 이벤트 원본 로거입니다.
    • Informational 로깅 수준에서 Microsoft.AspNetCore.Hosting 로깅(4).
  4. dotnet-trace Enter 키 또는 Ctrl+C를 눌러 도구를 중지합니다.

    추적은 dotnet-trace 명령이 실행되는 폴더에 trace.nettrace라는 이름으로 저장됩니다.

  5. Perfview를 사용하여 추적을 엽니다. trace.nettrace 파일을 열고 추적 이벤트를 탐색합니다.

앱이 호스트 WebApplication.CreateBuilder를 빌드하지 않는 경우 이벤트 원본 공급자를 앱의 로깅 구성에 추가합니다.

자세한 내용은 다음을 참조하세요.

Perfview

PerfView 유틸리티를 사용하여 로그를 수집하고 볼 수 있습니다. ETW 로그를 보는 다른 도구도 있지만, PerfView는 ASP.NET Core에서 내보내는 ETW 이벤트를 처리하기에 가장 좋은 환경을 제공합니다.

이 공급자가 기록한 이벤트를 수집하도록 PerfView를 구성하려면 추가 공급자 목록에 *Microsoft-Extensions-Logging 문자열을 추가합니다. 문자열의 시작 부분에 *를 누락하지 마세요.

Windows EventLog

EventLog 공급자는 로그 출력을 Windows 이벤트 로그에 보냅니다. 다른 공급자와 달리 EventLog 공급자는 기본 비공급자 설정을 상속하지 않습니다. EventLog 로그 설정을 지정하지 않으면 기본적으로 LogLevel.Warning으로 설정됩니다.

LogLevel.Warning 수준보다 낮은 이벤트를 기록하려면 로그 수준을 명시적으로 설정합니다. 다음 예제에서는 이벤트 로그 기본 로그 수준을 LogLevel.Information으로 설정합니다.

"Logging": {
  "EventLog": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

AddEventLog 오버로드는 EventLogSettings를 전달할 수 있습니다. null이거나 지정하지 않으면 다음 기본 설정이 사용됩니다.

  • LogName: "Application"
  • SourceName: “.NET Runtime”
  • MachineName: 로컬 컴퓨터 이름이 사용됩니다.

다음 코드에서는 SourceName을 기본값 ".NET Runtime"에서 MyLogs로 변경합니다.


var builder = WebApplication.CreateBuilder();
builder.Logging.AddEventLog(eventLogSettings =>
{
    eventLogSettings.SourceName = "MyLogs";
});

Azure App Service

Microsoft.Extensions.Logging.AzureAppServices 공급자 패키지는 Azure App Service 앱의 파일 시스템 및 Azure Storage 계정의 Blob 스토리지에 텍스트 파일로 로그를 기록합니다.

이 공급자 패키지는 공유 프레임워크에 포함되어 있지 않습니다. 이 공급자를 사용하려면 프로젝트에 공급자 패키지를 추가합니다.

공급자 설정을 구성하려면 다음 예제와 같이 AzureFileLoggerOptionsAzureBlobLoggerOptions를 사용합니다.

using Microsoft.Extensions.Logging.AzureAppServices;

var builder = WebApplication.CreateBuilder();
builder.Logging.AddAzureWebAppDiagnostics();
builder.Services.Configure<AzureFileLoggerOptions>(options =>
{
    options.FileName = "azure-diagnostics-";
    options.FileSizeLimit = 50 * 1024;
    options.RetainedFileCountLimit = 5;
});
builder.Services.Configure<AzureBlobLoggerOptions>(options =>
{
    options.BlobName = "log.txt";
});

Azure App Service에 배포하는 경우 앱은 Azure Portal에서 App Service 페이지에 있는 App Service 로그 섹션의 설정을 사용합니다. 다음 설정이 업데이트되면 앱을 다시 시작하거나 재배포하지 않아도 변경 내용이 즉시 적용됩니다.

  • 애플리케이션 로깅(파일 시스템)
  • 애플리케이션 로깅(Blob)

로그 파일의 기본 위치는 D:\\home\\LogFiles\\Application 폴더이고 기본 파일 이름은 diagnostics-yyyymmdd.txt입니다. 기본 파일 크기 제한은 10MB이고, 보존되는 기본 최대 파일 수는 2입니다. 기본 Blob 이름은 {app-name}{timestamp}/yyyy/mm/dd/hh/{guid}-applicationLog.txt입니다.

이 공급자는 프로젝트가 Azure 환경에서 실행되는 경우에만 로그합니다.

Azure 로그 스트리밍

Azure 로그 스트리밍을 통해 다음에서 로그 활동을 실시간으로 볼 수 있습니다.

  • 앱 서버
  • 웹 서버
  • 실패한 요청 추적

Azure 로그 스트리밍을 구성하려면:

  • 앱의 포털 페이지에서 App Service 로그 페이지로 이동합니다.
  • 애플리케이션 로깅(파일 시스템)On으로 설정합니다.
  • 로그 수준을 선택합니다. 이 설정은 Azure 로그 스트리밍에만 적용됩니다.

로그 스트림 페이지로 이동하여 로그를 봅니다. 로드되는 메시지는 ILogger 인터페이스를 사용하여 로그됩니다.

Azure Application Insights

Microsoft.Extensions.Logging.ApplicationInsights 공급자 패키지는 Azure Application Insights에 로그를 기록합니다. Application Insights는 웹앱을 모니터링하고 원격 분석 데이터를 쿼리 및 분석하기 위한 도구를 제공하는 서비스입니다. 이 공급자를 사용하는 경우 Application Insights 도구를 사용하여 로그를 쿼리 및 분석할 수 있습니다.

로깅 공급자는 ASP.NET Core에 대한 모든 사용 가능한 원격 분석을 제공하는 패키지인 Microsoft.ApplicationInsights.AspNetCore의 종속성으로 포함됩니다. 이 패키지를 사용하는 경우 공급자 패키지를 설치할 필요가 없습니다.

Microsoft.ApplicationInsights.Web 패키지는 ASP.NET Core가 아닌 ASP.NET 4.x용입니다.

자세한 내용은 다음 리소스를 참조하세요.

타사 로깅 공급자

ASP.NET Core와 호환되는 타사 로깅 프레임워크는 다음과 같습니다.

일부 타사 프레임워크는 구조적 로깅이라고 하는 의미 체계 로깅을 수행할 수 있습니다.

타사 프레임워크를 사용하는 방법은 다음과 같이 기본 공급자 중 하나를 사용하는 방법과 비슷합니다.

  1. 프로젝트에 NuGet 패키지를 추가합니다.
  2. 로깅 프레임워크에서 제공하는 ILoggerFactory 확장 메서드를 호출합니다.

자세한 내용은 각 공급자의 설명서를 참조하세요. 타사 로깅 공급자는 Microsoft에서 지원되지 않습니다.

비동기 로거 메서드 미지원

로깅은 매우 빨라서 비동기 코드의 성능 비용을 들일 필요가 없습니다. 로깅 데이터 저장소가 느린 경우 직접 작성하지 마세요. 로그 메시지를 처음에 빠른 저장소에 작성한 다음, 나중에 느린 저장소로 이동하는 것이 좋습니다. 예를 들어 SQL Server에 로그하는 경우 Log 메서드는 동기식이므로 Log 메서드에서 직접 로그하지 마세요. 대신 동기적으로 로그 메시지를 메모리 내 큐에 추가하고 백그라운드 작업자가 큐에서 메시지를 풀하여 SQL Server에 대해 비동기 데이터 푸시 작업을 수행하도록 합니다. 자세한 내용은 느린 데이터 저장소의 메시지 큐에 로깅하는 방법에 대한 지침(dotnet/AspNetCore.Docs #11801)을 참조하세요.

실행 중인 앱에서 로그 수준 변경

로깅 API는 앱이 실행되는 동안 로그 수준을 변경하는 시나리오를 포함하지 않습니다. 그러나 일부 구성 공급자는 구성을 다시 로드할 수 있으며 이는 로깅 구성에 대한 즉각적인 영향을 줍니다. 예를 들어 파일 구성 공급자는 기본적으로 로깅 구성을 다시 로드합니다. 앱이 실행되는 동안 코드에서 구성이 변경되면 앱이 IConfigurationRoot.Reload를 호출하여 앱의 로깅 구성을 업데이트할 수 있습니다.

ILogger 및 ILoggerFactory

ILogger<TCategoryName>ILoggerFactory 인터페이스와 구현은 .NET Core SDK에 포함되어 있습니다. 또한 다음 NuGet 패키지에서도 사용할 수 있습니다.

코드에서 로그 필터 규칙 적용

로그 필터 규칙을 설정하는 기본 방법은 구성을 사용하는 것입니다.

다음 예제에서는 코드에 필터 규칙을 등록하는 방법을 보여줍니다.

using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Logging.Debug;

var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter("System", LogLevel.Debug);
builder.Logging.AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information);
builder.Logging.AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace);

logging.AddFilter("System", LogLevel.Debug)System범주 및 로그 수준Debug을 지정합니다. 특정 공급자를 구성하지 않았으므로 필터가 모든 공급자에 적용됩니다.

AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)은 다음을 지정합니다.

  • Debug 로깅 공급자
  • 로그 수준 Information 이상
  • "Microsoft"로 시작하는 모든 범주

SpanId, TraceId, ParentId, BaggageTags를 사용하여 자동으로 로그 범위를 지정합니다.

로깅 라이브러리는 SpanId, TraceId, ParentId,BaggageTags를 사용하여 암시적으로 범위 개체를 만듭니다. 이 동작은 ActivityTrackingOptions를 통해 구성됩니다.

var builder = WebApplication.CreateBuilder(args);

builder.Logging.AddSimpleConsole(options =>
{
    options.IncludeScopes = true;
});

builder.Logging.Configure(options =>
{
    options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
                                       | ActivityTrackingOptions.TraceId
                                       | ActivityTrackingOptions.ParentId
                                       | ActivityTrackingOptions.Baggage
                                       | ActivityTrackingOptions.Tags;
});
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

traceparent http 요청 헤더가 설정된 경우 로그 범위의 ParentId는 인바운드 traceparent 헤더의 W3C parent-id를 표시하고, 로그 범위의 SpanId는 다음 아웃바운드 단계/범위에 대해 업데이트된 parent-id를 표시합니다. 자세한 내용은 추적 부모 필드 변경을 참조하세요.

사용자 지정 로거 만들기

사용자 지정 로거를 만들려면 .NET에서 사용자 지정 로깅 공급자 구현을 참조하세요.

추가 리소스

작성자: Kirk Larkin, Juergen GutschRick Anderson

이 항목에서는 ASP.NET Core 앱에 적용되는 .NET의 로깅에 대해 설명합니다. .NET의 로깅에 대한 자세한 내용은 .NET의 로깅을 참조하세요. Blazor 앱의 로깅에 대한 자세한 내용은 ASP.NET Core Blazor 로깅을 참조하세요.

예제 코드 살펴보기 및 다운로드 (다운로드 방법). 다운로드 예제는 영역을 테스트하기 위한 기초적인 앱을 제공합니다.

로깅 공급자

로그를 표시하는 Console 공급자를 제외하고 로깅 공급자는 로그를 저장합니다. 예를 들어 Azure Application Insights 공급자는 Azure Application Insights에 로그를 저장합니다. 여러 공급자를 사용하도록 설정할 수 있습니다.

기본 ASP.NET Core 웹앱 템플릿은 다음과 같습니다.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

위의 코드는 ASP.NET Core 웹앱 템플릿을 사용하여 만든 Program 클래스를 보여 줍니다. 다음 몇 개 섹션에서는 제네릭 호스트를 사용하는 ASP.NET Core 웹앱 템플릿을 기반으로 하는 샘플을 제공합니다. 비호스트 콘솔 앱은 문서의 뒷부분에 설명되어 있습니다.

Host.CreateDefaultBuilder로 추가된 로깅 공급자의 기본 세트를 재정의하려면 ClearProviders를 호출하고 필요한 로깅 공급자를 추가합니다. 예를 들어, 다음 코드는

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.AddConsole();
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

추가 공급자는 다음을 참조하세요.

로그 만들기

로그를 만들려면 DI(종속성 주입)ILogger<TCategoryName> 개체를 사용합니다.

다음 예제를 참조하세요.

  • 형식이 AboutModel인 정규화된 이름의 로그 ‘범주’를 사용하는 ILogger<AboutModel> 로거를 만듭니다. 로그 범주는 각 로그와 연결된 문자열입니다.
  • LogInformation을 호출하여 Information 수준에 로그합니다. 로그 수준은 기록된 이벤트의 심각도를 나타냅니다.
public class AboutModel : PageModel
{
    private readonly ILogger _logger;

    public AboutModel(ILogger<AboutModel> logger)
    {
        _logger = logger;
    }
    public string Message { get; set; }

    public void OnGet()
    {
        Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
        _logger.LogInformation(Message);
    }
}

수준범주는 이 문서의 뒷부분에 자세히 설명되어 있습니다.

Blazor에 대한 자세한 내용은 ASP.NET Core Blazor 로깅을 참조하세요.

Main 및 Startup에서 로그 만들기에서는 MainStartup에서 로그를 만드는 방법을 보여 줍니다.

로깅 구성

로깅 구성은 일반적으로 appsettings.{Environment}.json 파일의 Logging 섹션에서 제공됩니다. 다음 appsettings.Development.json 파일은 ASP.NET Core 웹앱 템플릿에서 생성됩니다.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

위의 JSON에서

  • "Default", "Microsoft""Microsoft.Hosting.Lifetime" 범주가 지정되었습니다.
  • "Microsoft" 범주는 "Microsoft"로 시작하는 모든 범주에 적용됩니다. 예를 들어 이 설정은 "Microsoft.AspNetCore.Routing.EndpointMiddleware" 범주에 적용됩니다.
  • "Microsoft" 범주는 로그 수준 Warning 이상에 로그됩니다.
  • "Microsoft.Hosting.Lifetime" 범주는 "Microsoft" 범주보다 구체적이므로 "Microsoft.Hosting.Lifetime" 범주는 로그 수준 “정보” 이상에 로그됩니다.
  • 특정 로그 공급자를 지정하지 않았으므로 LogLevelWindows EventLog를 제외하고 사용하도록 설정한 모든 로깅 공급자에 적용됩니다.

Logging 속성은 LogLevel 및 로그 공급자 속성을 포함할 수 있습니다. LogLevel 속성은 선택한 범주에 대해 로그할 최소 수준을 지정합니다. 위의 JSON에서는 InformationWarning 로그 수준을 지정했습니다. LogLevel 로그의 심각도를 나타내며 0에서 6 사이의 범위입니다.

Trace = 0, Debug = 1, Information = 2, Warning = 3, Error = 4, Critical = 5 및 None = 6

LogLevel을 지정하면 지정된 수준 이상의 메시지에 대해 로깅을 사용하도록 설정됩니다. 위의 JSON에서 Default 범주는 Information 이상에 대해 로그됩니다. 예를 들어 Information, Warning, ErrorCritical 메시지가 로그됩니다. LogLevel 지정하지 않으면 로깅은 Information 수준으로 기본 설정됩니다. 자세한 내용은 로그 수준을 참조하세요.

공급자 속성에서 LogLevel 속성을 지정할 수 있습니다. 공급자 아래의 LogLevel은 해당 공급자에 대해 로그할 수준을 지정하고 공급자 이외의 로그 설정을 재정의합니다. 다음 appsettings.json 파일을 살펴보세요.

{
  "Logging": {
    "LogLevel": { // All providers, LogLevel applies to all the enabled providers.
      "Default": "Error", // Default logging, Error and higher.
      "Microsoft": "Warning" // All Microsoft* categories, Warning and higher.
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information", // Overrides preceding LogLevel:Default setting.
        "Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.
      }
    },
    "EventSource": { // EventSource provider
      "LogLevel": {
        "Default": "Warning" // All categories of EventSource provider.
      }
    }
  }
}

Logging.{providername}.LogLevel의 설정은 Logging.LogLevel의 설정을 재정의합니다. 위의 JSON에서는 Debug 공급자의 기본 로그 수준이 Information으로 설정되었습니다.

Logging:Debug:LogLevel:Default:Information

위 설정은 Microsoft.Hosting을 제외하고 모든 Logging:Debug: 범주에 대해 Information 로그 수준을 지정합니다. 특정 범주를 나열하면 특정 범주로 기본 범주가 재정의됩니다. 위의 JSON에서 Logging:Debug:LogLevel 범주 "Microsoft.Hosting""Default"Logging:LogLevel의 설정을 재정의합니다.

최소 로그 수준은 다음에 대해 지정할 수 있습니다.

  • 특정 공급자: 예를 들면 Logging:EventSource:LogLevel:Default:Information과 같습니다.
  • 특정 범주: 예를 들어 Logging:LogLevel:Microsoft:Warning
  • 모든 공급자와 모든 범주: Logging:LogLevel:Default:Warning

최소 수준 이하의 모든 로그는 다음과 같이 되지 않습니다.

  • 공급자에 전달됩니다.
  • 로그되거나 표시됩니다.

모든 로그를 표시하지 않으려면 LogLevel.None을 지정합니다. LogLevel.None의 값은 LogLevel.Critical(5)보다 높은 6입니다.

공급자가 로그 범위를 지원하는 경우 IncludeScopes는 사용 가능 여부를 나타냅니다. 자세한 내용은 로그 범위를 참조하세요.

다음 appsettings.json 파일에는 기본적으로 사용하도록 설정되는 모든 공급자가 포함되어 있습니다.

{
  "Logging": {
    "LogLevel": { // No provider, LogLevel applies to all the enabled providers.
      "Default": "Error",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Warning"
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information" // Overrides preceding LogLevel:Default setting.
      }
    },
    "Console": {
      "IncludeScopes": true,
      "LogLevel": {
        "Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
        "Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
        "Microsoft.AspNetCore.Mvc.Razor": "Error",
        "Default": "Information"
      }
    },
    "EventSource": {
      "LogLevel": {
        "Microsoft": "Information"
      }
    },
    "EventLog": {
      "LogLevel": {
        "Microsoft": "Information"
      }
    },
    "AzureAppServicesFile": {
      "IncludeScopes": true,
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "AzureAppServicesBlob": {
      "IncludeScopes": true,
      "LogLevel": {
        "Microsoft": "Information"
      }
    },
    "ApplicationInsights": {
      "LogLevel": {
        "Default": "Information"
      }
    }
  }
}

앞의 예제에서:

  • 범주 및 수준은 제안된 값이 아닙니다. 기본 공급자를 모두 표시하기 위해 제공되는 샘플입니다.
  • Logging.{providername}.LogLevel의 설정은 Logging.LogLevel의 설정을 재정의합니다. 예를 들어 Debug.LogLevel.Default 수준은 LogLevel.Default수준을 재정의합니다.
  • 각 기본 공급자 ‘별칭’을 사용합니다. 각 공급자는 정규화된 형식 이름 대신 구성에서 사용할 수 있는 별칭을 정의합니다. 기본 제공 공급자 별칭은 다음과 같습니다.
    • 콘솔
    • 디버그
    • EventSource
    • EventLog
    • AzureAppServicesFile
    • AzureAppServicesBlob
    • ApplicationInsights

명령줄, 환경 변수 및 기타 구성으로 로그 수준 설정

로그 수준은 구성 공급자 중 하나로 설정할 수 있습니다.

: 구분 기호는 모든 플랫폼의 환경 변수 계층적 키에서 작동하지 않습니다. 이중 밑줄 __은 다음과 같습니다.

  • 모든 플랫폼에서 지원됩니다. 예를 들어 : 구분 기호는 Bash에서 지원되지 않지만 __은 지원됩니다.
  • 자동으로 :으로 대체

다음 명령은,

  • Windows에서 환경 키 Logging:LogLevel:MicrosoftInformation 값으로 설정합니다.
  • ASP.NET Core 웹 애플리케이션 템플릿을 사용하여 만든 앱을 사용할 때 설정을 테스트합니다. dotnet run 명령은 set을 사용한 후 프로젝트 디렉터리에서 실행해야 합니다.
set Logging__LogLevel__Microsoft=Information
dotnet run

위의 환경 설정은,

  • 설정된 명령 창에서 시작된 프로세스에서만 설정됩니다.
  • Visual Studio에서 시작된 브라우저에서는 읽을 수 없습니다.

다음 setx 명령은 Windows에서 환경 키 및 값도 설정합니다. set와 달리, setx 설정은 유지됩니다. /M 스위치는 시스템 환경에서 변수를 설정합니다. /M을 사용하지 않으면 사용자 환경 변수가 설정됩니다.

setx Logging__LogLevel__Microsoft Information /M

다음 appsettings.json 파일을 살펴보세요.

"Logging": {
    "Console": {
      "LogLevel": {
        "Microsoft.Hosting.Lifetime": "Trace"
      }
    }
}

다음 명령은 환경에서 위의 구성을 설정합니다.

setx Logging__Console__LogLevel__Microsoft.Hosting.Lifetime Trace /M

Azure App Service설정 > 구성 페이지에서 새 애플리케이션 설정을 선택합니다. Azure App Service 애플리케이션 설정은,

  • 미사용 시 암호화되고 암호화된 채널을 통해 전송됩니다.
  • 환경 변수로 노출됩니다.

자세한 내용은 Azure 앱: Azure Portal을 사용하여 앱 구성 재정의를 참조하세요.

환경 변수를 사용하여 ASP.NET Core 구성 값을 설정하는 방법에 대한 자세한 내용은 환경 변수를 참조하세요. 명령줄, Azure Key Vault, Azure App Configuration, 기타 파일 형식 등을 포함하여 다른 구성 원본을 사용하는 방법에 대한 자세한 내용은 ASP.NET Core의 구성을 참조하세요.

필터링 규칙 적용 방식

ILogger<TCategoryName> 개체를 만들 때 ILoggerFactory 개체는 공급자마다 해당 로거에 적용할 단일 규칙을 선택합니다. ILogger 인스턴스에서 작성된 모든 메시지는 선택한 규칙에 따라 필터링됩니다. 사용 가능한 규칙 중에서 각 공급자 및 범주 쌍과 가장 관련이 많은 규칙이 선택됩니다.

지정된 범주에 대한 ILogger가 생성되면 다음 알고리즘이 각 공급자에 사용됩니다.

  • 공급자 또는 공급자의 별칭과 일치하는 모든 규칙을 선택합니다. 일치하는 규칙이 없는 경우 빈 공급자가 있는 모든 규칙을 선택합니다.
  • 앞 단계의 결과에서 일치하는 범주 접두사가 가장 긴 규칙을 선택합니다. 일치하는 규칙이 없는 경우 범주를 지정하지 않는 규칙을 모두 선택합니다.
  • 여러 규칙을 선택하는 경우 마지막 규칙을 사용합니다.
  • 규칙을 선택하지 않는 경우 MinimumLevel을 사용합니다.

dotnet run 및 Visual Studio의 로깅 출력

기본 로깅 공급자를 사용하여 만든 로그는 다음과 같이 표시됩니다.

  • Visual Studio에서
    • 디버그할 때 디버그 출력 창에 표시됨
    • ASP.NET Core 웹 서버 창에 표시됨
  • dotnet run을 사용하여 앱을 실행할 때 콘솔 창에 표시됨

“Microsoft” 범주로 시작하는 로그는 ASP.NET Core 프레임워크 코드에서 온 것입니다. ASP.NET Core 및 애플리케이션 코드는 동일한 로깅 API와 공급자를 사용합니다.

로그 범주

ILogger 개체가 생성되면 ‘범주’가 지정됩니다. 해당 범주는 ILogger의 해당 인스턴스에서 만든 각 로그 메시지에 포함됩니다. 범주 문자열은 임의로 지정되지만 규칙은 클래스 이름을 사용하는 것입니다. 예를 들어 컨트롤러에서 이름은 "TodoApi.Controllers.TodoController"일 수 있습니다. ASP.NET Core 웹앱은 ILogger<T>를 사용하여 T의 정규화된 형식 이름을 범주로 사용하는 ILogger 인스턴스를 자동으로 가져옵니다.

public class PrivacyModel : PageModel
{
    private readonly ILogger<PrivacyModel> _logger;

    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.PrivacyModel called.");
    }
}

범주를 명시적으로 지정하려면 ILoggerFactory.CreateLogger를 호출합니다.

public class ContactModel : PageModel
{
    private readonly ILogger _logger;

    public ContactModel(ILoggerFactory logger)
    {
        _logger = logger.CreateLogger("TodoApi.Pages.ContactModel.MyCategory");
    }

    public void OnGet()
    {
        _logger.LogInformation("GET Pages.ContactModel called.");
    }

고정 이름을 사용하여 CreateLogger를 호출하면 여러 메서드에서 사용할 때 유용할 수 있으므로 이벤트를 범주별로 구성할 수 있습니다.

ILogger<T>T의 정규화된 형식 이름으로 CreateLogger를 호출하는 것과 동일합니다.

로그 수준

다음 표에서는 LogLevel 값, 편리한 Log{LogLevel} 확장 메서드 및 추천 사용법을 설명합니다.

LogLevel 메서드 설명
Trace 0 LogTrace 가장 자세한 메시지를 포함합니다. 해당 메시지는 중요한 앱 데이터를 포함할 수 있습니다. 해당 메시지는 기본적으로 사용하지 않도록 설정되며 프로덕션에서 사용하도록 설정하면 안 됩니다.
디버그 1 LogDebug 디버깅 및 개발을 위한 수준입니다. 너무 많으므로 프로덕션에서는 주의해서 사용합니다.
정보 2 LogInformation 앱의 일반적인 흐름을 추적합니다. 장기적인 값이 있을 수 있습니다.
경고 3 LogWarning 비정상적이거나 예기치 않은 이벤트를 위한 수준입니다. 일반적으로 앱의 오류를 발생시키지 않는 오류 또는 조건을 포함합니다.
오류 4 LogError 처리할 수 없는 오류 및 예외입니다. 해당 메시지는 전체 앱 오류가 아닌 현재 작업 또는 요청의 오류를 의미합니다.
위험 5 LogCritical 즉각적인 대응이 필요한 오류를 위한 수준입니다. 예: 데이터 손실 시나리오, 디스크 공간 부족.
없음 6 로깅 범주에서 메시지를 쓰지 않도록 지정합니다.

위의 표에서는 LogLevel이 심각도가 낮은 것에서 높은 것 순으로 표시됩니다.

Log 메서드의 첫 번째 매개 변수인 LogLevel은 로그의 심각도를 나타냅니다. 대부분의 개발자는 Log(LogLevel, ...) 대신 Log{LogLevel} 확장 메서드를 호출합니다. Log{LogLevel} 확장 메서드는 Log 메서드를 호출하고 LogLevel을 지정합니다. 예를 들어 다음 두 로깅 호출은 기능이 동일하며 같은 로그를 생성합니다.

[HttpGet]
public IActionResult Test1(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);

    _logger.Log(LogLevel.Information, MyLogEvents.TestItem, routeInfo);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    return ControllerContext.MyDisplayRouteInfo();
}

MyLogEvents.TestItem은 이벤트 ID입니다. MyLogEvents는 샘플 앱의 일부이며 로그 이벤트 ID 섹션에 표시됩니다.

MyDisplayRouteInfo 및 ToCtxStringRick.Docs.Samples.RouteInfo NuGet 패키지가 제공합니다. 이 메서드는 ControllerRazor Page 경로 정보를 표시합니다.

다음 코드는 InformationWarning 로그를 만듭니다.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

위의 코드에서 첫 번째 Log{LogLevel} 매개 변수 MyLogEvents.GetItem로그 이벤트 ID입니다. 두 번째 매개 변수는 나머지 메서드 매개 변수가 제공하는 인수 값에 대한 자리 표시자를 포함하고 있는 메시지 템플릿입니다. 메서드 매개 변수는 이 문서의 뒷부분에 있는 메시지 템플릿 섹션에 설명되어 있습니다.

적절한 Log{LogLevel} 메서드를 호출하여 특정 스토리지 매체에 기록되는 로그 출력의 양을 제어합니다. 예시:

  • 프로덕션:
    • Trace 또는 Information 수준 로깅은 자세한 로그 메시지를 대량으로 생성합니다. 비용을 관리하고 데이터 스토리지 제한을 초과하지 않으려면 TraceInformation 수준 메시지를 대용량, 저비용 데이터 저장소에 로그합니다. TraceInformation을 특정 범주로 제한하는 것이 좋습니다.
    • Warning~Critical 수준의 로깅은 적은 로그 메시지를 생성합니다.
      • 비용과 스토리지 제한이 일반적으로 문제가 되지 않습니다.
      • 로그가 적으므로 데이터 저장소를 더 유연하게 선택할 수 있습니다.
  • 개발 중:
    • Warning로 설정합니다.
    • 문제를 해결할 때는 Trace 또는 Information 메시지를 추가합니다. 출력을 제한하려면 조사 중인 범주에 대해서만 Trace 또는 Information을 설정합니다.

ASP.NET Core는 프레임워크 이벤트에 대한 로그를 작성합니다. 예를 들어 다음의 로그 출력을 고려하세요.

  • ASP.NET Core 템플릿을 사용하여 만든 Razor Pages 앱
  • 로깅을 Logging:Console:LogLevel:Microsoft:Information으로 설정
  • Privacy 페이지 탐색:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 GET https://localhost:5001/Privacy
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint '/Privacy'
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
      Route matched with {page = "/Privacy"}. Executing page /Privacy
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[101]
      Executing handler method DefaultRP.Pages.PrivacyModel.OnGet - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[102]
      Executed handler method OnGet, returned result .
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
      Executing an implicit handler method - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
      Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
      Executed page /Privacy in 74.5188ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint '/Privacy'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 149.3023ms 200 text/html; charset=utf-8

다음 JSON은 Logging:Console:LogLevel:Microsoft:Information을 설정합니다.

{
  "Logging": {      // Default, all providers.
    "LogLevel": {
      "Microsoft": "Warning"
    },
    "Console": { // Console provider.
      "LogLevel": {
        "Microsoft": "Information"
      }
    }
  }
}

로그 이벤트 ID

각 로그는 이벤트 ID를 지정할 수 있습니다. 샘플 앱에서는 MyLogEvents 클래스를 사용하여 이벤트 ID를 정의합니다.

public class MyLogEvents
{
    public const int GenerateItems = 1000;
    public const int ListItems     = 1001;
    public const int GetItem       = 1002;
    public const int InsertItem    = 1003;
    public const int UpdateItem    = 1004;
    public const int DeleteItem    = 1005;

    public const int TestItem      = 3000;

    public const int GetItemNotFound    = 4000;
    public const int UpdateItemNotFound = 4001;
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

이벤트 ID는 이벤트 집합을 연결합니다. 예를 들어 페이지에서 항목 목록을 표시하는 것과 관련된 모든 로그는 1001일 수 있습니다.

로깅 공급자는 이벤트 ID를 ID 필드, 로그 메시지에 저장하거나 또는 전혀 저장하지 않을 수도 있습니다. 디버그 공급자는 이벤트 ID를 표시하지 않습니다. 콘솔 공급자는 범주 뒤에 대괄호로 이벤트 ID를 표시합니다.

info: TodoApi.Controllers.TodoItemsController[1002]
      Getting item 1
warn: TodoApi.Controllers.TodoItemsController[4000]
      Get(1) NOT FOUND

일부 로깅 공급자는 ID에 대한 필터링을 허용하는 필드에 이벤트 ID를 저장합니다.

로그 메시지 템플릿

각 로그 API는 메시지 템플릿을 사용합니다. 메시지 템플릿에는 인수가 제공되는 자리 표시자를 포함할 수 있습니다. 번호가 아닌 자리 표시자의 이름을 사용합니다.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
        return NotFound();
    }

    return ItemToDTO(todoItem);
}

해당 자리 표시자 이름이 아니라 매개 변수의 순서가 로그 메시지에 자리 표시자 값을 제공하는 데 사용되는 매개 변수를 결정합니다. 다음 코드에서는 매개 변수 이름의 순서가 메시지 템플릿 내 자리 표시자의 순서와 일치하지 않습니다.

var apples = 1;
var pears = 2;
var bananas = 3;

_logger.LogInformation("Parameters: {pears}, {bananas}, {apples}", apples, pears, bananas);

그러나 매개 변수는 apples, pears, bananas의 순서로 자리 표시자에 할당됩니다. 로그 메시지는 매개 변수의 순서를 반영합니다.

Parameters: 1, 2, 3

해당 접근 방식을 통해 로깅 공급자는 의미 체계 또는 구조적 로깅를 구현할 수 있습니다. 인수 자체는 서식이 지정된 메시지 템플릿뿐만 아니라 로깅 시스템에 전달됩니다. 따라서 로깅 공급자는 매개 변수 값을 필드로 저장할 수 있습니다. 예를 들어 다음 로거 메서드를 살펴보세요.

_logger.LogInformation("Getting item {Id} at {RequestTime}", id, DateTime.Now);

Azure Table Storage에 로그할 경우를 예로 듭니다.

  • 각 Azure Table 엔터티에는 IDRequestTime 속성이 있을 수 있습니다.
  • 속성이 있는 테이블은 로그된 데이터의 쿼리를 쉽게 합니다. 예를 들어 문자 메시지의 시간 초과를 구문 분석하지 않고도 특정 RequestTime 범위 내에 있는 모든 로그를 쿼리를 통해 찾을 수 있습니다.

예외 기록

로거 메서드에는 예외 매개 변수를 사용하는 오버로드가 있습니다.

[HttpGet("{id}")]
public IActionResult TestExp(int id)
{
    var routeInfo = ControllerContext.ToCtxString(id);
    _logger.LogInformation(MyLogEvents.TestItem, routeInfo);

    try
    {
        if (id == 3)
        {
            throw new Exception("Test exception");
        }
    }
    catch (Exception ex)
    {
        _logger.LogWarning(MyLogEvents.GetItemNotFound, ex, "TestExp({Id})", id);
        return NotFound();
    }

    return ControllerContext.MyDisplayRouteInfo();
}

MyDisplayRouteInfo 및 ToCtxStringRick.Docs.Samples.RouteInfo NuGet 패키지가 제공합니다. 이 메서드는 ControllerRazor Page 경로 정보를 표시합니다.

예외 로깅은 공급자별로 다릅니다.

기본 로그 수준

기본 로그 수준을 설정하지 않으면 기본 로그 수준 값은 Information입니다.

예를 들어 다음 웹앱을 고려하세요.

  • ASP.NET 웹앱 템플릿을 사용하여 만들었습니다.
  • appsettings.jsonappsettings.Development.json이 삭제되었거나 이름이 변경되었습니다.

이전 설정을 사용하여 개인정보처리방침이나 홈페이지로 이동하면 범주 이름에 Microsoft가 포함된 Trace, DebugInformation 메시지가 많이 생성됩니다.

다음 코드에서는 구성에 기본 로그 수준이 설정되어 있지 않은 경우 기본 로그 수준을 설정합니다.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Warning))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

일반적으로 로그 수준은 코드에서가 아니라 구성에서 지정해야 합니다.

필터 함수

필터 함수는 구성 또는 코드를 통해 규칙이 할당되지 않은 모든 공급자와 범주에 대해 호출됩니다.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging =>
            {
                logging.AddFilter((provider, category, logLevel) =>
                {
                    if (provider.Contains("ConsoleLoggerProvider")
                        && category.Contains("Controller")
                        && logLevel >= LogLevel.Information)
                    {
                        return true;
                    }
                    else if (provider.Contains("ConsoleLoggerProvider")
                        && category.Contains("Microsoft")
                        && logLevel >= LogLevel.Information)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                });
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

앞의 코드는 범주에 Controller 또는 Microsoft가 포함되어 있고 로그 수준이 Information 이상인 경우 콘솔 로그를 표시합니다.

일반적으로 로그 수준은 코드에서가 아니라 구성에서 지정해야 합니다.

ASP.NET Core 및 EF Core 범주

다음 표에는 ASP.NET Core 및 Entity Framework Core에서 사용되는 몇 가지 범주와 로그에 관한 참고 사항이 나와 있습니다.

범주 주의
Microsoft.AspNetCore 일반 ASP.NET Core 진단.
Microsoft.AspNetCore.DataProtection 고려되고, 발견되고, 사용된 키.
Microsoft.AspNetCore.HostFiltering 허용되는 호스트.
Microsoft.AspNetCore.Hosting HTTP 요청을 완료하는 데 걸린 시간과 시작 시간. 로드된 호스팅 시작 어셈블리.
Microsoft.AspNetCore.Mvc MVC 및 Razor 진단. 모델 바인딩, 필터 실행, 뷰 컴파일 작업 선택.
Microsoft.AspNetCore.Routing 경로 일치 정보.
Microsoft.AspNetCore.Server 연결 시작, 중지 및 활성 응답 유지. HTTPS 인증서 정보.
Microsoft.AspNetCore.StaticFiles 제공된 파일.
Microsoft.EntityFrameworkCore 일반 Entity Framework Core 진단. 데이터베이스 작업 및 구성, 변경 내용 검색, 마이그레이션.

콘솔 창에서 더 많은 범주를 보려면 appsettings.Development.json을 다음으로 설정합니다.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Trace",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

로그 점수

범위는 논리적 작업 집합을 그룹화할 수 있습니다. 이 그룹화는 집합의 일부로 생성된 각 로그에 동일한 데이터를 연결하는 데 사용될 수 있습니다. 예를 들어 트랜잭션 처리의 일부로 생성되는 모든 로그에는 트랜잭션 ID가 포함될 수 있습니다.

범위:

  • BeginScope 메서드에서 반환하는 IDisposable 형식입니다.
  • 삭제될 때까지 유지됩니다.

범위를 지원하는 공급자는 다음과 같습니다.

using 블록에 로거 호출을 래핑하여 범위를 사용합니다.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    TodoItem todoItem;
    var transactionId = Guid.NewGuid().ToString();
    using (_logger.BeginScope(new List<KeyValuePair<string, object>>
        {
            new KeyValuePair<string, object>("TransactionId", transactionId),
        }))
    {
        _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);

        todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            _logger.LogWarning(MyLogEvents.GetItemNotFound, 
                "Get({Id}) NOT FOUND", id);
            return NotFound();
        }
    }

    return ItemToDTO(todoItem);
}

기본 제공 로깅 공급자

ASP.NET Core에는 공유 프레임워크의 일부로 다음과 같은 로깅 공급자가 포함되어 있습니다.

다음 로깅 공급자는 Microsoft에서 제공하지만 공유 프레임워크의 일부로 제공하는 것은 아닙니다. 추가 NuGet으로 설치해야 합니다.

ASP.NET Core에는 파일에 로그를 기록하기 위한 로깅 공급자가 포함되지 않습니다. ASP.NET Core 앱에서 파일에 로그를 쓰려면 타사 로깅 공급자를 사용하는 것이 좋습니다.

ASP.NET Core 모듈을 사용한 stdout 및 디버그 로깅에 대한 자세한 내용은 Azure App Service 및 IIS에서 ASP.NET Core 문제 해결IIS용 ANCM(ASP.NET Core 모듈)을 참조하세요.

콘솔

Console 공급자는 콘솔에 출력을 로그합니다. 개발 중인 Console 로그를 보는 방법에 대한 자세한 내용은 dotnet run 및 Visual Studio의 로깅 출력을 참조하세요.

디버그

Debug 공급자는 System.Diagnostics.Debug 클래스를 사용하여 로그 출력을 기록합니다. System.Diagnostics.Debug.WriteLine을 호출하여 Debug 공급자에 기록합니다.

Linux에서 Debug 공급자 로그 위치는 배포판마다 다르며 다음 중 하나일 수 있습니다.

  • /var/log/message
  • /var/log/syslog

이벤트 원본

EventSource 공급자는 이름이 Microsoft-Extensions-Logging인 플랫폼 간 이벤트 원본에 기록합니다. Windows에서 공급자는 ETW를 사용합니다.

dotnet 추적 도구

dotnet 추적 도구는 실행 중인 프로세스의 .NET Core 추적을 수집할 수 있도록 하는 플랫폼 간 CLI 전역 도구입니다. 이 도구는 LoggingEventSource를 사용하여 Microsoft.Extensions.Logging.EventSource 공급자 데이터를 수집합니다.

설치 지침은 dotnet-trace를 참조하세요.

Dotnet 추적 도구를 사용하여 앱에서 추적을 수집합니다.

  1. dotnet run 명령으로 앱을 실행합니다.

  2. .NET Core 앱의 PID(프로세스 식별자)를 확인합니다.

    dotnet trace ps
    

    앱의 어셈블리와 동일한 이름의 프로세스에 대한 PID를 찾습니다.

  3. dotnet trace 명령을 실행합니다.

    일반 명령 구문:

    dotnet trace collect -p {PID} 
        --providers Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"
    

    PowerShell 명령 셸을 사용하는 경우 --providers 값을 작은따옴표(')로 묶습니다.

    dotnet trace collect -p {PID} 
        --providers 'Microsoft-Extensions-Logging:{Keyword}:{Provider Level}
            :FilterSpecs=\"
                {Logger Category 1}:{Category Level 1};
                {Logger Category 2}:{Category Level 2};
                ...
                {Logger Category N}:{Category Level N}\"'
    

    Windows가 아닌 플랫폼에서는 출력 추적 파일의 형식을 speedscope로 변경하는 -f speedscope 옵션을 추가합니다.

    다음 표에서는 키워드를 정의합니다.

    키워드 설명
    1 LoggingEventSource에 대한 로그 메타 이벤트입니다. ILogger에서 이벤트를 로깅하지 않습니다.
    2 ILogger.Log()가 호출될 때 Message 이벤트 설정을 켭니다. 서식 지정되지 않은 프로그래밍 방식으로 정보를 제공합니다.
    4 ILogger.Log()가 호출될 때 FormatMessage 이벤트 설정을 켭니다. 서식 지정된 문자열 버전의 정보를 제공합니다.
    8 ILogger.Log()가 호출될 때 MessageJson 이벤트 설정을 켭니다. 인수의 JSON 표현을 제공합니다.

    다음 표에는 공급자 수준이 나열되어 있습니다.

    공급자 수준 설명
    0 LogAlways
    1 Critical
    2 Error
    3 Warning
    4 Informational
    5 Verbose

    범주 수준에 대한 구문 분석은 문자열 또는 숫자일 수 있습니다.

    범주 명명된 값 숫자 값
    Trace 0
    Debug 1
    Information 2
    Warning 3
    Error 4
    Critical 5

    공급자 수준 및 범주 수준:

    • 역순입니다.
    • 문자열 상수가 모두 동일하지는 않습니다.

    FilterSpecs를 지정하지 않을 경우 EventSourceLogger 구현이 공급자 수준을 범주 수준으로 변환하고 모든 범주에 적용합니다.

    공급자 수준 범주 수준
    Verbose(5) Debug(1)
    Informational(4) Information(2)
    Warning(3) Warning(3)
    Error(2) Error(4)
    Critical(1) Critical(5)

    FilterSpecs를 제공하는 경우 목록에 포함된 모든 범주가 인코딩된 범주 수준을 사용합니다. 다른 모든 범주는 필터링됩니다.

    다음 예제에서는 다음과 같이 가정합니다.

    • 앱이 실행 중이고 logger.LogDebug("12345")를 호출합니다.
    • PID(프로세스 ID)가 set PID=12345를 통해 설정되었습니다. 여기서 12345는 실제 PID입니다.

    다음 명령을 생각해 볼 수 있습니다.

    dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5
    

    이전 명령:

    • 디버그 메시지를 캡처합니다.
    • FilterSpecs를 적용하지 않습니다.
    • 범주 디버그를 매핑하는 수준 5를 지정합니다.

    다음 명령을 생각해 볼 수 있습니다.

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:5\"
    

    이전 명령:

    • 디버그 메시지를 캡처하지 않습니다. 범주 수준 5가 Critical이기 때문입니다.
    • FilterSpecs를 제공합니다.

    다음 명령은 디버그 메시지를 캡처합니다. 범주 수준 1이 Debug이기 때문입니다.

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:1\"
    

    다음 명령은 디버그 메시지를 캡처합니다. 범주가 Debug를 지정하기 때문입니다.

    dotnet trace collect -p %PID%  --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:Debug\"
    

    FilterSpecs{Logger Category}{Category Level}에 대한 항목은 추가 로그 필터링 조건을 나타냅니다. ; 세미콜론 문자를 사용하여 FilterSpecs 항목을 구분합니다.

    Windows 명령 셸을 사용하는 예제:

    dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:2:FilterSpecs=\"Microsoft.AspNetCore.Hosting*:4\"
    

    이전 명령은 다음과 같이 활성화됩니다.

    • (2) 오류에 대해 형식이 지정된 문자열(4)을 생성하는 이벤트 원본 로거입니다.
    • Informational 로깅 수준에서 Microsoft.AspNetCore.Hosting 로깅(4).
  4. Enter 키 또는 Ctrl + C를 눌러 dotnet 추적 도구를 중지합니다.

    추적은 dotnet trace 명령이 실행되는 폴더에 trace.nettrace 이름으로 저장됩니다.

  5. Perfview를 사용하여 추적을 엽니다. trace.nettrace 파일을 열고 추적 이벤트를 탐색합니다.

앱이 호스트 CreateDefaultBuilder를 빌드하지 않는 경우 이벤트 원본 공급자를 앱의 로깅 구성에 추가합니다.

자세한 내용은 다음을 참조하세요.

Perfview

PerfView 유틸리티를 사용하여 로그를 수집하고 볼 수 있습니다. ETW 로그를 보는 다른 도구도 있지만, PerfView는 ASP.NET Core에서 내보내는 ETW 이벤트를 처리하기에 가장 좋은 환경을 제공합니다.

이 공급자가 기록한 이벤트를 수집하도록 PerfView를 구성하려면 추가 공급자 목록에 *Microsoft-Extensions-Logging 문자열을 추가합니다. 문자열의 시작 부분에 *를 누락하지 마세요.

Windows EventLog

EventLog 공급자는 로그 출력을 Windows 이벤트 로그에 보냅니다. 다른 공급자와 달리 EventLog 공급자는 기본 비공급자 설정을 상속하지 않습니다. EventLog 로그 설정을 지정하지 않으면 LogLevel.Warning으로 기본 설정됩니다.

LogLevel.Warning 수준보다 낮은 이벤트를 기록하려면 로그 수준을 명시적으로 설정합니다. 다음 예제에서는 이벤트 로그 기본 로그 수준을 LogLevel.Information으로 설정합니다.

"Logging": {
  "EventLog": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

AddEventLog 오버로드EventLogSettings를 전달할 수 있습니다. null이거나 지정하지 않으면 다음 기본 설정이 사용됩니다.

  • LogName: "Application"
  • SourceName: “.NET Runtime”
  • MachineName: 로컬 컴퓨터 이름이 사용됩니다.

다음 코드에서는 SourceName을 기본값 ".NET Runtime"에서 MyLogs로 변경합니다.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging =>
            {
                logging.AddEventLog(eventLogSettings =>
                {
                    eventLogSettings.SourceName = "MyLogs"; 
                });
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Azure App Service

Microsoft.Extensions.Logging.AzureAppServices 공급자 패키지는 Azure App Service 앱의 파일 시스템과 Azure Storage 계정의 Blob 스토리지에 텍스트 파일을 기록합니다.

이 공급자 패키지는 공유 프레임워크에 포함되어 있지 않습니다. 이 공급자를 사용하려면 프로젝트에 공급자 패키지를 추가합니다.

공급자 설정을 구성하려면 다음 예제와 같이 AzureFileLoggerOptionsAzureBlobLoggerOptions를 사용합니다.

public class Scopes
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureLogging(logging => logging.AddAzureWebAppDiagnostics())
                .ConfigureServices(serviceCollection => serviceCollection
                    .Configure<AzureFileLoggerOptions>(options =>
                    {
                        options.FileName = "azure-diagnostics-";
                        options.FileSizeLimit = 50 * 1024;
                        options.RetainedFileCountLimit = 5;
                    })
                    .Configure<AzureBlobLoggerOptions>(options =>
                    {
                        options.BlobName = "log.txt";
                    }))
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Azure App Service에 배포하는 경우 앱은 Azure Portal에서 App Service 페이지에 있는 App Service 로그 섹션의 설정을 사용합니다. 다음 설정이 업데이트되면 앱을 다시 시작하거나 재배포하지 않아도 변경 내용이 즉시 적용됩니다.

  • 애플리케이션 로깅(파일 시스템)
  • 애플리케이션 로깅(Blob)

로그 파일의 기본 위치는 D:\home\LogFiles\Application 폴더이고, 기본 파일 이름은 diagnostics-yyyymmdd.txt입니다. 기본 파일 크기 제한은 10MB이고, 보존되는 기본 최대 파일 수는 2입니다. 기본 BLOB 이름은 {app-name}{timestamp}/yyyy/mm/dd/hh/{guid}-applicationLog.txt입니다.

이 공급자는 프로젝트가 Azure 환경에서 실행되는 경우에만 로그합니다.

Azure 로그 스트리밍

Azure 로그 스트리밍을 통해 다음에서 로그 활동을 실시간으로 볼 수 있습니다.

  • 앱 서버
  • 웹 서버
  • 실패한 요청 추적

Azure 로그 스트리밍을 구성하려면:

  • 앱의 포털 페이지에서 App Service 로그 페이지로 이동합니다.
  • 애플리케이션 로깅(파일 시스템)On으로 설정합니다.
  • 로그 수준을 선택합니다. 이 설정은 Azure 로그 스트리밍에만 적용됩니다.

로그 스트림 페이지로 이동하여 로그를 봅니다. 로드되는 메시지는 ILogger 인터페이스를 사용하여 로그됩니다.

Azure Application Insights

Microsoft.Extensions.Logging.ApplicationInsights 공급자 패키지는 Azure Application Insights에 로그를 기록합니다. Application Insights는 웹앱을 모니터링하고 원격 분석 데이터를 쿼리 및 분석하기 위한 도구를 제공하는 서비스입니다. 이 공급자를 사용하는 경우 Application Insights 도구를 사용하여 로그를 쿼리 및 분석할 수 있습니다.

로깅 공급자는 ASP.NET Core에 대한 모든 사용 가능한 원격 분석을 제공하는 패키지인 Microsoft.ApplicationInsights.AspNetCore의 종속성으로 포함됩니다. 이 패키지를 사용하는 경우 공급자 패키지를 설치할 필요가 없습니다.

Microsoft.ApplicationInsights.Web 패키지는 ASP.NET Core가 아니라 ASP.NET 4.x용입니다.

자세한 내용은 다음 리소스를 참조하세요.

타사 로깅 공급자

ASP.NET Core와 호환되는 타사 로깅 프레임워크는 다음과 같습니다.

일부 타사 프레임워크는 구조적 로깅이라고 하는 의미 체계 로깅을 수행할 수 있습니다.

타사 프레임워크를 사용하는 방법은 다음과 같이 기본 공급자 중 하나를 사용하는 방법과 비슷합니다.

  1. 프로젝트에 NuGet 패키지를 추가합니다.
  2. 로깅 프레임워크에서 제공하는 ILoggerFactory 확장 메서드를 호출합니다.

자세한 내용은 각 공급자의 설명서를 참조하세요. 타사 로깅 공급자는 Microsoft에서 지원되지 않습니다.

비호스트 콘솔 앱

비 웹 콘솔 앱에서 제네릭 호스트를 사용하는 방법에 대한 예제는 백그라운드 작업 샘플 앱(ASP.NET Core에서 호스팅된 서비스를 사용하는 백그라운드 작업)의 Program.cs 파일을 참조하세요.

제네릭 호스트가 없는 앱에 대한 로깅 코드는 공급자를 추가하고 로거를 만드는 방식에 따라 다릅니다.

로깅 공급자

비 호스트 콘솔 앱에서는 LoggerFactory를 만드는 동안 공급자의 Add{provider name} 확장 메서드를 호출합니다.

class Program
{
    static void Main(string[] args)
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole()
                .AddEventLog();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
    }
}

로그 만들기

로그를 만들려면 ILogger<TCategoryName> 개체를 사용합니다. LoggerFactory를 사용하여 ILogger를 만듭니다.

다음 예제에서는 LoggingConsoleApp.Program을 범주로 사용하여 로거를 만듭니다.

class Program
{
    static void Main(string[] args)
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole()
                .AddEventLog();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
    }
}

다음 예제에서 로거는 Information 수준에서 로그를 만드는 데 사용됩니다. 로그 수준은 기록된 이벤트의 심각도를 나타냅니다.

class Program
{
    static void Main(string[] args)
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole()
                .AddEventLog();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
    }
}

수준범주는 이 문서에 자세히 설명되어 있습니다.

호스트 생성 중 로깅

호스트 생성 중 로깅은 직접 지원되지 않습니다. 그러나 별도의 로거를 사용할 수 있습니다. 다음 예에서는 Serilog 로거를 사용하여 CreateHostBuilder에 로그인합니다. AddSerilog에서 Log.Logger에 지정된 정적 구성을 사용합니다.

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var builtConfig = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddCommandLine(args)
            .Build();

        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .WriteTo.File(builtConfig["Logging:FilePath"])
            .CreateLogger();

        try
        {
            return Host.CreateDefaultBuilder(args)
                .ConfigureServices((context, services) =>
                {
                    services.AddRazorPages();
                })
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddConfiguration(builtConfig);
                })
                .ConfigureLogging(logging =>
                {   
                    logging.AddSerilog();
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host builder error");

            throw;
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }
}

ILogger에 종속되는 서비스 구성

이전 버전의 ASP.NET Core에서는 Startup에 대한 로거의 생성자 주입이 작동하는데, 이는 웹 호스트에 대한 별도의 DI 컨테이너가 생성되기 때문입니다. 제네릭 호스트에 대해 하나의 컨테이너만 생성되는 이유에 대한 자세한 내용은 호환성이 손상되는 변경 공지를 참조하세요.

ILogger<T>에 종속되는 서비스를 구성하려면 생성자 주입을 사용하거나 팩터리 메서드를 제공합니다. 팩터리 메서드 접근 방식은 다른 옵션이 없는 경우에만 권장됩니다. 예를 들어 DI에서 제공하는 ILogger<T> 인스턴스가 필요한 서비스를 살펴보겠습니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddRazorPages();

    services.AddSingleton<IMyService>((container) =>
    {
        var logger = container.GetRequiredService<ILogger<MyService>>();
        return new MyService() { Logger = logger };
    });
}

위에 강조 표시된 코드 Func<T,TResult>는 DI 컨테이너가 MyService의 인스턴스를 처음 생성해야 할 때 실행됩니다. 이러한 방식으로 등록된 서비스에 액세스할 수 있습니다.

Main에서 로그 만들기

다음 코드는 호스트를 빌드한 후 DI에서 ILogger 인스턴스를 가져와 Main에 로그합니다.

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    var logger = host.Services.GetRequiredService<ILogger<Program>>();
    logger.LogInformation("Host created.");

    host.Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

시작 시 로그 만들기

다음 코드는 Startup.Configure에 로그를 작성합니다.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
                      ILogger<Startup> logger)
{
    if (env.IsDevelopment())
    {
        logger.LogInformation("In Development.");
        app.UseDeveloperExceptionPage();
    }
    else
    {
        logger.LogInformation("Not Development.");
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    });
}

Startup.ConfigureServices 메서드에서 DI 컨테이너 설정이 완료되기 전에 로그를 작성하는 작업은 지원되지 않습니다.

  • Startup 생성자에 대한 로거 주입은 지원되지 않습니다.
  • Startup.ConfigureServices 메서드 시그니처에 대한 로거 주입은 지원되지 않습니다.

이러한 제한의 이유는 로깅이 DI와 구성에 종속되며, 이는 결국 DI에 종속되기 때문입니다. DI 컨테이너는 ConfigureServices가 완료될 때까지 설정되지 않습니다.

ILogger<T>에 종속되는 서비스를 구성하는 방법이나 Startup로 로거의 생성자 주입이 이전 버전에서 작동한 이유에 대한 자세한 내용은 ILogger에 종속되는 서비스 구성을 참조하세요.

비동기 로거 메서드 미지원

로깅은 매우 빨라서 비동기 코드의 성능 비용을 들일 필요가 없습니다. 로깅 데이터 저장소가 느린 경우 직접 작성하지 마세요. 로그 메시지를 처음에 빠른 저장소에 작성한 다음, 나중에 느린 저장소로 이동하는 것이 좋습니다. 예를 들어 SQL Server에 로그하는 경우 Log 메서드는 동기식이므로 Log 메서드에서 직접 로그하지 마세요. 대신 동기적으로 로그 메시지를 메모리 내 큐에 추가하고 백그라운드 작업자가 큐에서 메시지를 풀하여 SQL Server에 대해 비동기 데이터 푸시 작업을 수행하도록 합니다. 자세한 내용은 해당 GitHub 이슈를 참조하세요.

실행 중인 앱에서 로그 수준 변경

로깅 API는 앱이 실행되는 동안 로그 수준을 변경하는 시나리오를 포함하지 않습니다. 그러나 일부 구성 공급자는 구성을 다시 로드할 수 있으며 이는 로깅 구성에 대한 즉각적인 영향을 줍니다. 예를 들어 파일 구성 공급자는 기본적으로 로깅 구성을 다시 로드합니다. 앱이 실행되는 동안 코드에서 구성이 변경되면 앱이 IConfigurationRoot.Reload를 호출하여 앱의 로깅 구성을 업데이트할 수 있습니다.

ILogger 및 ILoggerFactory

ILogger<TCategoryName>ILoggerFactory 인터페이스와 구현은 .NET Core SDK에 포함되어 있습니다. 또한 다음 NuGet 패키지에서도 사용할 수 있습니다.

코드에서 로그 필터 규칙 적용

로그 필터 규칙을 설정하는 기본 방법은 구성을 사용하는 것입니다.

다음 예제에서는 코드에 필터 규칙을 등록하는 방법을 보여줍니다.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging =>
               logging.AddFilter("System", LogLevel.Debug)
                  .AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)
                  .AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

logging.AddFilter("System", LogLevel.Debug)System범주 및 로그 수준Debug을 지정합니다. 특정 공급자를 구성하지 않았으므로 필터가 모든 공급자에 적용됩니다.

AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)은 다음을 지정합니다.

  • Debug 로깅 공급자
  • 로그 수준 Information 이상
  • "Microsoft"로 시작하는 모든 범주

SpanId, TraceId 및 ParentId를 사용하여 자동으로 로그 범위 지정

로깅 라이브러리는 SpanId, TraceIdParentId를 사용하여 암시적으로 범위 개체를 만듭니다. 이 동작은 ActivityTrackingOptions를 통해 구성됩니다.

  var loggerFactory = LoggerFactory.Create(logging =>
  {
      logging.Configure(options =>
      {
          options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
                                              | ActivityTrackingOptions.TraceId
                                              | ActivityTrackingOptions.ParentId;
      }).AddSimpleConsole(options =>
      {
          options.IncludeScopes = true;
      });
  });

traceparent http 요청 헤더가 설정된 경우 로그 범위의 ParentId는 인바운드 traceparent 헤더의 W3C parent-id를 표시하고, 로그 범위의 SpanId는 다음 아웃바운드 단계/범위에 대해 업데이트된 parent-id를 표시합니다. 자세한 내용은 추적 부모 필드 변경을 참조하세요.

사용자 지정 로거 만들기

사용자 지정 로거를 만들려면 .NET에서 사용자 지정 로깅 공급자 구현을 참조하세요.

추가 리소스