SiamCafe.net Blog
Cybersecurity

WordPress WooCommerce Log Management ELK — ระบบจัดการ Log ด้วย Elasticsearch Logstash Kibana

wordpress woocommerce log management elk
WordPress WooCommerce Log Management ELK | SiamCafe Blog
2026-04-21· อ. บอม — SiamCafe.net· 1,251 คำ

ทำไมต้องใช้ ELK Stack จัดการ Log ของ WooCommerce

WooCommerce สร้าง log หลายประเภทเช่น order log, payment gateway log, shipping log, error log และ debug log ปัญหาคือ log เหล่านี้กระจายอยู่หลายที่ทั้งใน wp-content/debug.log, wc-logs directory และ database ทำให้ยากต่อการค้นหาและวิเคราะห์เมื่อเกิดปัญหา

ELK Stack ประกอบด้วย Elasticsearch สำหรับจัดเก็บและค้นหา log, Logstash สำหรับ parse และ transform log data และ Kibana สำหรับ visualize ข้อมูล เมื่อรวมกับ Filebeat ที่ทำหน้าที่เก็บ log จาก server แล้วส่งมายัง pipeline จะได้ระบบ centralized log management ที่ครบวงจร

ประโยชน์ของการใช้ ELK กับ WooCommerce ได้แก่ ค้นหา log ได้ภายในวินาทีแม้มี log หลายล้าน records, สร้าง dashboard แสดง real-time order analytics, ตั้ง alert เมื่อ payment failure เพิ่มขึ้นผิดปกติ, วิเคราะห์ performance bottleneck จาก slow query log และ ตรวจจับ security threats จาก access log

สถาปัตยกรรมของระบบประกอบด้วย WordPress/WooCommerce Server ที่ติดตั้ง Filebeat, Logstash Server ที่รับและ parse log, Elasticsearch Cluster ที่เก็บข้อมูล และ Kibana ที่แสดงผล

ติดตั้ง ELK Stack ด้วย Docker Compose

ติดตั้ง Elasticsearch, Logstash และ Kibana ด้วย Docker Compose สำหรับ production environment

# docker-compose-elk.yml
version: "3.9"
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
    container_name: elasticsearch
    environment:
      - node.name=es01
      - cluster.name=woocommerce-logs
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.enrollment.enabled=true
      - ELASTIC_PASSWORD=
      - "ES_JAVA_OPTS=-Xms2g -Xmx2g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - es_data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"
    healthcheck:
      test: ["CMD-SHELL", "curl -s -u elastic: http://localhost:9200/_cluster/health | grep -q green"]
      interval: 30s
      timeout: 10s
      retries: 5
    networks:
      - elk

  logstash:
    image: docker.elastic.co/logstash/logstash:8.13.0
    container_name: logstash
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
    ports:
      - "5044:5044"
      - "5000:5000"
    environment:
      - "LS_JAVA_OPTS=-Xms1g -Xmx1g"
      - ELASTIC_PASSWORD=
    depends_on:
      elasticsearch:
        condition: service_healthy
    networks:
      - elk

  kibana:
    image: docker.elastic.co/kibana/kibana:8.13.0
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=
      - xpack.security.enabled=true
    ports:
      - "5601:5601"
    depends_on:
      elasticsearch:
        condition: service_healthy
    networks:
      - elk

volumes:
  es_data:

networks:
  elk:
    driver: bridge

# .env
# ELASTIC_PASSWORD=your-elastic-password
# KIBANA_PASSWORD=your-kibana-password

# เริ่มต้นระบบ
# docker compose -f docker-compose-elk.yml up -d

# ตรวจสอบ Elasticsearch
# curl -u elastic:$ELASTIC_PASSWORD http://localhost:9200/_cluster/health?pretty

# ตั้งค่า kibana_system password
# curl -X POST -u elastic:$ELASTIC_PASSWORD \
#   "http://localhost:9200/_security/user/kibana_system/_password" \
#   -H "Content-Type: application/json" \
#   -d '{"password":"your-kibana-password"}'

ตั้งค่า Filebeat เก็บ Log จาก WordPress และ WooCommerce

ติดตั้ง Filebeat บน WordPress Server เพื่อเก็บ log ทั้งหมดแล้วส่งไปยัง Logstash

# ติดตั้ง Filebeat บน Ubuntu
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elastic-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elastic-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update && sudo apt install filebeat -y

