측정지표는 시간에 따라 보고되는 수치적 측정값입니다. 일반적으로 앱의 상태를 모니터링하고 경고를 생성하는 데 사용됩니다.
.NET 8부터 System.Net.Http
및 System.Net.NameResolution
구성 요소가 계측되어, .NET의 새로운 System.Diagnostics.Metrics API를 사용하여 메트릭을 게시합니다.
이러한 메트릭은 OpenTelemetry 협력하여 표준과 일치하고 Prometheus 및 Grafana같은 인기 있는 도구와 잘 작동하도록 설계되었습니다.
또한 다차원 , 즉 측정값은 태그(특성 또는 레이블이라고도 함)라는 키-값 쌍과 연결됩니다. 태그를 사용하면 측정값을 분류하여 분석에 도움이 됩니다.
팁
모든 기본 제공 도구와 그 특성의 포괄적인 목록은 System.Net 메트릭을 참조하세요.
System.Net 메트릭 수집
기본 제공 메트릭 계측을 활용하려면 이러한 메트릭을 수집하도록 .NET 앱을 구성해야 합니다. 이는 일반적으로 외부 스토리지 및 분석을 위해 모니터링 시스템으로 변환하는 것을 의미합니다.
.NET에서 네트워킹 메트릭을 수집하는 방법에는 여러 가지가 있습니다.
- 간단하고 독립적인 예제를 사용하여 빠른 개요를 보려면 dotnet-counters 메트릭 수집을 참조하세요.
- 프로덕션 시간 메트릭 수집 및 모니터링의 경우 OpenTelemetry 및 Prometheus Grafana를 사용하거나 Azure Monitor Application Insights 수 있습니다. 그러나 이러한 도구는 복잡성 때문에 개발 시 사용하기가 불편할 수 있습니다.
- 개발 시간 메트릭 수집 및 문제 해결을 위해 애플리케이션에서 메트릭 및 분산 추적을 시작하고 로컬에서 문제를 진단하는 간단하지만 확장 가능한 방법을 제공하는 .NET Aspire사용하는 것이 좋습니다.
- 또한 ASP.NET 프로젝트에 OpenTelemetry 추적 및 메트릭 구성 API를 도입하는 편리한 방법인 Aspire 오케스트레이션 없이 Aspire 서비스 기본 프로젝트를 다시 사용할 있습니다.
dotnet-counters를 사용하여 메트릭 수집
dotnet-counters
.NET 메트릭의 임시 검사 및 첫 번째 수준 성능 조사를 위한 플랫폼 간 명령줄 도구입니다.
이 자습서를 위해 다양한 엔드포인트에 HTTP 요청을 병렬로 보내는 앱을 만듭니다.
dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics
Program.cs
내용을 다음 샘플 코드로 바꿉니다.
using System.Net;
string[] uris = ["http://example.com", "http://httpbin.org/get", "https://example.com", "https://httpbin.org/get"];
using HttpClient client = new()
{
DefaultRequestVersion = HttpVersion.Version20
};
Console.WriteLine("Press any key to start.");
Console.ReadKey();
while (!Console.KeyAvailable)
{
await Parallel.ForAsync(0, Random.Shared.Next(20), async (_, ct) =>
{
string uri = uris[Random.Shared.Next(uris.Length)];
try
{
byte[] bytes = await client.GetByteArrayAsync(uri, ct);
await Console.Out.WriteLineAsync($"{uri} - received {bytes.Length} bytes.");
}
catch { await Console.Out.WriteLineAsync($"{uri} - failed."); }
});
}
dotnet-counters
설치되어 있는지 확인합니다.
dotnet tool install --global dotnet-counters
HelloBuiltinMetrics 앱을 시작합니다.
dotnet run -c Release
별도의 CLI 창에서 dotnet-counters
시작하고 감시할 프로세스 이름과 미터를 지정한 다음 HelloBuiltinMetrics 앱에서 키를 눌러 요청 보내기를 시작합니다. 측정값이 착륙하기 시작하자마자 dotnet-counters
계속해서 최신 숫자로 콘솔을 새로 고칩니다.
dotnet-counters monitor --counters System.Net.Http,System.Net.NameResolution -n HelloBuiltinMetrics
dotnet-counters 출력dotnet-counters output
.NET Aspire를 사용하여 메트릭 수집
ASP.NET 애플리케이션에서 추적 및 메트릭을 수집하는 간단한 방법은 .NET Aspire사용하는 것입니다. .NET Aspire는 분산 애플리케이션을 쉽게 만들고 사용할 수 있도록 .NET에 대한 확장 집합입니다. .NET Aspire를 사용할 때의 이점 중 하나는 .NET용 OpenTelemetry 라이브러리를 사용하여 원격 분석이 기본 제공된다는 것입니다.
.NET Aspire의 기본 프로젝트 템플릿에는 ServiceDefaults
프로젝트가 포함되어 있습니다. .NET Aspire 솔루션의 각 서비스에는 서비스 기본값 프로젝트에 대한 참조가 있습니다. 서비스는 OTel을 설정하고 구성하는 데 사용합니다.
서비스 기본값 프로젝트 템플릿에는 OTel SDK, ASP.NET, HttpClient 및 런타임 계측 패키지가 포함됩니다. 이러한 계측 구성 요소는 Extensions.cs 파일에 구성됩니다. Aspire 대시보드에서 원격 분석 시각화를 지원하기 위해 서비스 기본값 프로젝트에는 기본적으로 OTLP 내보내기도 포함됩니다.
Aspire 대시보드는 로컬 디버그 주기에 원격 분석 관찰을 제공하도록 설계되어 개발자가 애플리케이션에서 원격 분석을 생성하도록 할 수 있습니다. 원격 분석 시각화는 이러한 애플리케이션을 로컬로 진단하는 데도 도움이 됩니다. 서비스 간의 호출을 관찰할 수 있다는 것은 프로덕션에서처럼 디버그 시 유용합니다. .NET Aspire 대시보드는 Visual Studio에서 AppHost
프로젝트를 실행하거나 명령줄에서 dotnet run
프로젝트를 AppHost
할 때 자동으로 시작됩니다.
빠른 가이드
사용하여
dotnet new
만듭니다.dotnet new aspire-starter-9 --output AspireDemo
또는 Visual Studio에서 새 프로젝트를 만들고 .NET Aspire 9 Starter 앱 템플릿을 선택합니다.
Extensions.cs
프로젝트에서ServiceDefaults
열고ConfigureOpenTelemetry
메서드로 스크롤합니다. 네트워킹 미터를 구독하는AddHttpClientInstrumentation()
호출을 확인합니다..WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddRuntimeInstrumentation(); })
.NET 8 및 이후 버전에서는
AddHttpClientInstrumentation()
를 수동 미터 구독으로 바꿀 수 있음을 유의하십시오..WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() .AddMeter("System.Net.Http") .AddMeter("System.Net.NameResolution") .AddRuntimeInstrumentation(); })
AppHost
프로젝트를 실행합니다. 이는 Aspire 대시보드를 실행합니다.webfrontend
앱의 날씨 페이지로 이동하여HttpClient
대한apiservice
요청을 생성합니다. 여러 요청을 보내려면 페이지를 여러 번 새로 고치세요.대시보드로 돌아가서 메트릭 페이지로 이동하고
webfrontend
리소스를 선택합니다. 아래로 스크롤하면 기본 제공System.Net
메트릭을 찾아볼 수 있습니다.
.NET Aspire에 대한 자세한 내용은 다음을 참조하세요.
.NET Aspire 오케스트레이션 없이 서비스 기본 프로젝트 다시 사용
Aspire Service Defaults 프로젝트는 오케스트레이션에 AppHost와 같은 나머지 .NET Aspire 사용하지 않더라도 ASP.NET 프로젝트에 OTel을 쉽게 구성할 수 있는 방법을 제공합니다. 서비스 기본값 프로젝트는 Visual Studio 또는 dotnet new
통해 프로젝트 템플릿으로 사용할 수 있습니다. OTel을 구성하고 OTLP 내보내기를 설정합니다. 그런 다음 OTel 환경 변수 사용하여 원격 분석을 보내고 애플리케이션에 대한 리소스 속성을 제공하도록 OTLP 엔드포인트를 구성할 수 있습니다.
.NET Aspire 외부에서 ServiceDefaults 사용하는 단계는 다음과 같습니다.
Visual Studio에서 새 프로젝트 추가를 사용하여 ServiceDefaults 프로젝트를 솔루션에 추가하거나
dotnet new
사용합니다.dotnet new aspire-servicedefaults --output ServiceDefaults
ASP.NET 애플리케이션에서 ServiceDefaults 프로젝트를 참조합니다. Visual Studio에서 >선택하고 ServiceDefaults 프로젝트"를 선택합니다.
애플리케이션 작성기 초기화의 일부로 OpenTelemetry 설치 함수
ConfigureOpenTelemetry()
호출합니다.var builder = WebApplication.CreateBuilder(args) builder.ConfigureOpenTelemetry(); // Extension method from ServiceDefaults. var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run();
전체 단계별 설명은 예제: OpenTelemetry와 OTLP 사용 및 단독 Aspire 대시보드를 참조하세요.
OpenTelemetry 및 Prometheus를 사용하여 Grafana에서 메트릭 보기
예제 앱을 Prometheus 및 Grafana와 연결하는 방법을 보려면 Prometheus, Grafana 및 JaegerOpenTelemetry 사용 연습에 따릅니다.
다양한 엔드포인트에 병렬 요청을 전송하여 HttpClient
강조하려면 다음 엔드포인트를 사용하여 예제 앱을 확장합니다.
app.MapGet("/ClientStress", async Task<string> (ILogger<Program> logger, HttpClient client) =>
{
string[] uris = ["http://example.com", "http://httpbin.org/get", "https://example.com", "https://httpbin.org/get"];
await Parallel.ForAsync(0, 50, async (_, ct) =>
{
string uri = uris[Random.Shared.Next(uris.Length)];
try
{
await client.GetAsync(uri, ct);
logger.LogInformation($"{uri} - done.");
}
catch { logger.LogInformation($"{uri} - failed."); }
});
return "Sent 50 requests to example.com and httpbin.org.";
});
위쪽 도구 모음에서 + 아이콘을 선택한 다음 대시보드선택하여 Grafana 대시보드를 만듭니다. 표시되는 대시보드 편집기에서 제목 상자에 HTTP/1.1 연결 열기를 입력하고, PromQL 식 필드에 다음 쿼리를 입력합니다.
sum by(http_connection_state) (http_client_open_connections{network_protocol_version="1.1"})
적용 선택하여 새 대시보드를 저장하고 봅니다. 풀에서 활성 및 유휴 HTTP/1.1 연결 수를 표시합니다.
농축
보강 메트릭에 사용자 지정 태그(특성 또는 레이블이라고도 함)를 추가하는 것입니다. 이는 앱이 메트릭을 사용하여 빌드된 대시보드 또는 경고에 사용자 지정 분류를 추가하려는 경우에 유용합니다.
http.client.request.duration
계측기는 콜백을 HttpMetricsEnrichmentContext을 통해 등록하여 강화를 지원합니다.
이 API는 하위 수준 API이며 각 HttpRequestMessage
대해 별도의 콜백 등록이 필요합니다.
단일 위치에서 콜백 등록을 수행하는 간단한 방법은 사용자 지정 DelegatingHandler구현하는 것입니다. 이렇게 하면 내부 처리기로 전달되고 서버로 전송되기 전에 요청을 가로채고 수정할 수 있습니다.
using System.Net.Http.Metrics;
using HttpClient client = new(new EnrichmentHandler() { InnerHandler = new HttpClientHandler() });
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");
sealed class EnrichmentHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpMetricsEnrichmentContext.AddCallback(request, static context =>
{
if (context.Response is not null) // Response is null when an exception occurs.
{
// Use any information available on the request or the response to emit custom tags.
string? value = context.Response.Headers.GetValues("Enrichment-Value").FirstOrDefault();
if (value != null)
{
context.AddCustomTag("enrichment_value", value);
}
}
});
return base.SendAsync(request, cancellationToken);
}
}
IHttpClientFactory
으로 작업하는 경우, AddHttpMessageHandler을 사용하여 EnrichmentHandler
를 등록할 수 있습니다.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Net.Http.Metrics;
ServiceCollection services = new();
services.AddHttpClient(Options.DefaultName).AddHttpMessageHandler(() => new EnrichmentHandler());
ServiceProvider serviceProvider = services.BuildServiceProvider();
HttpClient client = serviceProvider.GetRequiredService<HttpClient>();
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");
메모
성능상의 이유로 보강 콜백은 http.client.request.duration
계측이 활성화된 경우에만 호출됩니다. 즉, 메트릭을 수집해야 합니다.
dotnet-monitor
, Prometheus 내보내기, MeterListener
또는 MetricCollector<T>
일 수 있습니다.
IMeterFactory
및 IHttpClientFactory
통합
HTTP 메트릭은 격리 및 테스트 가능성을 염두에 두고 설계되었습니다. 이러한 측면은 IMeterFactory사용하여 지원되며, 이를 통해 미터를 서로 격리하기 위해 사용자 지정 Meter 인스턴스에서 메트릭을 게시할 수 있습니다.
기본적으로 전역 Meter 모든 메트릭을 내보내는 데 사용됩니다. 이 Meter은(는) System.Net.Http
라이브러리 내에 있습니다. 사용자 지정 IMeterFactory 인스턴스를 SocketsHttpHandler.MeterFactory 또는 HttpClientHandler.MeterFactory할당하여 이 동작을 재정의할 수 있습니다.
메모
Meter.Name는 System.Net.Http
와 HttpClientHandler
이 내보내는 모든 메트릭에 대해 SocketsHttpHandler
입니다.
.NET 8 이상에서 Microsoft.Extensions.Http
및 IHttpClientFactory
사용하는 경우 기본 IHttpClientFactory
구현은 IMeterFactory
등록된 IServiceCollection 인스턴스를 자동으로 선택하고 내부적으로 만드는 기본 처리기에 할당합니다.
메모
.NET 8부터 AddHttpClient 메서드는 자동으로 AddMetrics 호출하여 메트릭 서비스를 초기화하고 기본 IMeterFactory 구현을 IServiceCollection등록합니다. 기본 IMeterFactory은 이름으로 Meter 인스턴스를 캐시합니다. 즉, Meter마다 이름이 System.Net.Http
인 IServiceCollection 하나가 있습니다.
테스트 메트릭
다음 예제에서는 IHttpClientFactory
NuGet 패키지에서 xUnit, MetricCollector<T>
및 Microsoft.Extensions.Diagnostics.Testing
사용하여 단위 테스트에서 기본 제공 메트릭의 유효성을 검사하는 방법을 보여 줍니다.
[Fact]
public async Task RequestDurationTest()
{
// Arrange
ServiceCollection services = new();
services.AddHttpClient();
ServiceProvider serviceProvider = services.BuildServiceProvider();
var meterFactory = serviceProvider.GetService<IMeterFactory>();
var collector = new MetricCollector<double>(meterFactory,
"System.Net.Http", "http.client.request.duration");
var client = serviceProvider.GetRequiredService<HttpClient>();
// Act
await client.GetStringAsync("http://example.com");
// Assert
await collector.WaitForMeasurementsAsync(minCount: 1).WaitAsync(TimeSpan.FromSeconds(5));
Assert.Collection(collector.GetMeasurementSnapshot(),
measurement =>
{
Assert.Equal("http", measurement.Tags["url.scheme"]);
Assert.Equal("GET", measurement.Tags["http.request.method"]);
});
}
메트릭과 EventCounters 비교
메트릭은 EventCounters보다 기능이 풍부한 , 특히 다차원 특성 때문입니다. 이 다차원을 사용하면 Prometheus와 같은 도구에서 정교한 쿼리를 만들고 EventCounters에서 불가능한 수준에서 인사이트를 얻을 수 있습니다.
그럼에도 불구하고 .NET 8부터는 메트릭을 사용하여 System.Net.Http
및 System.Net.NameResolutions
구성 요소만 계측됩니다. 즉, System.Net.Sockets
또는 System.Net.Security
같은 스택의 하위 수준에서 카운터가 필요한 경우 EventCounters를 사용해야 합니다.
또한 메트릭과 일치하는 EventCounters 간에는 몇 가지 의미 체계 차이가 있습니다.
예를 들어 HttpCompletionOption.ResponseContentRead
사용하는 경우 current-requests
EventCounter 요청 본문의 마지막 바이트를 읽은 순간까지 요청이 활성화된 것으로 간주합니다.
http.client.active_requests
해당 메트릭에는 활성 요청을 계산할 때 응답 본문을 읽는 데 소요된 시간이 포함되지 않습니다.
더 많은 메트릭이 필요하세요?
메트릭을 통해 노출될 수 있는 다른 유용한 정보에 대한 제안이 있는 경우 dotnet/runtime 이슈을 만드세요.
.NET