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

Python アプリケーションでの New Relic APM 導入は、動的な言語特性を活かした柔軟な監視ソリューションを提供します。Python エージェントは、主要なフレームワークとの深い統合、WSGI/ASGI アプリケーションの包括的な監視、豊富なカスタマイズオプションを実現します。

Python エージェントの特徴

New Relic Python エージェントは、インタープリター レベルでの動的計測により、アプリケーションの実行時動作を詳細に追跡します。デコレータベースの計測システムとコンテキスト管理により、Pythonic な監視実装を可能にします。

Django、Flask、FastAPI、Tornado などの主要フレームワークとの自動統合により、フレームワーク固有の処理パターンを効率的に監視できます。また、非同期処理(asyncio)、バックグラウンドタスク(Celery)、データ処理パイプラインなど、Python エコシステムの多様な実行パターンに対応しています。

導入前の準備

環境要件の確認

Python エージェントは以下の環境での動作をサポートしています:

対応 Python バージョン:

  • CPython: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12
  • PyPy3: 3.7以降の互換バージョン
  • Jython: 限定サポート(一部機能のみ)

パフォーマンス影響: メモリオーバーヘッドは通常30-80MB、CPU オーバーヘッドは2-4%程度です。パッケージ管理には pip、conda、Poetry などの標準ツールを使用できます。

仮想環境の設定

本番環境での安定した運用のため、仮想環境での環境分離を推奨します。

bash
# venv を使用した仮想環境の作成
python -m venv newrelic-env
source newrelic-env/bin/activate  # Linux/macOS
# newrelic-env\Scripts\activate    # Windows

# Poetry を使用した場合
poetry init
poetry add newrelic

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

pip を使用したインストール

bash
pip install newrelic

requirements.txt への追加

txt
newrelic>=9.2.0  # 最新版推奨(Python 3.12 対応)

Poetry プロジェクトでの追加

bash
poetry add newrelic

基本設定の構成

設定ファイルの生成

New Relic エージェントの設定ファイルを生成します。

bash
newrelic-admin generate-config YOUR_LICENSE_KEY newrelic.ini

設定ファイルの編集

生成された newrelic.ini ファイルを編集し、アプリケーション固有の設定を行います。

ini
[newrelic]
license_key = YOUR_LICENSE_KEY
app_name = My Python Application

# ログ設定
log_file = /tmp/newrelic-python-agent.log
log_level = info

# トランザクション設定
transaction_tracer.enabled = true
transaction_tracer.transaction_threshold = 2.0
transaction_tracer.record_sql = obfuscated
transaction_tracer.stack_trace_threshold = 0.5

# エラー収集設定
error_collector.enabled = true
error_collector.ignore_errors = requests.exceptions.ConnectionError

# ブラウザ監視設定
browser_monitoring.auto_instrument = true

フレームワーク別設定

Django アプリケーション

Django プロジェクトでは、WSGI ファイルまたは manage.py での初期化を行います。

settings.py での設定

python
# settings.py
import newrelic.agent

# New Relic エージェントの初期化
newrelic.agent.initialize('/path/to/newrelic.ini')

# Django設定
INSTALLED_APPS = [
    'newrelic',  # オプション:Django固有の統合
    # その他のアプリ
]

# ミドルウェア設定
MIDDLEWARE = [
    'newrelic.agent.django_middleware',
    # その他のミドルウェア
]

wsgi.py での設定

python
# wsgi.py
import os
import newrelic.agent

# New Relic設定の初期化
newrelic.agent.initialize()

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_wsgi_application()

# WSGIアプリケーションのラップ
application = newrelic.agent.wsgi_application()(application)

Flask アプリケーション

Flask アプリケーションでは、アプリケーション初期化時にエージェントを設定します。

python
# app.py
import newrelic.agent
newrelic.agent.initialize()

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run()

FastAPI アプリケーション

FastAPI では ASGI アプリケーションとしてエージェントを統合します。

python
# main.py
import newrelic.agent
newrelic.agent.initialize()

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"Hello": "World"}

# ASGI アプリケーションのラップ
app = newrelic.agent.asgi_application()(app)

起動方法の設定

環境変数による設定

bash
export NEW_RELIC_CONFIG_FILE=/path/to/newrelic.ini
export NEW_RELIC_ENVIRONMENT=production
python app.py

