New Relic

フルスタック可観測性プラットフォーム。APM、インフラ監視、ブラウザ監視、モバイル監視を統合。リアルタイム性能分析とAI支援による問題解決機能。

監視サーバーAPMフルスタック可観測性性能監視AI支援デジタル変革クラウドファースト

監視サーバー

New Relic

概要

New Relicはフルスタック可観測性プラットフォームです。APM、インフラ監視、ブラウザ監視、モバイル監視を統合し、リアルタイム性能分析とAI支援による問題解決機能を提供します。APM分野での老舗プロバイダーとして、AI支援による自動化機能、フルスタック可観測性でデジタル変革を支援し、クラウドファースト戦略で成長を続ける包括的監視ソリューションです。

詳細

New Relicは2008年にLew Cirrneによって設立され、APM分野での老舗プロバイダーとして長年の実績を持ちます。AI支援による自動化機能、フルスタック可観測性でデジタル変革を支援し、クラウドファースト戦略で継続的な成長を遂げています。統一された可観測性プラットフォームとして、開発・運用チームの生産性向上とシステムの信頼性確保に貢献しています。

主要な技術的特徴

  • フルスタック可観測性: アプリケーションからインフラまで統合監視
  • AI支援分析: 機械学習による自動異常検知と根本原因分析
  • リアルタイム分析: 高頻度データ収集とリアルタイム分析
  • 統一ダッシュボード: 全レイヤーの情報を統合した可視化
  • 豊富なインテグレーション: 主要プラットフォーム・ツールとの統合

用途

  • アプリケーション性能監視(APM)
  • インフラストラクチャ監視
  • ブラウザ・モバイルアプリ監視
  • サーバーレス監視
  • デジタルカスタマーエクスペリエンス監視

メリット・デメリット

メリット

  • 包括的監視: フルスタック可観測性の統一プラットフォーム
  • AI/ML機能: 高度な異常検知と予測分析
  • 豊富な経験: APM分野での長年の実績と知見
  • リアルタイム分析: 高頻度データ収集による即座の洞察
  • スケーラビリティ: エンタープライズ規模での高い信頼性
  • 統合プラットフォーム: 開発から運用まで一元管理

デメリット

  • 高コスト: エンタープライズ向けの高額な料金体系
  • 複雑性: 豊富な機能による習得の複雑さ
  • ベンダーロックイン: プラットフォーム依存のリスク
  • 設定複雑性: 最適な設定のための専門知識が必要
  • データボリューム制限: 大量データでのコスト増加

参考ページ

書き方の例

New Relic Agent設定

# newrelic.ini
[newrelic]
license_key = YOUR_LICENSE_KEY_HERE
app_name = My Python Application

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

# 監視設定
monitor_mode = true
ssl = true
high_security = false

# パフォーマンス設定
agent_limits.data_collector_timeout = 30.0
agent_limits.transaction_tracer_timeout = 10.0

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

# エラー設定
error_collector.enabled = true
error_collector.ignore_errors = 
error_collector.ignore_status_codes = 404

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

# データベース設定
datastore_tracer.instance_reporting.enabled = true
datastore_tracer.database_name_reporting.enabled = true

# 分散トレーシング
distributed_tracing.enabled = true

# カスタムインサイト
custom_insights_events.enabled = true

# セキュリティ設定
capture_params = false
ignored_params = credit_card, ssn, password

# 属性設定
attributes.enabled = true
attributes.exclude = request.headers.cookie
attributes.exclude = request.headers.authorization
attributes.exclude = request.headers.proxy-authorization
attributes.exclude = request.headers.x-*

# ラベル設定
labels = Environment:Production;Team:Backend;Region:US-East

Python アプリケーション統合

# app.py
import newrelic.agent
import logging
import time
from flask import Flask, request, jsonify
from sqlalchemy import create_engine, text
import redis

# New Relic初期化
newrelic.agent.initialize('/path/to/newrelic.ini')

app = Flask(__name__)

# データベース接続
engine = create_engine('postgresql://user:pass@localhost/mydb')

# Redis接続
redis_client = redis.Redis(host='localhost', port=6379, db=0)

