Datadog

クラウドネイティブ環境向けの統合監視・可視化プラットフォーム。APM、インフラ監視、ログ管理、セキュリティ監視を一元化。機械学習による異常検知機能。

監視サーバーSaaS監視APMインフラ監視機械学習クラウドネイティブ統合監視

監視サーバー

Datadog

概要

Datadogはクラウドネイティブ環境向けの統合監視・可視化プラットフォームです。APM、インフラ監視、ログ管理、セキュリティ監視を一元化し、機械学習による異常検知機能を提供します。SaaS監視市場でリーダーポジションを維持し、年間売上20億ドル超、Fortune 500企業の多くが採用するAI・機械学習統合の次世代監視プラットフォームです。

詳細

Datadogは2010年にOlivier Pomelらによって設立され、現在ではSaaS監視市場でリーダーポジションを維持しています。年間売上20億ドル超、Fortune 500企業の多くが採用し、AI・機械学習統合で次世代監視プラットフォームに進化を続けています。クラウドファースト戦略により継続的な成長を遂げ、統合監視ソリューションの業界標準として確立されています。

主要な技術的特徴

  • 統合監視プラットフォーム: インフラ、APM、ログ、セキュリティの一元管理
  • 機械学習統合: AI支援による異常検知と予測分析
  • クラウドネイティブ対応: AWS、Azure、GCP等主要クラウドとの深い統合
  • リアルタイム監視: 高頻度メトリクス収集と即座のアラート
  • 豊富なインテグレーション: 800+のサービス・ツール統合

用途

  • クラウドインフラ監視
  • アプリケーション性能監視(APM)
  • ログ管理と分析
  • セキュリティ監視とSIEM
  • ビジネスメトリクス可視化

メリット・デメリット

メリット

  • 統合プラットフォーム: 全領域をカバーする統一ソリューション
  • AI/ML機能: 機械学習による高度な異常検知
  • 豊富なインテグレーション: 800+のサービス統合
  • スケーラビリティ: エンタープライズ規模での高い信頼性
  • ユーザビリティ: 直感的なUI/UXと高い操作性
  • 24/7サポート: 充実したサポート体制

デメリット

  • 高コスト: エンタープライズ向けの高額な料金体系
  • ベンダーロックイン: SaaSプラットフォームへの依存
  • 学習コスト: 豊富な機能による習得の複雑さ
  • データ主権: クラウドベースによるデータ管理の制約
  • カスタマイズ制限: SaaSによるカスタマイズの限界

参考ページ

書き方の例

Datadog Agent設定

# datadog.yaml
api_key: YOUR_API_KEY_HERE
site: datadoghq.com

# ホスト名設定
hostname: web-server-01
hostname_fqdn: web-server-01.example.com

# タグ設定
tags:
  - env:production
  - service:web
  - team:backend
  - region:us-east-1

# ログ収集設定
logs_enabled: true
logs_config:
  container_collect_all: true
  use_http: true
  compression_level: 6

# APM設定
apm_config:
  enabled: true
  receiver_port: 8126
  max_traces_per_second: 10

# プロセス監視
process_config:
  enabled: true
  scrub_args: true

# Network Performance Monitoring
network_config:
  enabled: true

# システムプローブ
system_probe_config:
  enabled: true

# 収集間隔
check_runners: 4
collection_timeout: 30

# プロキシ設定
proxy:
  http: http://proxy.example.com:8080
  https: https://proxy.example.com:8080
  no_proxy:
    - localhost
    - 127.0.0.1

# JMX設定
jmx_use_cgroup_memory_limit: true

# Security Agent
security_agent:
  enabled: true
  
# Remote Configuration
remote_configuration:
  enabled: true

カスタムメトリクス送信

# custom_metrics.py
from datadog import initialize, api, statsd
import time
import psutil
import requests

# Datadog初期化
options = {
    'api_key': 'YOUR_API_KEY',
    'app_key': 'YOUR_APP_KEY'
}
initialize(**options)