# /etc/filebeat/filebeat.yml
filebeat.inputs:
  # WordPress Debug Log
  - type: log
    id: wordpress-debug
    enabled: true
    paths:
      - /var/www/html/wp-content/debug.log
    fields:
      log_type: wordpress_debug
    multiline.pattern: '^\['
    multiline.negate: true
    multiline.match: after

  # WooCommerce Logs
  - type: log
    id: woocommerce-logs
    enabled: true
    paths:
      - /var/www/html/wp-content/uploads/wc-logs/*.log
    fields:
      log_type: woocommerce
    multiline.pattern: '^\d{4}-\d{2}-\d{2}'
    multiline.negate: true
    multiline.match: after

  # Apache/Nginx Access Log
  - type: log
    id: webserver-access
    enabled: true
    paths:
      - /var/log/nginx/access.log
      - /var/log/apache2/access.log
    fields:
      log_type: webserver_access

  # Apache/Nginx Error Log
  - type: log
    id: webserver-error
    enabled: true
    paths:
      - /var/log/nginx/error.log
      - /var/log/apache2/error.log
    fields:
      log_type: webserver_error

  # PHP-FPM Log
  - type: log
    id: php-fpm
    enabled: true
    paths:
      - /var/log/php*-fpm.log
    fields:
      log_type: php_fpm

  # MySQL Slow Query Log
  - type: log
    id: mysql-slow
    enabled: true
    paths:
      - /var/log/mysql/mysql-slow.log
    fields:
      log_type: mysql_slow
    multiline.pattern: '^# Time:|^# User@Host:'
    multiline.negate: true
    multiline.match: after

output.logstash:
  hosts: ["logstash-server:5044"]
  ssl.enabled: false

processors:
  - add_host_metadata: ~
  - add_fields:
      target: ''
      fields:
        environment: production
        site: woocommerce-shop

# เริ่มต้น Filebeat
sudo systemctl enable filebeat
sudo systemctl start filebeat

# ตรวจสอบสถานะ
sudo filebeat test config
sudo filebeat test output
sudo systemctl status filebeat

สร้าง Logstash Pipeline สำหรับ Parse WooCommerce Log

สร้าง Logstash Pipeline ที่ parse log จาก WooCommerce ให้เป็น structured data

# logstash/pipeline/woocommerce.conf
input {
  beats {
    port => 5044
  }
}

filter {
  # Parse WooCommerce Log
  if [fields][log_type] == "woocommerce" {
    grok {
      match => {
        "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:log_level} %{GREEDYDATA:wc_message}"
      }
    }
    date {
      match => ["timestamp", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd HH:mm:ss"]
      target => "@timestamp"
    }
    
    # Extract payment gateway info
    if "payment" in [wc_message] or "PayPal" in [wc_message] or "Stripe" in [wc_message] {
      mutate {
        add_tag => ["payment"]
        add_field => { "category" => "payment" }
      }
      grok {
        match => {
          "wc_message" => "Order #%{NUMBER:order_id}.*%{WORD:payment_gateway}"
        }
        tag_on_failure => []
      }
    }
    
    # Extract order info
    if "order" in [wc_message] {
      grok {
        match => {
          "wc_message" => "Order #%{NUMBER:order_id}.*status changed from %{WORD:old_status} to %{WORD:new_status}"
        }
        tag_on_failure => []
      }
    }
  }

  # Parse WordPress Debug Log
  if [fields][log_type] == "wordpress_debug" {
    grok {
      match => {
        "message" => "\[%{HTTPDATE:timestamp}\] PHP %{DATA:php_error_type}: %{GREEDYDATA:error_message} in %{DATA:file} on line %{NUMBER:line_number}"
      }
    }
    date {
      match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
      target => "@timestamp"
    }
  }

  # Parse Nginx Access Log
  if [fields][log_type] == "webserver_access" {
    grok {
      match => {
        "message" => '%{IPORHOST:client_ip} - %{DATA:user} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{URIPATHPARAM:request} HTTP/%{NUMBER:http_version}" %{NUMBER:response_code} %{NUMBER:bytes} "%{DATA:referrer}" "%{DATA:user_agent}"'
      }
    }
    date {
      match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
      target => "@timestamp"
    }
    
    # GeoIP lookup
    geoip {
      source => "client_ip"
      target => "geoip"
    }
    
    # Identify WooCommerce API calls
    if "/wp-json/wc/" in [request] or "/wc-api/" in [request] {
      mutate {
        add_tag => ["wc_api"]
        add_field => { "category" => "wc_api" }
      }
    }
    
    # Identify checkout pages
    if "/checkout" in [request] or "/cart" in [request] {
      mutate {
        add_tag => ["checkout_flow"]
      }
    }
    
    useragent {
      source => "user_agent"
      target => "ua"
    }
  }

  # Parse MySQL Slow Query Log
  if [fields][log_type] == "mysql_slow" {
    grok {
      match => {
        "message" => "# Query_time: %{NUMBER:query_time} Lock_time: %{NUMBER:lock_time} Rows_sent: %{NUMBER:rows_sent} Rows_examined: %{NUMBER:rows_examined}"
      }
    }
    mutate {
      convert => {
        "query_time" => "float"
        "lock_time" => "float"
        "rows_sent" => "integer"
        "rows_examined" => "integer"
      }
    }
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    user => "elastic"
    password => ""
    index => "woocommerce-%{[fields][log_type]}-%{+YYYY.MM.dd}"
  }
}

สร้าง Kibana Dashboard สำหรับ WooCommerce Analytics

สร้าง Index Pattern และ Dashboard ใน Kibana

# สร้าง Index Pattern ผ่าน API
curl -X POST -u elastic:$ELASTIC_PASSWORD \
  "http://localhost:5601/api/saved_objects/index-pattern/woocommerce-*" \
  -H "kbn-xsrf: true" \
  -H "Content-Type: application/json" \
  -d '{
    "attributes": {
      "title": "woocommerce-*",
      "timeFieldName": "@timestamp"
    }
  }'

# สร้าง ILM Policy สำหรับจัดการ index lifecycle
curl -X PUT -u elastic:$ELASTIC_PASSWORD \
  "http://localhost:9200/_ilm/policy/woocommerce-log-policy" \
  -H "Content-Type: application/json" \
  -d '{
    "policy": {
      "phases": {
        "hot": {
          "actions": {
            "rollover": {
              "max_size": "10gb",
              "max_age": "7d"
            }
          }
        },
        "warm": {
          "min_age": "7d",
          "actions": {
            "shrink": {"number_of_shards": 1},
            "forcemerge": {"max_num_segments": 1}
          }
        },
        "cold": {
          "min_age": "30d",
          "actions": {
            "freeze": {}
          }
        },
        "delete": {
          "min_age": "90d",
          "actions": {
            "delete": {}
          }
        }
      }
    }
  }'

# Elasticsearch Queries สำหรับ WooCommerce Analytics

# 1. นับ Orders ต่อวัน
curl -s -u elastic:$ELASTIC_PASSWORD \
  "http://localhost:9200/woocommerce-woocommerce-*/_search" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 0,
    "query": {
      "bool": {
        "must": [
          {"exists": {"field": "order_id"}},
          {"match": {"new_status": "completed"}}
        ]
      }
    },
    "aggs": {
      "orders_per_day": {
        "date_histogram": {
          "field": "@timestamp",
          "calendar_interval": "day"
        }
      }
    }
  }' | python3 -m json.tool