# ログ設定
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@newrelic.agent.function_trace()
def get_user_from_db(user_id):
    """データベースからユーザー情報を取得"""
    with engine.connect() as conn:
        result = conn.execute(
            text("SELECT * FROM users WHERE id = :user_id"),
            user_id=user_id
        )
        return result.fetchone()

@newrelic.agent.function_trace()
def get_user_from_cache(user_id):
    """キャッシュからユーザー情報を取得"""
    cache_key = f"user:{user_id}"
    cached_data = redis_client.get(cache_key)
    
    if cached_data:
        newrelic.agent.add_custom_attribute('cache_hit', True)
        return cached_data.decode('utf-8')
    
    newrelic.agent.add_custom_attribute('cache_hit', False)
    return None

@app.route('/user/<int:user_id>')
@newrelic.agent.function_trace()
def get_user(user_id):
    """ユーザー情報取得エンドポイント"""
    
    # カスタム属性追加
    newrelic.agent.add_custom_attribute('user_id', user_id)
    newrelic.agent.add_custom_attribute('endpoint', 'get_user')
    
    try:
        # キャッシュ確認
        cached_user = get_user_from_cache(user_id)
        if cached_user:
            newrelic.agent.record_custom_metric('Custom/Cache/Hit', 1)
            return jsonify({"user": cached_user, "source": "cache"})
        
        # データベースアクセス
        with newrelic.agent.BackgroundTask(application=newrelic.agent.application(), name='get_user_db'):
            user = get_user_from_db(user_id)
            
        if user:
            # キャッシュに保存
            cache_key = f"user:{user_id}"
            redis_client.setex(cache_key, 300, str(user))
            
            newrelic.agent.record_custom_metric('Custom/Cache/Miss', 1)
            newrelic.agent.record_custom_metric('Custom/User/Retrieved', 1)
            
            return jsonify({"user": dict(user), "source": "database"})
        else:
            newrelic.agent.record_custom_metric('Custom/User/NotFound', 1)
            return jsonify({"error": "User not found"}), 404
            
    except Exception as e:
        # エラーの記録
        newrelic.agent.record_exception()
        newrelic.agent.add_custom_attribute('error_type', type(e).__name__)
        newrelic.agent.record_custom_metric('Custom/Error/Database', 1)
        
        logger.error(f"Error retrieving user {user_id}: {e}")
        return jsonify({"error": "Internal server error"}), 500

@app.route('/health')
def health_check():
    """ヘルスチェック"""
    newrelic.agent.add_custom_attribute('endpoint', 'health_check')
    
    # 外部依存関係チェック
    health_status = {
        "status": "healthy",
        "timestamp": time.time(),
        "checks": {}
    }
    
    # データベース接続確認
    try:
        with engine.connect() as conn:
            conn.execute(text("SELECT 1"))
        health_status["checks"]["database"] = "healthy"
    except Exception as e:
        health_status["checks"]["database"] = "unhealthy"
        health_status["status"] = "unhealthy"
        newrelic.agent.record_custom_metric('Custom/Health/Database/Failure', 1)
    
    # Redis接続確認
    try:
        redis_client.ping()
        health_status["checks"]["redis"] = "healthy"
    except Exception as e:
        health_status["checks"]["redis"] = "unhealthy"
        health_status["status"] = "unhealthy"
        newrelic.agent.record_custom_metric('Custom/Health/Redis/Failure', 1)
    
    newrelic.agent.record_custom_metric('Custom/Health/Check', 1)
    return jsonify(health_status)

@app.route('/api/orders', methods=['POST'])
@newrelic.agent.function_trace()
def create_order():
    """注文作成エンドポイント"""
    start_time = time.time()
    
    try:
        order_data = request.get_json()
        
        # カスタム属性
        newrelic.agent.add_custom_attribute('order_value', order_data.get('total', 0))
        newrelic.agent.add_custom_attribute('user_id', order_data.get('user_id'))
        newrelic.agent.add_custom_attribute('items_count', len(order_data.get('items', [])))
        
        # ビジネスロジック処理
        order_id = process_order(order_data)
        
        # 処理時間記録
        processing_time = time.time() - start_time
        newrelic.agent.record_custom_metric('Custom/Order/ProcessingTime', processing_time)
        newrelic.agent.record_custom_metric('Custom/Order/Created', 1)
        
        return jsonify({
            "order_id": order_id,
            "status": "created",
            "processing_time": processing_time
        }), 201
        
    except Exception as e:
        newrelic.agent.record_exception()
        newrelic.agent.record_custom_metric('Custom/Order/Failed', 1)
        return jsonify({"error": "Order creation failed"}), 500

