.NET アプリケーション向け New Relic APM 設定ガイド

.NET アプリケーションでの New Relic APM 導入は、エンタープライズレベルでの包括的な監視ソリューションを提供します。.NET エージェントは、CLR レベルでの深い統合、ASP.NET/ASP.NET Core の完全サポート、Windows および Linux 環境での一貫した監視体験を実現します。

.NET エージェントの特徴

New Relic .NET エージェントは、Common Language Runtime(CLR)レベルでの統合により、マネージドコードの実行を詳細に監視します。プロファイリング API を活用したバイトコード計測により、既存のアプリケーションコードを変更することなく包括的な監視を提供します。

ASP.NET MVC、ASP.NET Core、Web API、WCF、Entity Framework などの主要技術スタックとの自動統合により、フレームワーク固有の処理パターンを効率的に追跡できます。また、.NET 5/6/7/8 の最新ランタイムから .NET Framework 4.5 以降まで幅広いバージョンをサポートしています。

導入前の準備

システム要件の確認

.NET エージェントは以下の環境をサポートしています:

  • .NET Framework: 4.5 以降
  • .NET Core/.NET: 2.0 以降(Linux、Windows、macOS)
  • IIS: 7.0 以降
  • IIS Express: 8.0 以降

Windows Server、Azure App Service、Docker コンテナ、Kubernetes での実行が可能です。

必要な権限の確認

Windows 環境では、エージェントインストールに管理者権限が必要です。IIS アプリケーションプールの実行アカウントに適切な権限設定も確認します。

エージェントのインストール

Windows での MSI インストーラー使用

最も一般的なインストール方法は、MSI インストーラーを使用する方法です。

powershell
# MSI インストーラーのダウンロードと実行
# 管理者権限で実行
msiexec /i NewRelicAgent_x64.msi NR_LICENSE_KEY=YOUR_LICENSE_KEY /quiet

NuGet パッケージによるインストール

アプリケーション固有のエージェント導入には、NuGet パッケージを使用できます。

xml
<!-- プロジェクトファイル(.csproj)に追加 -->
<PackageReference Include="NewRelic.Agent" Version="10.20.1" />
powershell
# Package Manager Console
Install-Package NewRelic.Agent

# .NET CLI
dotnet add package NewRelic.Agent

Docker コンテナでのインストール

dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0