class CustomMetricsCollector:
    def __init__(self):
        self.statsd = statsd
        
    def collect_system_metrics(self):
        """システムメトリクス収集"""
        # CPU使用率
        cpu_percent = psutil.cpu_percent(interval=1)
        self.statsd.gauge('custom.system.cpu_percent', cpu_percent, 
                         tags=['host:web-01', 'env:prod'])
        
        # メモリ使用率
        memory = psutil.virtual_memory()
        self.statsd.gauge('custom.system.memory_percent', memory.percent,
                         tags=['host:web-01', 'env:prod'])
        
        # ディスク使用率
        disk = psutil.disk_usage('/')
        disk_percent = (disk.used / disk.total) * 100
        self.statsd.gauge('custom.system.disk_percent', disk_percent,
                         tags=['host:web-01', 'env:prod'])
        
    def collect_application_metrics(self):
        """アプリケーションメトリクス収集"""
        # API レスポンス時間測定
        start_time = time.time()
        try:
            response = requests.get('http://localhost:8080/health', timeout=5)
            response_time = (time.time() - start_time) * 1000
            
            self.statsd.histogram('custom.api.response_time', response_time,
                                tags=['endpoint:health', 'env:prod'])
            
            # ステータスコード
            self.statsd.increment('custom.api.requests',
                                tags=[f'status_code:{response.status_code}', 'env:prod'])
            
        except requests.RequestException as e:
            self.statsd.increment('custom.api.errors',
                                tags=['error_type:timeout', 'env:prod'])
    
    def send_custom_event(self, title, text, alert_type='info'):
        """カスタムイベント送信"""
        api.Event.create(
            title=title,
            text=text,
            alert_type=alert_type,
            tags=['custom:event', 'env:prod']
        )
    
    def run_continuous_monitoring(self):
        """継続的監視実行"""
        while True:
            try:
                self.collect_system_metrics()
                self.collect_application_metrics()
                time.sleep(60)  # 1分間隔
            except Exception as e:
                print(f"Monitoring error: {e}")
                time.sleep(60)

if __name__ == "__main__":
    collector = CustomMetricsCollector()
    collector.run_continuous_monitoring()

Docker統合設定

# docker-compose.yml
version: '3.8'

services:
  datadog-agent:
    image: gcr.io/datadoghq/agent:7
    container_name: datadog-agent
    restart: unless-stopped
    environment:
      - DD_API_KEY=${DD_API_KEY}
      - DD_SITE=datadoghq.com
      - DD_LOGS_ENABLED=true
      - DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL=true
      - DD_APM_ENABLED=true
      - DD_APM_NON_LOCAL_TRAFFIC=true
      - DD_PROCESS_AGENT_ENABLED=true
      - DD_SYSTEM_PROBE_ENABLED=true
      - DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true
      - DD_AC_EXCLUDE=image:gcr.io/datadoghq/agent
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /proc/:/host/proc/:ro
      - /opt/datadog-agent/run:/opt/datadog-agent/run:rw
      - /sys/fs/cgroup/:/host/sys/fs/cgroup:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /etc/passwd:/etc/passwd:ro
      - ./datadog.yaml:/etc/datadog-agent/datadog.yaml:ro
      - ./conf.d:/etc/datadog-agent/conf.d:ro
    ports:
      - "8125:8125/udp"  # DogStatsD
      - "8126:8126"      # APM
    cap_add:
      - SYS_ADMIN
      - SYS_RESOURCE
      - SYS_PTRACE
      - NET_ADMIN
      - NET_BROADCAST
      - NET_RAW
      - IPC_LOCK
    security_opt:
      - apparmor:unconfined
    networks:
      - monitoring

  webapp:
    image: nginx:alpine
    container_name: webapp
    labels:
      - "com.datadoghq.ad.check_names=[\"nginx\"]"
      - "com.datadoghq.ad.init_configs=[{}]"
      - "com.datadoghq.ad.instances=[{\"nginx_status_url\":\"http://%%host%%:81/nginx_status\"}]"
      - "com.datadoghq.ad.logs=[{\"source\":\"nginx\",\"service\":\"webapp\"}]"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "80:80"
      - "81:81"
    networks:
      - monitoring

networks:
  monitoring:
    driver: bridge

Kubernetes統合設定

# datadog-agent.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: datadog-agent
  namespace: datadog