@newrelic.agent.function_trace()
def process_order(order_data):
    """注文処理ロジック"""
    # 在庫確認
    with newrelic.agent.FunctionTrace(name='check_inventory'):
        time.sleep(0.1)  # 処理シミュレーション
    
    # 支払い処理
    with newrelic.agent.FunctionTrace(name='process_payment'):
        time.sleep(0.2)  # 処理シミュレーション
        
    # 配送手配
    with newrelic.agent.FunctionTrace(name='arrange_shipping'):
        time.sleep(0.05)  # 処理シミュレーション
    
    return "ORD-" + str(int(time.time()))

# カスタムイベント送信
@app.route('/event')
def send_custom_event():
    """カスタムイベント送信"""
    newrelic.agent.record_custom_event('CustomEvent', {
        'eventType': 'user_action',
        'action': 'button_click',
        'user_id': 12345,
        'page': '/dashboard',
        'timestamp': time.time()
    })
    
    return jsonify({"message": "Custom event sent"})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Kubernetes統合設定

# newrelic-infrastructure.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: newrelic-infra
  namespace: newrelic
  labels:
    app: newrelic-infra
spec:
  selector:
    matchLabels:
      app: newrelic-infra
  template:
    metadata:
      labels:
        app: newrelic-infra
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8001"
    spec:
      serviceAccountName: newrelic
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
      - name: newrelic-infra
        image: newrelic/infrastructure-k8s:2.13.0
        resources:
          limits:
            memory: 300M
            cpu: 150m
          requests:
            memory: 150M
            cpu: 100m
        volumeMounts:
        - mountPath: /host
          name: host-root
          readOnly: true
        - mountPath: /var/run/docker.sock
          name: host-docker-socket
        env:
        - name: NRIA_LICENSE_KEY
          valueFrom:
            secretKeyRef:
              name: newrelic-license
              key: license
        - name: NRIA_CLUSTER_NAME
          value: "production-cluster"
        - name: NRIA_DISPLAY_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: spec.nodeName
        - name: NRK8S_NODE_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: spec.nodeName
        - name: NRIA_CUSTOM_ATTRIBUTES
          value: '{"environment":"production","team":"devops"}'
        - name: NRIA_PASSTHROUGH_ENVIRONMENT
          value: "KUBERNETES_SERVICE_HOST,KUBERNETES_SERVICE_PORT,CLUSTER_NAME,CADVISOR_PORT,NRK8S_NODE_NAME,KUBE_STATE_METRICS_URL,KUBE_STATE_METRICS_POD_LABEL"
        - name: CADVISOR_PORT
          value: "4194"
        - name: KUBE_STATE_METRICS_URL
          value: "http://kube-state-metrics.kube-system.svc.cluster.local:8080"
        - name: KUBE_STATE_METRICS_POD_LABEL
          value: "app.kubernetes.io/name=kube-state-metrics"
        - name: TIMEOUT
          value: "20"
        - name: NRIA_VERBOSE
          value: "1"
      volumes:
      - name: host-root
        hostPath:
          path: /
      - name: host-docker-socket
        hostPath:
          path: /var/run/docker.sock
      tolerations:
      - effect: NoSchedule
        operator: Exists
      - effect: NoExecute
        operator: Exists

---
apiVersion: v1
kind: Secret
metadata:
  name: newrelic-license
  namespace: newrelic
type: Opaque
data:
  license: <BASE64_ENCODED_LICENSE_KEY>

ブラウザ監視設定