newrelic-admin コマンドによる起動

bash
newrelic-admin run-program python app.py

Gunicorn での起動

bash
newrelic-admin run-program gunicorn --bind 0.0.0.0:8000 myapp:app

uWSGI での起動

bash
newrelic-admin run-program uwsgi --http :8000 --module myapp:app

カスタム計測の実装

デコレータベースの計測

重要な関数やメソッドにカスタム計測を追加できます。

python
import newrelic.agent

@newrelic.agent.function_trace()
def important_business_logic():
    # ビジネスロジック
    pass

@newrelic.agent.background_task()
def background_process():
    # バックグラウンド処理
    pass

class PaymentService:
    @newrelic.agent.function_trace('PaymentService/process_payment')
    def process_payment(self, amount):
        # 支払い処理
        newrelic.agent.record_custom_metric('Custom/PaymentAmount', amount)

コンテキストマネージャーによる計測

python
import newrelic.agent

def complex_operation():
    with newrelic.agent.FunctionTrace('ComplexOperation/database_query'):
        # データベース処理
        pass
    
    with newrelic.agent.FunctionTrace('ComplexOperation/api_call'):
        # API呼び出し
        pass

非同期処理の計測

python
import asyncio
import newrelic.agent

@newrelic.agent.background_task()
async def async_background_task():
    await asyncio.sleep(1)
    newrelic.agent.record_custom_event('AsyncTaskCompleted', {
        'duration': 1.0,
        'task_type': 'background'
    })

async def main():
    await async_background_task()

Celery 統合

Celery タスクの監視

python
# tasks.py
import newrelic.agent
from celery import Celery

app = Celery('tasks')

@app.task
@newrelic.agent.background_task()
def add(x, y):
    result = x + y
    newrelic.agent.record_custom_metric('Custom/CeleryTask/Add', result)
    return result

Celery ワーカーの起動

bash
newrelic-admin run-program celery -A tasks worker --loglevel=info

データベース監視の詳細設定

SQLAlchemy 統合

python
from sqlalchemy import create_engine
import newrelic.agent

# データベースエンジンの作成
engine = create_engine('postgresql://user:password@localhost/dbname')

# 自動的にSQLクエリが監視される

Django ORM の詳細監視

ini
[newrelic]
# Django ORM固有の設定
database_name_reporting.enabled = true
transaction_tracer.explain_enabled = true
transaction_tracer.explain_threshold = 500

パフォーマンス最適化

エージェント設定の調整

ini
[newrelic]
# パフォーマンス影響を最小化する設定
transaction_tracer.top_n = 20
error_collector.max_stack_trace_lines = 50
agent_limits.transaction_traces_nodes = 2000

メモリ使用量の最適化

python
import newrelic.agent

# エージェント設定のプログラムによる調整
settings = newrelic.agent.global_settings()
settings.transaction_tracer.explain_threshold = 1.0
settings.slow_sql.enabled = True

監視データの確認とアラート設定

カスタムメトリクスの記録

python
import newrelic.agent

def business_metric_example():
    # ビジネスメトリクスの記録
    newrelic.agent.record_custom_metric('Business/Revenue', 1500.00)
    newrelic.agent.record_custom_metric('Business/UserSignups', 5)
    
    # カスタムイベントの記録
    newrelic.agent.record_custom_event('UserAction', {
        'user_id': 12345,
        'action_type': 'purchase',
        'amount': 99.99
    })

セキュリティベストプラクティス

OWASP Top 10に準拠したセキュリティ設定:

ini
[newrelic]
# 機密情報の自動難読化
capture_params = false
ignored_params = password,credit_card,ssn,api_key,token

# HTTPSアクセスの強制
ssl = true

# 属性から機密情報を除外
attributes.exclude = request.headers.authorization,
                   request.headers.x-api-key,
                   request.parameters.password,
                   request.parameters.credit_card

# セキュリティヘッダーの監視
browser_monitoring.auto_instrument = true

高度なエラーハンドリング

包括的なエラー追跡と分析の実装例:

python
import newrelic.agent
import logging
from functools import wraps
from enum import Enum