# 2. Top Payment Errors
curl -s -u elastic:$ELASTIC_PASSWORD \
  "http://localhost:9200/woocommerce-woocommerce-*/_search" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 0,
    "query": {
      "bool": {
        "must": [
          {"term": {"category": "payment"}},
          {"term": {"log_level": "ERROR"}}
        ]
      }
    },
    "aggs": {
      "by_gateway": {
        "terms": {"field": "payment_gateway.keyword", "size": 10}
      }
    }
  }'

ตั้งค่า Alert เมื่อพบ Error หรือ Suspicious Activity

ใช้ Elasticsearch Watcher หรือ Kibana Alerting สร้าง alert สำหรับ WooCommerce

# สร้าง Watcher Alert สำหรับ Payment Failure Spike
curl -X PUT -u elastic:$ELASTIC_PASSWORD \
  "http://localhost:9200/_watcher/watch/payment_failure_alert" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger": {
      "schedule": {"interval": "5m"}
    },
    "input": {
      "search": {
        "request": {
          "indices": ["woocommerce-woocommerce-*"],
          "body": {
            "size": 0,
            "query": {
              "bool": {
                "must": [
                  {"term": {"category": "payment"}},
                  {"term": {"log_level": "ERROR"}},
                  {"range": {"@timestamp": {"gte": "now-15m"}}}
                ]
              }
            }
          }
        }
      }
    },
    "condition": {
      "compare": {"ctx.payload.hits.total.value": {"gt": 10}}
    },
    "actions": {
      "notify_slack": {
        "webhook": {
          "scheme": "https",
          "host": "hooks.slack.com",
          "port": 443,
          "method": "post",
          "path": "/services/xxx/yyy/zzz",
          "body": "{\"text\":\"ALERT: {{ctx.payload.hits.total.value}} payment failures in last 15 minutes\"}"
        }
      }
    }
  }'