<!-- Browser Agent設定 -->
<!DOCTYPE html>
<html>
<head>
    <title>My Application</title>
    
    <!-- New Relic Browser Agent -->
    <script type="text/javascript">
        window.NREUM||(NREUM={});
        NREUM.loader_config={
            accountID:"YOUR_ACCOUNT_ID",
            trustKey:"YOUR_TRUST_KEY",
            agentID:"YOUR_AGENT_ID",
            licenseKey:"YOUR_LICENSE_KEY",
            applicationID:"YOUR_APP_ID"
        };
        NREUM.info={
            beacon:"bam.nr-data.net",
            errorBeacon:"bam.nr-data.net",
            sa:1
        };
    </script>
    <script src="https://js-agent.newrelic.com/nr-loader-rum-1.260.0.min.js"></script>
</head>
<body>
    <div id="app">
        <h1>My Application</h1>
        <button id="actionButton">Click Me</button>
        <div id="content"></div>
    </div>

    <script>
        // カスタムページアクション
        function trackCustomAction(actionName, attributes = {}) {
            if (typeof newrelic !== 'undefined') {
                newrelic.addPageAction(actionName, attributes);
            }
        }

        // カスタム属性追加
        function addCustomAttributes() {
            if (typeof newrelic !== 'undefined') {
                newrelic.setCustomAttribute('userType', 'premium');
                newrelic.setCustomAttribute('experimentGroup', 'A');
                newrelic.setCustomAttribute('feature_flags', JSON.stringify({
                    newDashboard: true,
                    betaFeature: false
                }));
            }
        }

        // エラー追跡
        function trackCustomError(error, attributes = {}) {
            if (typeof newrelic !== 'undefined') {
                newrelic.noticeError(error, attributes);
            }
        }

        // ユーザーアクション追跡
        document.getElementById('actionButton').addEventListener('click', function() {
            const startTime = Date.now();
            
            // APIコール
            fetch('/api/data')
                .then(response => {
                    const responseTime = Date.now() - startTime;
                    
                    trackCustomAction('api_call_completed', {
                        endpoint: '/api/data',
                        responseTime: responseTime,
                        status: response.status
                    });
                    
                    return response.json();
                })
                .then(data => {
                    document.getElementById('content').innerHTML = JSON.stringify(data);
                    
                    trackCustomAction('content_updated', {
                        dataSize: JSON.stringify(data).length
                    });
                })
                .catch(error => {
                    trackCustomError(error, {
                        context: 'api_call',
                        endpoint: '/api/data'
                    });
                });
        });

        // ページロード時の設定
        document.addEventListener('DOMContentLoaded', function() {
            addCustomAttributes();
            
            trackCustomAction('page_loaded', {
                timestamp: Date.now(),
                userAgent: navigator.userAgent
            });
        });

        // Single Page Application (SPA) ルート変更追跡
        function trackRouteChange(from, to) {
            if (typeof newrelic !== 'undefined') {
                newrelic.interaction().setName(to);
                trackCustomAction('route_change', {
                    from: from,
                    to: to,
                    timestamp: Date.now()
                });
            }
        }

        // パフォーマンス測定
        function measurePerformance(name, fn) {
            const start = performance.now();
            
            const result = fn();
            
            if (result instanceof Promise) {
                return result.finally(() => {
                    const duration = performance.now() - start;
                    trackCustomAction('custom_timing', {
                        name: name,
                        duration: duration
                    });
                });
            } else {
                const duration = performance.now() - start;
                trackCustomAction('custom_timing', {
                    name: name,
                    duration: duration
                });
                return result;
            }
        }
    </script>
</body>
</html>

Infrastructure as Code (Terraform)

# newrelic.tf
terraform {
  required_providers {
    newrelic = {
      source  = "newrelic/newrelic"
      version = "~> 3.0"
    }
  }
}

provider "newrelic" {
  account_id = var.newrelic_account_id
  api_key    = var.newrelic_api_key
  region     = "US"
}

# アプリケーション作成
resource "newrelic_application" "app" {
  name     = "My Production App"
  language = "python"

  app_apdex_threshold      = 0.5
  end_user_apdex_threshold = 7
  enable_real_user_monitoring = true
}

# アラートポリシー
resource "newrelic_alert_policy" "production_policy" {
  name                = "Production Alerts"
  incident_preference = "PER_POLICY"
}