spec:
  selector:
    matchLabels:
      app: datadog-agent
  template:
    metadata:
      labels:
        app: datadog-agent
      name: datadog-agent
    spec:
      serviceAccountName: datadog-agent
      containers:
      - image: gcr.io/datadoghq/agent:7
        imagePullPolicy: Always
        name: datadog-agent
        ports:
        - containerPort: 8125
          name: dogstatsdport
          protocol: UDP
        - containerPort: 8126
          name: traceport
          protocol: TCP
        env:
        - name: DD_API_KEY
          valueFrom:
            secretKeyRef:
              name: datadog-secret
              key: api-key
        - name: DD_CLUSTER_NAME
          value: "production-cluster"
        - name: DD_SITE
          value: "datadoghq.com"
        - name: DD_LOGS_ENABLED
          value: "true"
        - name: DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL
          value: "true"
        - name: DD_APM_ENABLED
          value: "true"
        - name: DD_APM_NON_LOCAL_TRAFFIC
          value: "true"
        - name: DD_PROCESS_AGENT_ENABLED
          value: "true"
        - name: DD_KUBERNETES_KUBELET_HOST
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: KUBERNETES
          value: "true"
        - name: DD_HEALTH_PORT
          value: "5555"
        - name: DD_DOGSTATSD_NON_LOCAL_TRAFFIC
          value: "true"
        resources:
          requests:
            memory: "256Mi"
            cpu: "200m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        volumeMounts:
        - name: dockersocket
          mountPath: /var/run/docker.sock
        - name: procdir
          mountPath: /host/proc
          readOnly: true
        - name: cgroups
          mountPath: /host/sys/fs/cgroup
          readOnly: true
        - name: config
          mountPath: /etc/datadog-agent
        livenessProbe:
          httpGet:
            path: /health
            port: 5555
          initialDelaySeconds: 15
          periodSeconds: 15
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health
            port: 5555
          initialDelaySeconds: 15
          periodSeconds: 15
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
      volumes:
      - hostPath:
          path: /var/run/docker.sock
        name: dockersocket
      - hostPath:
          path: /proc
        name: procdir
      - hostPath:
          path: /sys/fs/cgroup
        name: cgroups
      - configMap:
          name: datadog-config
        name: config

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: datadog-config
  namespace: datadog
data:
  datadog.yaml: |
    api_key: ${DD_API_KEY}
    site: datadoghq.com
    logs_enabled: true
    apm_config:
      enabled: true
    process_config:
      enabled: true
    kubernetes_kubelet_host: ${DD_KUBERNETES_KUBELET_HOST}
    
    tags:
      - cluster:production
      - env:prod

アラート設定(Terraform)

# alerts.tf
terraform {
  required_providers {
    datadog = {
      source = "DataDog/datadog"
      version = "~> 3.0"
    }
  }
}

provider "datadog" {
  api_key = var.datadog_api_key
  app_key = var.datadog_app_key
  api_url = "https://api.datadoghq.com/"
}

# CPU使用率アラート
resource "datadog_monitor" "high_cpu" {
  name         = "High CPU Usage"
  type         = "metric alert"
  message      = <<-EOF
    CPU usage is above 80% for more than 5 minutes
    @slack-alerts
    @pagerduty-team
  EOF
  
  query = "avg(last_5m):avg:system.cpu.user{env:production} by {host} > 80"
  
  monitor_thresholds {
    critical = 80
    warning  = 70
  }
  
  notify_no_data    = true
  no_data_timeframe = 10
  
  tags = ["team:sre", "env:production", "service:system"]
}

# APMエラー率アラート
resource "datadog_monitor" "high_error_rate" {
  name    = "High Error Rate"
  type    = "metric alert"
  message = <<-EOF
    Error rate is above 5% for service {{service.name}}
    @slack-alerts
  EOF
  
  query = "avg(last_10m):sum:trace.web.request.errors{env:production} by {service}.as_rate() / sum:trace.web.request.hits{env:production} by {service}.as_rate() > 0.05"
  
  monitor_thresholds {
    critical = 0.05
    warning  = 0.03
  }
  
  tags = ["team:backend", "env:production", "service:apm"]
}

# ログベースアラート
resource "datadog_monitor" "error_logs" {
  name    = "Error Log Spike"
  type    = "log alert"
  message = "Error log count is unusually high @slack-alerts"
  
  query = "logs(\"status:error env:production\").index(\"*\").rollup(\"count\").last(\"15m\") > 100"
  
  monitor_thresholds {
    critical = 100
    warning  = 50
  }
  
  tags = ["team:sre", "env:production", "service:logs"]
}

# 外形監視
resource "datadog_synthetics_test" "api_test" {
  type      = "api"
  subtype   = "http"
  name      = "API Health Check"
  message   = "API endpoint is down @slack-alerts"
  
  locations = ["aws:us-east-1", "aws:eu-west-1"]
  
  options_list {
    tick_every = 60
    
    retry {
      count    = 2
      interval = 300
    }
    
    monitor_options {
      renotify_interval = 120
    }
  }
  
  request_definition {
    method = "GET"
    url    = "https://api.example.com/health"
    
    assertion {
      type     = "statusCode"
      operator = "is"
      target   = "200"
    }
    
    assertion {
      type     = "responseTime"
      operator = "lessThan"
      target   = "2000"
    }
  }
  
  tags = ["team:api", "env:production", "service:synthetics"]
}

ダッシュボード設定