# Alert สำหรับ High Error Rate
curl -X PUT -u elastic:$ELASTIC_PASSWORD \
  "http://localhost:9200/_watcher/watch/high_error_rate" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger": {
      "schedule": {"interval": "10m"}
    },
    "input": {
      "search": {
        "request": {
          "indices": ["woocommerce-webserver_access-*"],
          "body": {
            "size": 0,
            "query": {
              "bool": {
                "must": [
                  {"range": {"response_code": {"gte": 500}}},
                  {"range": {"@timestamp": {"gte": "now-10m"}}}
                ]
              }
            }
          }
        }
      }
    },
    "condition": {
      "compare": {"ctx.payload.hits.total.value": {"gt": 50}}
    },
    "actions": {
      "send_email": {
        "email": {
          "to": ["admin@example.com"],
          "subject": "WooCommerce High 5xx Error Rate",
          "body": {
            "text": "{{ctx.payload.hits.total.value}} 5xx errors in last 10 minutes"
          }
        }
      }
    }
  }'

FAQ คำถามที่พบบ่อย

Q: ELK Stack ต้องใช้ resource เท่าไหร่?

A: สำหรับ WooCommerce ขนาดเล็กถึงกลาง (ไม่เกิน 1000 orders/วัน) Elasticsearch ต้องการ RAM อย่างน้อย 4GB, Logstash 2GB และ Kibana 1GB รวมแล้ว server ควรมี RAM อย่างน้อย 8GB สำหรับ store ขนาดใหญ่อาจต้องการ Elasticsearch cluster หลาย node

Q: ใช้ Loki แทน ELK ได้ไหม?

A: ได้ Grafana Loki เป็นทางเลือกที่เบากว่ามาก ใช้ resource น้อยกว่า ELK และตั้งค่าง่ายกว่า เหมาะสำหรับ store ขนาดเล็กที่ไม่ต้องการ full-text search แต่ถ้าต้องการ complex query, aggregation และ visualization ที่หลากหลาย ELK ยังเป็นตัวเลือกที่ดีกว่า

Q: Filebeat กับ Fluentd ต่างกันอย่างไร?

A: Filebeat เขียนด้วย Go เบาและใช้ resource น้อย เหมาะเป็น log shipper ที่ส่ง log ไปยัง Logstash หรือ Elasticsearch ส่วน Fluentd เป็น log aggregator ที่มี plugin ecosystem ใหญ่กว่า สามารถ parse และ route log ได้เอง ถ้าใช้ ELK Stack แนะนำ Filebeat เพราะ integrate ได้ดีที่สุด

Q: ควรเก็บ WooCommerce log ไว้นานแค่ไหน?

A: ขึ้นอยู่กับข้อกำหนดทางกฎหมายและ storage budget โดยทั่วไปแนะนำเก็บ access log 90 วัน, error log 180 วัน และ payment log 1 ปี (ตาม PCI DSS requirement) ใช้ ILM Policy ของ Elasticsearch จัดการ lifecycle อัตโนมัติเพื่อย้ายข้อมูลเก่าไป cold storage หรือลบทิ้ง

📖 บทความที่เกี่ยวข้อง

Redis Pub Sub Log Management ELKอ่านบทความ → Azure Front Door Log Management ELKอ่านบทความ → Model Registry Log Management ELKอ่านบทความ → CSS Nesting Log Management ELKอ่านบทความ → WordPress WooCommerce Cloud Migration Strategyอ่านบทความ →

📚 ดูบทความทั้งหมด →