# レスポンス時間アラート
resource "newrelic_alert_condition" "response_time" {
  policy_id = newrelic_alert_policy.production_policy.id

  name        = "High Response Time"
  type        = "apm_app_metric"
  entities    = [newrelic_application.app.id]
  metric      = "response_time_web"
  runbook_url = "https://docs.example.com/runbooks/high-response-time"

  term {
    duration      = 5
    operator      = "above"
    priority      = "critical"
    threshold     = "2.0"
    time_function = "all"
  }

  term {
    duration      = 3
    operator      = "above"
    priority      = "warning"
    threshold     = "1.0"
    time_function = "all"
  }
}

# エラー率アラート
resource "newrelic_alert_condition" "error_rate" {
  policy_id = newrelic_alert_policy.production_policy.id

  name     = "High Error Rate"
  type     = "apm_app_metric"
  entities = [newrelic_application.app.id]
  metric   = "error_percentage"

  term {
    duration      = 5
    operator      = "above"
    priority      = "critical"
    threshold     = "5.0"
    time_function = "all"
  }
}

# インフラアラート
resource "newrelic_infra_alert_condition" "high_cpu" {
  policy_id = newrelic_alert_policy.production_policy.id

  name          = "High CPU Usage"
  type          = "infra_metric"
  event         = "SystemSample"
  select        = "cpuPercent"
  comparison    = "above"
  where         = "environment = 'production'"

  critical {
    duration      = 5
    value         = 80
    time_function = "all"
  }

  warning {
    duration      = 3
    value         = 70
    time_function = "all"
  }
}

# 通知チャンネル
resource "newrelic_alert_channel" "slack" {
  name = "slack-alerts"
  type = "slack"

  config {
    url     = var.slack_webhook_url
    channel = "#alerts"
  }
}

# ポリシーとチャンネルの関連付け
resource "newrelic_alert_policy_channel" "alert_policy_slack" {
  policy_id  = newrelic_alert_policy.production_policy.id
  channel_ids = [newrelic_alert_channel.slack.id]
}

# Synthetics監視
resource "newrelic_synthetics_monitor" "website_monitor" {
  name      = "Website Monitor"
  type      = "SIMPLE"
  frequency = 5
  status    = "ENABLED"
  locations = ["AWS_US_EAST_1", "AWS_EU_WEST_1"]

  uri                       = "https://example.com"
  validation_string         = "Welcome"
  verify_ssl                = true
  bypass_head_request       = false
  treat_redirect_as_failure = false
}

# ダッシュボード
resource "newrelic_dashboard" "production_dashboard" {
  title = "Production Dashboard"

  widget {
    title         = "Response Time"
    row           = 1
    column        = 1
    width         = 1
    height        = 1
    visualization = "faceted_line_chart"

    nrql = "SELECT average(duration) FROM Transaction WHERE appName = '${newrelic_application.app.name}' TIMESERIES"
  }

  widget {
    title         = "Error Rate"
    row           = 1
    column        = 2
    width         = 1
    height        = 1
    visualization = "gauge"

    nrql = "SELECT percentage(count(*), WHERE error IS true) FROM Transaction WHERE appName = '${newrelic_application.app.name}'"

    threshold_red    = 5.0
    threshold_yellow = 2.0
  }

  widget {
    title         = "Throughput"
    row           = 2
    column        = 1
    width         = 2
    height        = 1
    visualization = "line_chart"

    nrql = "SELECT rate(count(*), 1 minute) FROM Transaction WHERE appName = '${newrelic_application.app.name}' TIMESERIES"
  }
}

# カスタムイベント用のWorkflow
resource "newrelic_workflow" "production_workflow" {
  name                = "Production Incident Workflow"
  muting_rules_handling = "NOTIFY_ALL_ISSUES"

  issues_filter {
    name = "Filter-name"
    type = "FILTER"

    predicate {
      attribute = "labels.policyIds"
      operator  = "EXACTLY_MATCHES"
      values    = [newrelic_alert_policy.production_policy.id]
    }
  }

  destination {
    channel_id = newrelic_alert_channel.slack.id
  }
}