# New Relic エージェントのインストール
RUN apt-get update && apt-get install -y wget ca-certificates gnupg \
    && echo 'deb http://apt.newrelic.com/debian/ newrelic non-free' | tee /etc/apt/sources.list.d/newrelic.list \
    && wget https://download.newrelic.com/548C16BF.gpg \
    && apt-key add 548C16BF.gpg \
    && apt-get update \
    && apt-get install -y newrelic-dotnet-agent \
    && rm -rf /var/lib/apt/lists/*

# 環境変数の設定
ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER={36032161-FFC0-4B61-B559-F6C5D41BAE5A}
ENV CORECLR_PROFILER_PATH=/usr/local/newrelic-dotnet-agent/libNewRelicProfiler.so
ENV CORECLR_NEWRELIC_HOME=/usr/local/newrelic-dotnet-agent
ENV NEW_RELIC_LICENSE_KEY=YOUR_LICENSE_KEY
ENV NEW_RELIC_APP_NAME="My .NET App"

COPY . /app
WORKDIR /app
EXPOSE 80

ENTRYPOINT ["dotnet", "MyApp.dll"]

環境変数による設定

基本的な環境変数

bash
# ライセンスキーとアプリケーション名
NEW_RELIC_LICENSE_KEY=your_license_key_here
NEW_RELIC_APP_NAME="My .NET Application"

# プロファイラーの有効化(.NET Core/.NET)
CORECLR_ENABLE_PROFILING=1
CORECLR_PROFILER={36032161-FFC0-4B61-B559-F6C5D41BAE5A}
CORECLR_PROFILER_PATH="C:\Program Files\New Relic\.NET Agent\netcore\NewRelic.Profiler.dll"

# .NET Framework用の設定
COR_ENABLE_PROFILING=1
COR_PROFILER={71DA0A04-7777-4EC6-9643-7D28B46A8A41}
COR_PROFILER_PATH="C:\Program Files\New Relic\.NET Agent\NewRelic.Profiler.dll"

Azure App Service での設定

json
{
  "NEW_RELIC_LICENSE_KEY": "your_license_key",
  "NEW_RELIC_APP_NAME": "MyApp (Azure)",
  "CORECLR_ENABLE_PROFILING": "1",
  "CORECLR_PROFILER": "{36032161-FFC0-4B61-B559-F6C5D41BAE5A}",
  "CORECLR_PROFILER_PATH": "D:\\home\\LogFiles\\NewRelic\\newrelic\\netcore\\NewRelic.Profiler.dll"
}

設定ファイルのカスタマイズ

newrelic.config ファイルの編集

xml
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns="urn:newrelic-config"
              agentEnabled="true"
              logLevel="info"
              licenseKey="YOUR_LICENSE_KEY">
  
  <application>
    <name>My .NET Application</name>
  </application>
  
  <service ssl="true" host="collector.newrelic.com" port="443" />
  
  <transactionTracer enabled="true"
                    transactionThreshold="2.0"
                    recordSql="obfuscated"
                    explainEnabled="true"
                    explainThreshold="500" />
  
  <errorCollector enabled="true">
    <ignoreErrors>
      <exception>System.ArgumentException</exception>
    </ignoreErrors>
    <ignoreStatusCodes>
      <code>400</code>
      <code>401</code>
      <code>404</code>
    </ignoreStatusCodes>
  </errorCollector>
  
  <browserMonitoring autoInstrument="true" />
  
  <attributes enabled="true">
    <include>request.parameters.*</include>
    <exclude>request.headers.cookie</exclude>
    <exclude>request.headers.authorization</exclude>
  </attributes>
  
</configuration>

ASP.NET Core での統合

Startup.cs での設定

csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using NewRelic.Api.Agent;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        
        // New Relic サービスの追加
        services.AddNewRelicTelemetry();
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        
        app.UseRouting();
        app.UseAuthorization();
        
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

コントローラーでのカスタム計測

csharp
using Microsoft.AspNetCore.Mvc;
using NewRelic.Api.Agent;

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;
    
    public OrdersController(IOrderService orderService)
    {
        _orderService = orderService;
    }
    
    [HttpPost]
    [Trace(MetricName = "Custom/Orders/Create")]
    public async Task<IActionResult> CreateOrder([FromBody] CreateOrderRequest request)
    {
        try
        {
            var order = await _orderService.CreateOrderAsync(request);
            
            // カスタムメトリクスの記録
            NewRelic.RecordMetric("Custom/Orders/Created", 1);
            NewRelic.AddCustomAttribute("order.value", order.TotalAmount);
            
            return Ok(order);
        }
        catch (Exception ex)
        {
            NewRelic.NoticeError(ex);
            return StatusCode(500, "Internal server error");
        }
    }
    
    [HttpGet("{id}")]
    public async Task<IActionResult> GetOrder(int id)
    {
        return NewRelic.GetAgent().NewRelic.SetTransactionName("Custom", "GetOrder")
            ? Ok(await _orderService.GetOrderAsync(id))
            : NotFound();
    }
}

Entity Framework 監視

Entity Framework Core での設定

csharp
using Microsoft.EntityFrameworkCore;
using NewRelic.Api.Agent;

public class ApplicationDbContext : DbContext
{
    public DbSet<Order> Orders { get; set; }
    public DbSet<Customer> Customers { get; set; }
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(connectionString);
        
        // New Relic による SQL 監視の有効化
        optionsBuilder.EnableSensitiveDataLogging(false);
        optionsBuilder.LogTo(Console.WriteLine);
    }
}

public class OrderService : IOrderService
{
    private readonly ApplicationDbContext _context;
    
    public OrderService(ApplicationDbContext context)
    {
        _context = context;
    }
    
    [Trace(MetricName = "Database/Orders/GetByCustomer")]
    public async Task<List<Order>> GetOrdersByCustomerAsync(int customerId)
    {
        return await _context.Orders
            .Where(o => o.CustomerId == customerId)
            .Include(o => o.Items)
            .ToListAsync();
    }
}

カスタム計測の実装

ビジネスメトリクスの記録

csharp
using NewRelic.Api.Agent;

public class PaymentService
{
    [Trace(MetricName = "Custom/Payment/Process")]
    public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
    {
        var startTime = DateTime.UtcNow;
        
        try
        {
            var result = await CallPaymentGatewayAsync(request);
            
            // 成功メトリクスの記録
            NewRelic.RecordMetric("Custom/Payment/Success", 1);
            NewRelic.RecordMetric("Custom/Payment/Amount", request.Amount);
            
            // カスタムイベントの記録
            NewRelic.RecordCustomEvent("PaymentProcessed", new Dictionary<string, object>
            {
                ["amount"] = request.Amount,
                ["currency"] = request.Currency,
                ["gateway"] = result.Gateway,
                ["processingTime"] = (DateTime.UtcNow - startTime).TotalMilliseconds
            });
            
            return result;
        }
        catch (Exception ex)
        {
            NewRelic.NoticeError(ex);
            NewRelic.RecordMetric("Custom/Payment/Error", 1);
            throw;
        }
    }
    
    [Trace(MetricName = "External/PaymentGateway/Call")]
    private async Task<PaymentResult> CallPaymentGatewayAsync(PaymentRequest request)
    {
        // 外部サービス呼び出し
        using var httpClient = new HttpClient();
        var response = await httpClient.PostAsJsonAsync("/api/payments", request);
        return await response.Content.ReadFromJsonAsync<PaymentResult>();
    }
}

バックグラウンドタスクの監視

csharp
using NewRelic.Api.Agent;
using Microsoft.Extensions.Hosting;

public class EmailProcessingService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            await ProcessEmailQueueAsync();
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }
    }
    
    [Trace(MetricName = "BackgroundTask/EmailProcessing")]
    private async Task ProcessEmailQueueAsync()
    {
        var emails = await GetPendingEmailsAsync();
        
        foreach (var email in emails)
        {
            await ProcessSingleEmailAsync(email);
        }
        
        NewRelic.RecordMetric("Custom/EmailsProcessed", emails.Count);
    }
    
    [Trace(MetricName = "Email/Send")]
    private async Task ProcessSingleEmailAsync(EmailMessage email)
    {
        try
        {
            await SendEmailAsync(email);
            NewRelic.AddCustomAttribute("email.type", email.Type);
            NewRelic.AddCustomAttribute("email.recipient", email.To);
        }
        catch (Exception ex)
        {
            NewRelic.NoticeError(ex);
            throw;
        }
    }
}

パフォーマンス最適化

メモリとCPU監視

csharp
using System.Diagnostics;
using NewRelic.Api.Agent;

public class PerformanceMonitoringService : IHostedService
{
    private readonly Timer _timer;
    
    public PerformanceMonitoringService()
    {
        _timer = new Timer(RecordPerformanceMetrics, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
    }
    
    private void RecordPerformanceMetrics(object state)
    {
        var process = Process.GetCurrentProcess();
        
        // メモリ使用量
        NewRelic.RecordMetric("Custom/Memory/WorkingSet", process.WorkingSet64);
        NewRelic.RecordMetric("Custom/Memory/PrivateMemory", process.PrivateMemorySize64);
        
        // CPU 使用率
        NewRelic.RecordMetric("Custom/CPU/ProcessorTime", process.TotalProcessorTime.TotalMilliseconds);
        
        // ガベージコレクション
        for (int i = 0; i <= GC.MaxGeneration; i++)
        {
            NewRelic.RecordMetric($"Custom/GC/Gen{i}Collections", GC.CollectionCount(i));
        }
    }
    
    public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer?.Dispose();
        return Task.CompletedTask;
    }
}

設定の最適化

xml
<configuration xmlns="urn:newrelic-config">
  <!-- パフォーマンス最適化設定 -->
  <transactionTracer enabled="true"
                    transactionThreshold="2.0"
                    stackTraceThreshold="0.5"
                    maxStackTrace="30" />
  
  <errorCollector enabled="true" maxTracesStored="50" />
  
  <attributes enabled="true" maximumUserAttributes="64" />
  
  <!-- ガベージコレクション監視 -->
  <instrumentation>
    <applications>
      <application name="MyApp">
        <settings>
          <setting name="GCMetricsEnabled" value="true" />
          <setting name="ThreadProfilingEnabled" value="true" />
        </settings>
      </application>
    </applications>
  </instrumentation>
</configuration>

本番環境でのデプロイメント

IIS での設定

xml
<!-- web.config -->
<configuration>
  <system.webServer>
    <modules>
      <add name="NewRelicHttpModule" 
           type="NewRelic.Agent.Web.NewRelicHttpModule, NewRelic.Agent.Web" 
           preCondition="managedHandler" />
    </modules>
  </system.webServer>
  
  <appSettings>
    <add key="NewRelic.AppSettings.LicenseKey" value="YOUR_LICENSE_KEY" />
    <add key="NewRelic.AppSettings.AppName" value="MyApp (Production)" />
  </appSettings>
</configuration>

Kubernetes での設定

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dotnet-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: myapp:latest
        env:
        - name: NEW_RELIC_LICENSE_KEY
          valueFrom:
            secretKeyRef:
              name: newrelic-secret
              key: license_key
        - name: NEW_RELIC_APP_NAME
          value: "MyApp (Kubernetes)"
        - name: CORECLR_ENABLE_PROFILING
          value: "1"
        - name: CORECLR_PROFILER
          value: "{36032161-FFC0-4B61-B559-F6C5D41BAE5A}"
        - name: CORECLR_PROFILER_PATH
          value: "/usr/local/newrelic-dotnet-agent/libNewRelicProfiler.so"

トラブルシューティング

一般的な問題の診断

csharp
using NewRelic.Api.Agent;

public class DiagnosticsController : ControllerBase
{
    [HttpGet("health/newrelic")]
    public IActionResult NewRelicHealth()
    {
        var agent = NewRelic.GetAgent();
        var traceMetadata = NewRelic.GetTraceMetadata();
        
        return Ok(new
        {
            AgentEnabled = agent != null,
            TraceId = traceMetadata.TraceId,
            SpanId = traceMetadata.SpanId,
            Configuration = new
            {
                AppName = Environment.GetEnvironmentVariable("NEW_RELIC_APP_NAME"),
                LicenseKeyConfigured = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("NEW_RELIC_LICENSE_KEY"))
            }
        });
    }
}

ログ分析

xml
<configuration xmlns="urn:newrelic-config">
  <log level="debug" 
       directory="C:\logs\NewRelic\" 
       fileName="newrelic_agent.log"
       maxLogFiles="5"
       maxLogFileSizeMB="50" />
</configuration>

.NET アプリケーションでの New Relic APM 導入により、エンタープライズレベルでの包括的なパフォーマンス監視を実現できます。CLR レベルでの深い統合と豊富なカスタマイズオプションにより、.NET エコシステムの特性を活かした詳細な分析と継続的な最適化を支援します。


関連記事: Go APM設定関連記事: APM設定完全リファレンス