class ErrorSeverity(Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"

class AdvancedErrorHandler:
    def __init__(self):
        self.logger = logging.getLogger(__name__)
    
    def handle_error(self, exception, severity=ErrorSeverity.MEDIUM, **extra_attributes):
        """包括的なエラーハンドリング"""
        attributes = {
            'error.severity': severity.value,
            'error.class': type(exception).__name__,
            'error.message': str(exception),
            **extra_attributes
        }
        
        # エラーカテゴリ別の分類
        if isinstance(exception, ValueError):
            attributes['error.category'] = 'validation'
            newrelic.agent.record_custom_metric('Errors/Validation', 1)
        elif isinstance(exception, ConnectionError):
            attributes['error.category'] = 'network'
            newrelic.agent.record_custom_metric('Errors/Network', 1)
        elif isinstance(exception, PermissionError):
            attributes['error.category'] = 'security'
            newrelic.agent.record_custom_metric('Errors/Security', 1)
        else:
            attributes['error.category'] = 'unexpected'
            newrelic.agent.record_custom_metric('Errors/Unexpected', 1)
        
        # New Relicへのエラー報告
        newrelic.agent.notice_error(attributes=attributes)
        
        # 重要度に応じたアラート
        if severity == ErrorSeverity.CRITICAL:
            newrelic.agent.record_custom_metric('Errors/Critical', 1)
            self._trigger_critical_alert(exception, attributes)
        
        self.logger.error(f"Error handled: {exception}", extra=attributes)
    
    def _trigger_critical_alert(self, exception, attributes):
        """クリティカルエラー用のアラート送信"""
        # アラート送信ロジック
        self.logger.critical(f"Critical error detected: {exception}")

def error_tracking_decorator(severity=ErrorSeverity.MEDIUM, **extra_attrs):
    """エラートラッキング用デコレータ"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                error_handler = AdvancedErrorHandler()
                error_handler.handle_error(
                    e, 
                    severity=severity,
                    function_name=func.__name__,
                    **extra_attrs
                )
                raise
        return wrapper
    return decorator

# 使用例
@error_tracking_decorator(severity=ErrorSeverity.HIGH, module='payment')
@newrelic.agent.function_trace()
def process_payment(payment_data):
    # 支払い処理ロジック
    if not payment_data.get('amount'):
        raise ValueError("Payment amount is required")
    # 処理継続...

ビジネスメトリクス収集

アプリケーション固有のビジネス価値を測定するカスタムメトリクス:

python
import newrelic.agent
from datetime import datetime
from functools import wraps

class BusinessMetricsCollector:
    """ビジネスメトリクス収集クラス"""
    
    @staticmethod
    def track_user_action(action_type, user_id, **metadata):
        """ユーザーアクション追跡"""
        attributes = {
            'user_id': user_id,
            'action_type': action_type,
            'timestamp': datetime.now().isoformat(),
            **metadata
        }
        
        # メトリクス記録
        newrelic.agent.record_custom_metric(f'Business/UserActions/{action_type}', 1)
        newrelic.agent.record_custom_event('UserAction', attributes)
    
    @staticmethod
    def track_revenue(amount, currency='USD', category=None, **metadata):
        """売上追跡"""
        attributes = {
            'amount': amount,
            'currency': currency,
            'category': category or 'general',
            'timestamp': datetime.now().isoformat(),
            **metadata
        }
        
        # 売上メトリクス
        newrelic.agent.record_custom_metric('Business/Revenue/Total', amount)
        if category:
            newrelic.agent.record_custom_metric(f'Business/Revenue/Category/{category}', amount)
        
        newrelic.agent.record_custom_event('RevenueGenerated', attributes)
    
    @staticmethod
    def track_conversion(conversion_type, funnel_stage, **metadata):
        """コンバージョン追跡"""
        attributes = {
            'conversion_type': conversion_type,
            'funnel_stage': funnel_stage,
            'timestamp': datetime.now().isoformat(),
            **metadata
        }
        
        newrelic.agent.record_custom_metric(f'Business/Conversions/{conversion_type}', 1)
        newrelic.agent.record_custom_event('ConversionEvent', attributes)

def business_metrics_decorator(metric_type, **default_attrs):
    """ビジネスメトリクス記録用デコレータ"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start_time = datetime.now()
            
            try:
                result = func(*args, **kwargs)
                
                # 成功メトリクス
                duration = (datetime.now() - start_time).total_seconds()
                attributes = {
                    'function_name': func.__name__,
                    'duration': duration,
                    'status': 'success',
                    **default_attrs
                }
                
                newrelic.agent.record_custom_metric(f'Business/{metric_type}/Success', 1)
                newrelic.agent.record_custom_metric(f'Business/{metric_type}/Duration', duration)
                newrelic.agent.record_custom_event(f'{metric_type}Completed', attributes)
                
                return result
                
            except Exception as e:
                # 失敗メトリクス
                duration = (datetime.now() - start_time).total_seconds()
                attributes = {
                    'function_name': func.__name__,
                    'duration': duration,
                    'status': 'error',
                    'error_type': type(e).__name__,
                    **default_attrs
                }
                
                newrelic.agent.record_custom_metric(f'Business/{metric_type}/Error', 1)
                newrelic.agent.record_custom_event(f'{metric_type}Failed', attributes)
                raise
                
        return wrapper
    return decorator

# 使用例
@business_metrics_decorator('OrderProcessing', priority='high')
@newrelic.agent.function_trace()
def process_order(order_data):
    """注文処理"""
    # 注文処理ロジック
    order_total = calculate_order_total(order_data)
    
    # ビジネスメトリクスの記録
    BusinessMetricsCollector.track_revenue(
        amount=order_total,
        category=order_data.get('category', 'general'),
        customer_segment=order_data.get('customer_type', 'regular')
    )
    
    BusinessMetricsCollector.track_conversion(
        conversion_type='purchase',
        funnel_stage='checkout_complete',
        order_value=order_total
    )
    
    return order_total

# FastAPI/Flask での実装例
from flask import Flask, request
import newrelic.agent

app = Flask(__name__)

@app.route('/api/purchase', methods=['POST'])
@newrelic.agent.web_transaction()
def purchase_endpoint():
    try:
        order_data = request.get_json()
        
        # ユーザーアクション追跡
        BusinessMetricsCollector.track_user_action(
            action_type='purchase_attempt',
            user_id=order_data.get('user_id'),
            product_category=order_data.get('category')
        )
        
        # 注文処理
        result = process_order(order_data)
        
        return {'status': 'success', 'order_total': result}
        
    except Exception as e:
        # エラー処理と追跡
        error_handler = AdvancedErrorHandler()
        error_handler.handle_error(
            e, 
            severity=ErrorSeverity.HIGH,
            endpoint='/api/purchase',
            user_id=order_data.get('user_id', 'unknown')
        )
        return {'status': 'error', 'message': str(e)}, 500

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

環境別設定の管理

ini
[newrelic:production]
app_name = MyApp (Production)
monitor_mode = true
log_level = info

[newrelic:staging]
app_name = MyApp (Staging)
monitor_mode = true
log_level = debug

[newrelic:development]
app_name = MyApp (Development)
monitor_mode = false
log_level = debug

Docker コンテナでの設定

dockerfile
FROM python:3.11-slim

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY newrelic.ini .
COPY app.py .

# New Relic エージェントでアプリケーションを起動
CMD ["newrelic-admin", "run-program", "python", "app.py"]

Kubernetes での設定

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: myapp:latest
        env:
        - name: NEW_RELIC_CONFIG_FILE
          value: "/app/newrelic.ini"
        - name: NEW_RELIC_ENVIRONMENT
          value: "production"

トラブルシューティング

一般的な問題の診断

python
import newrelic.agent

# エージェント状態の確認
print(f"Agent version: {newrelic.agent.version}")
print(f"Config file: {newrelic.agent.config_file}")

# アプリケーション情報の確認
application = newrelic.agent.application()
print(f"Application name: {application.name}")
print(f"Application settings: {application.settings}")

ログ分析

ini
[newrelic]
log_file = /var/log/newrelic/python-agent.log
log_level = debug
audit_log_file = /var/log/newrelic/python-audit.log

Python アプリケーションでの New Relic APM 導入により、動的な言語特性を活かした詳細なパフォーマンス監視を実現できます。適切な設定と統合により、Python エコシステムの多様な実行パターンに対応した包括的な監視システムを構築できます。


関連記事: Node.js APM設定関連記事: 分散トレーシング設定