{
  "title": "Infrastructure Overview",
  "description": "Main infrastructure monitoring dashboard",
  "widgets": [
    {
      "id": 1,
      "definition": {
        "type": "timeseries",
        "requests": [
          {
            "q": "avg:system.cpu.user{env:production} by {host}",
            "display_type": "line",
            "style": {
              "palette": "dog_classic",
              "line_type": "solid",
              "line_width": "normal"
            }
          }
        ],
        "title": "CPU Usage by Host",
        "title_size": "16",
        "title_align": "left",
        "yaxis": {
          "label": "Percentage",
          "scale": "linear",
          "min": "auto",
          "max": "auto"
        }
      },
      "layout": {
        "x": 0,
        "y": 0,
        "width": 47,
        "height": 15
      }
    },
    {
      "id": 2,
      "definition": {
        "type": "query_value",
        "requests": [
          {
            "q": "avg:system.mem.pct_usable{env:production}",
            "aggregator": "avg"
          }
        ],
        "title": "Average Memory Usage",
        "title_size": "16",
        "title_align": "left",
        "precision": 2,
        "unit": "%"
      },
      "layout": {
        "x": 48,
        "y": 0,
        "width": 23,
        "height": 15
      }
    },
    {
      "id": 3,
      "definition": {
        "type": "toplist",
        "requests": [
          {
            "q": "top(avg:trace.web.request.duration{env:production} by {service}, 10, 'mean', 'desc')"
          }
        ],
        "title": "Slowest Services",
        "title_size": "16",
        "title_align": "left"
      },
      "layout": {
        "x": 72,
        "y": 0,
        "width": 47,
        "height": 15
      }
    },
    {
      "id": 4,
      "definition": {
        "type": "log_stream",
        "query": "status:error env:production",
        "columns": [
          "host",
          "service",
          "@timestamp",
          "message"
        ],
        "title": "Error Logs",
        "title_size": "16",
        "title_align": "left",
        "message_display": "expanded-md",
        "sort": {
          "column": "@timestamp",
          "order": "desc"
        }
      },
      "layout": {
        "x": 0,
        "y": 16,
        "width": 119,
        "height": 36
      }
    }
  ],
  "template_variables": [
    {
      "name": "env",
      "default": "production",
      "prefix": "env"
    },
    {
      "name": "service",
      "default": "*",
      "prefix": "service"
    }
  ],
  "layout_type": "ordered",
  "is_read_only": false,
  "notify_list": [],
  "reflow_type": "fixed",
  "tags": ["team:sre", "env:production"]
}

アプリケーション統合(Python)

# app_integration.py
from ddtrace import tracer, patch
from ddtrace.contrib.flask import TraceMiddleware
from datadog import DogStatsdClient
import logging
import time
from flask import Flask, request

# トレーシング設定
patch(sqlalchemy=True, requests=True, redis=True)

# メトリクス設定
statsd = DogStatsdClient(host='localhost', port=8125)

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

app = Flask(__name__)
traced_app = TraceMiddleware(app, tracer, service="web-app")

@app.before_request
def before_request():
    request.start_time = time.time()
    
    # リクエストメトリクス
    statsd.increment('web.request.count', 
                    tags=[f'endpoint:{request.endpoint}', 'env:production'])

@app.after_request
def after_request(response):
    # レスポンス時間
    response_time = (time.time() - request.start_time) * 1000
    statsd.histogram('web.request.duration', response_time,
                    tags=[f'endpoint:{request.endpoint}', 
                          f'status_code:{response.status_code}'])
    
    # ステータスコード
    statsd.increment('web.response.count',
                    tags=[f'status_code:{response.status_code}'])
    
    return response

@tracer.wrap('database', service='db')
def get_user_data(user_id):
    """データベースアクセスのトレーシング"""
    with tracer.trace('db.query', service='postgresql') as span:
        span.set_tag('user.id', user_id)
        span.set_tag('db.operation', 'select')
        
        # DBアクセスシミュレーション
        time.sleep(0.01)
        return {"user_id": user_id, "name": "Test User"}

@app.route('/health')
def health_check():
    """ヘルスチェックエンドポイント"""
    return {"status": "healthy", "timestamp": time.time()}

@app.route('/user/<int:user_id>')
def get_user(user_id):
    """ユーザー情報取得"""
    try:
        with tracer.trace('user.get', service='web-app') as span:
            span.set_tag('user.id', user_id)
            
            user_data = get_user_data(user_id)
            
            logger.info(f"User data retrieved", extra={
                'user_id': user_id,
                'dd.trace_id': span.trace_id,
                'dd.span_id': span.span_id
            })
            
            return user_data
            
    except Exception as e:
        statsd.increment('web.error.count', 
                        tags=['error_type:user_not_found'])
        logger.error(f"Error retrieving user: {e}", extra={
            'user_id': user_id,
            'error': str(e)
        })
        return {"error": "User not found"}, 404

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