WordPress WooCommerce Post-mortem Analysis คืออะไร
WordPress WooCommerce เป็น e-commerce platform ยอดนิยมที่ขับเคลื่อนร้านค้าออนไลน์กว่า 5 ล้านเว็บไซต์ทั่วโลก Post-mortem Analysis คือกระบวนการวิเคราะห์หลังเกิดเหตุการณ์ (incident) เพื่อหา root cause ป้องกันไม่ให้เกิดซ้ำ สำหรับ WooCommerce incidents อาจรวมถึง site downtime, checkout failures, payment gateway errors, performance degradation และ security breaches บทความนี้อธิบายวิธีทำ post-mortem สำหรับ WooCommerce อย่างเป็นระบบ พร้อม Python tools สำหรับวิเคราะห์ logs และ metrics
Common WooCommerce Incidents
# woo_incidents.py — Common WooCommerce incidents
import json
class WooCommerceIncidents:
INCIDENTS = {
"checkout_failure": {
"name": "Checkout Failure",
"severity": "P1 — Critical",
"symptoms": "ลูกค้าไม่สามารถชำระเงินได้ — abandoned carts เพิ่มขึ้นผิดปกติ",
"common_causes": [
"Payment gateway API down หรือ credentials expired",
"SSL certificate expired — mixed content errors",
"Plugin conflict — checkout JS errors",
"WooCommerce session timeout — cart หาย",
],
},
"performance_degradation": {
"name": "Performance Degradation",
"severity": "P2 — High",
"symptoms": "Page load > 5 วินาที, TTFB > 2 วินาที, conversion rate ลดลง",
"common_causes": [
"Database queries ช้า — ไม่มี index, autoload options bloated",
"Plugin ทำ external API calls ทุก page load",
"Image optimization ไม่ดี — ไม่มี lazy loading/WebP",
"Hosting resources ไม่พอ — RAM, CPU spike",
],
},
"security_breach": {
"name": "Security Breach",
"severity": "P1 — Critical",
"symptoms": "Malware injection, admin access unauthorized, customer data leak",
"common_causes": [
"Outdated WordPress/WooCommerce/plugins — known vulnerabilities",
"Weak admin passwords — brute force attack",
"Nulled/pirated themes/plugins — backdoors",
"SQL injection ผ่าน vulnerable plugin",
],
},
"inventory_sync": {
"name": "Inventory Sync Failure",
"severity": "P2 — High",
"symptoms": "Stock ไม่ตรง — overselling, out-of-stock แต่ยังขายได้",
"common_causes": [
"Webhook failures ระหว่าง WooCommerce กับ ERP/POS",
"Race condition — หลาย orders พร้อมกัน",
"Caching ทำให้ stock count เก่า",
"API rate limiting จาก third-party systems",
],
},
}
def show_incidents(self):
print("=== Common WooCommerce Incidents ===\n")
for key, inc in self.INCIDENTS.items():
print(f"[{inc['severity']}] {inc['name']}")
print(f" Symptoms: {inc['symptoms']}")
for cause in inc['common_causes'][:3]:
print(f" • {cause}")
print()
incidents = WooCommerceIncidents()
incidents.show_incidents()
Post-mortem Process
# postmortem_process.py — WooCommerce post-mortem process
import json
class PostMortemProcess:
STEPS = {
"detect": {
"name": "1. Detection & Alert",
"actions": [
"UptimeRobot/Pingdom: site availability monitoring",
"WooCommerce Status Dashboard: checkout success rate",
"Google Analytics Real-time: traffic drops",
"Server monitoring: CPU, RAM, disk alerts",
],
},
"respond": {
"name": "2. Incident Response",
"actions": [
"Acknowledge incident — notify team via Slack",
"Assess severity — P1: checkout down, P2: slow, P3: minor",
"Assign incident commander + communication lead",
"Start incident timeline documentation",
],
},
"mitigate": {
"name": "3. Mitigation",
"actions": [
"Enable maintenance mode ถ้าจำเป็น",
"Rollback recent deployments (plugins/themes/core updates)",
"Switch to backup payment gateway ถ้ามี",
"Scale up hosting resources ถ้า traffic spike",
],
},
"investigate": {
"name": "4. Root Cause Investigation",
"actions": [
"Check error logs: /wp-content/debug.log",
"Check server logs: access.log, error.log",
"Check database: slow query log, table sizes",
"Check recent changes: plugin updates, code deployments",
"Reproduce issue in staging environment",
],
},
"resolve": {
"name": "5. Resolution",
"actions": [
"Apply fix (code change, config update, plugin patch)",
"Test fix in staging first",
"Deploy to production",
"Verify fix — checkout test, monitoring green",
],
},
"document": {
"name": "6. Post-mortem Document",
"actions": [
"Write timeline of events",
"Document root cause + contributing factors",
"List action items with owners + deadlines",
"Share with team — blameless culture",
],
},
}
def show_process(self):
print("=== Post-mortem Process ===\n")
for key, step in self.STEPS.items():
print(f"[{step['name']}]")
for action in step['actions'][:3]:
print(f" • {action}")
print()
process = PostMortemProcess()
process.show_process()
Python Log Analyzer
# log_analyzer.py — WooCommerce log analysis
import json
class WooLogAnalyzer:
CODE = """
# woo_log_analyzer.py — Analyze WooCommerce logs for post-mortem
import re
import json
from collections import Counter
from datetime import datetime, timedelta
class WooCommerceLogAnalyzer:
def __init__(self, debug_log_path="/var/www/html/wp-content/debug.log"):
self.log_path = debug_log_path
self.entries = []
def parse_log(self):
'''Parse WordPress debug.log'''
with open(self.log_path) as f:
current_entry = None
for line in f:
# Match: [DD-Mon-YYYY HH:MM:SS UTC] PHP type: message
match = re.match(
r'\\[(\\d{2}-\\w{3}-\\d{4} \\d{2}:\\d{2}:\\d{2} \\w+)\\] (.+)',
line
)
if match:
if current_entry:
self.entries.append(current_entry)
timestamp_str = match.group(1)
message = match.group(2)
current_entry = {
'timestamp': timestamp_str,
'message': message,
'type': 'error' if 'Fatal' in message or 'Error' in message else
'warning' if 'Warning' in message else
'notice' if 'Notice' in message else 'info',
}
elif current_entry:
current_entry['message'] += '\\n' + line.strip()
if current_entry:
self.entries.append(current_entry)
return len(self.entries)
def errors_by_type(self):
'''Count errors by type'''
return Counter(e['type'] for e in self.entries)
def errors_by_plugin(self):
'''Identify which plugins cause errors'''
plugin_errors = Counter()
for entry in self.entries:
match = re.search(r'/plugins/([\\w-]+)/', entry['message'])
if match:
plugin_errors[match.group(1)] += 1
return plugin_errors.most_common(10)
def checkout_errors(self):
'''Find checkout-related errors'''
keywords = ['checkout', 'payment', 'wc_gateway', 'order', 'cart']
return [e for e in self.entries
if any(kw in e['message'].lower() for kw in keywords)]
def errors_in_window(self, hours=24):
'''Get errors within time window'''
# Filter by timestamp (simplified)
return [e for e in self.entries if e['type'] in ('error', 'warning')]
def generate_report(self):
'''Generate post-mortem log report'''
total = len(self.entries)
by_type = self.errors_by_type()
by_plugin = self.errors_by_plugin()
checkout = self.checkout_errors()
return {
'total_entries': total,
'by_type': dict(by_type),
'top_plugins': by_plugin[:5],
'checkout_errors': len(checkout),
'sample_errors': [e['message'][:100] for e in self.entries[:5]],
}
# analyzer = WooCommerceLogAnalyzer('/path/to/debug.log')
# analyzer.parse_log()
# report = analyzer.generate_report()
# print(json.dumps(report, indent=2))
"""
def show_code(self):
print("=== Log Analyzer ===")
print(self.CODE[:600])
analyzer = WooLogAnalyzer()
analyzer.show_code()
Database Health Check
# db_health.py — WooCommerce database health check
import json
import random
class DBHealthCheck:
CODE = """
# woo_db_health.py — Database health check for WooCommerce
import mysql.connector
import json
class WooDatabaseHealth:
def __init__(self, host, user, password, database):
self.conn = mysql.connector.connect(
host=host, user=user, password=password, database=database
)
self.cursor = self.conn.cursor(dictionary=True)
def check_table_sizes(self):
'''Check database table sizes'''
self.cursor.execute('''
SELECT table_name,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb,
table_rows
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY data_length DESC
LIMIT 20
''')
return self.cursor.fetchall()
def check_autoloaded_options(self):
'''Check bloated autoloaded options'''
self.cursor.execute('''
SELECT option_name,
LENGTH(option_value) AS size_bytes,
ROUND(LENGTH(option_value) / 1024, 1) AS size_kb
FROM wp_options
WHERE autoload = 'yes'
ORDER BY LENGTH(option_value) DESC
LIMIT 20
''')
return self.cursor.fetchall()
def check_transients(self):
'''Check expired transients'''
self.cursor.execute('''
SELECT COUNT(*) AS expired_transients
FROM wp_options
WHERE option_name LIKE '_transient_timeout_%'
AND option_value < UNIX_TIMESTAMP()
''')
return self.cursor.fetchone()
def check_post_revisions(self):
'''Check post revisions bloat'''
self.cursor.execute('''
SELECT post_type, COUNT(*) AS count
FROM wp_posts
WHERE post_type = 'revision'
OR post_status = 'auto-draft'
''')
return self.cursor.fetchall()
def check_slow_queries(self):
'''Check for slow queries'''
self.cursor.execute("SHOW VARIABLES LIKE 'slow_query_log'")
status = self.cursor.fetchone()
self.cursor.execute("SHOW VARIABLES LIKE 'long_query_time'")
threshold = self.cursor.fetchone()
return {"slow_log": status, "threshold": threshold}
def optimize_tables(self):
'''Optimize WooCommerce tables'''
tables = [
'wp_posts', 'wp_postmeta', 'wp_options',
'wp_woocommerce_sessions', 'wp_woocommerce_order_items',
]
results = []
for table in tables:
self.cursor.execute(f"OPTIMIZE TABLE {table}")
results.append(self.cursor.fetchone())
return results
def full_health_check(self):
return {
'table_sizes': self.check_table_sizes()[:5],
'autoloaded_options': self.check_autoloaded_options()[:5],
'expired_transients': self.check_transients(),
'slow_queries': self.check_slow_queries(),
}
# health = WooDatabaseHealth('localhost', 'root', 'password', 'wordpress')
# report = health.full_health_check()
"""
def show_code(self):
print("=== DB Health Check ===")
print(self.CODE[:600])
def sample_report(self):
print(f"\n=== DB Health Report ===")
print(f" wp_posts: {random.randint(50, 500)}MB ({random.randint(5000, 50000)} rows)")
print(f" wp_postmeta: {random.randint(100, 800)}MB ({random.randint(100000, 1000000)} rows)")
print(f" wp_options: {random.randint(10, 100)}MB (autoload: {random.randint(5, 30)}MB)")
print(f" Expired transients: {random.randint(100, 5000)}")
print(f" Post revisions: {random.randint(1000, 20000)}")
print(f" Slow queries (24h): {random.randint(0, 50)}")
db = DBHealthCheck()
db.show_code()
db.sample_report()
Prevention & Monitoring
# prevention.py — Prevent WooCommerce incidents
import json
class Prevention:
MONITORING = {
"uptime": {
"name": "Uptime Monitoring",
"tools": ["UptimeRobot (free)", "Better Uptime", "Pingdom"],
"check": "HTTP check ทุก 1-5 นาที + checkout page monitoring",
},
"performance": {
"name": "Performance Monitoring",
"tools": ["Query Monitor plugin", "New Relic", "Google PageSpeed"],
"check": "TTFB < 500ms, page load < 3s, Core Web Vitals",
},
"security": {
"name": "Security Monitoring",
"tools": ["Wordfence", "Sucuri", "WP Activity Log"],
"check": "Failed login attempts, file changes, malware scan",
},
"orders": {
"name": "Order Monitoring",
"tools": ["WooCommerce Analytics", "Custom dashboard", "Slack alerts"],
"check": "Checkout success rate, payment failures, abandoned carts",
},
}
BEST_PRACTICES = [
"อัพเดท WordPress, WooCommerce, plugins ทุกสัปดาห์",
"Staging environment — ทดสอบก่อน deploy production",
"Automated backups ทุกวัน — UpdraftPlus, BlogVault",
"Security headers + WAF (Cloudflare, Sucuri)",
"Database optimization ทุกสัปดาห์ — WP-Optimize plugin",
"CDN สำหรับ static assets — Cloudflare, BunnyCDN",
"Object caching — Redis/Memcached",
"Incident response playbook — ทุกู้คืนในทีมรู้ว่าต้องทำอะไร",
]
def show_monitoring(self):
print("=== Monitoring Setup ===\n")
for key, mon in self.MONITORING.items():
print(f"[{mon['name']}]")
print(f" Tools: {', '.join(mon['tools'])}")
print(f" Check: {mon['check']}")
print()
def show_practices(self):
print("=== Best Practices ===")
for bp in self.BEST_PRACTICES[:5]:
print(f" • {bp}")
prev = Prevention()
prev.show_monitoring()
prev.show_practices()
FAQ - คำถามที่พบบ่อย
Q: Post-mortem ควรทำเมื่อไหร่?
A: ทุก P1/P2 incident: ภายใน 48 ชั่วโมงหลัง resolution P3 (recurring): ถ้าเกิดซ้ำ 3+ ครั้ง Near-miss: เกือบเกิดปัญหา — ทำ mini post-mortem สำคัญ: blameless culture — โฟกัสที่ process ไม่ใช่คน เก็บ post-mortem documents ใน wiki/Notion — เรียนรู้จากอดีต
Q: debug.log เปิดใช้งานยังไง?
A: เพิ่มใน wp-config.php: define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false); Log จะอยู่ที่: /wp-content/debug.log สำคัญ: อย่าเปิด WP_DEBUG_DISPLAY บน production — แสดง errors ให้ users เห็น ปิดหลังจาก debug เสร็จ — log file จะโตเรื่อยๆ
Q: WooCommerce checkout ล่มบ่อย แก้ยังไง?
A: สาเหตุส่วนใหญ่: Plugin conflict: ปิด plugins ทีละตัว → หา conflict JavaScript errors: เปิด browser console ดู errors Payment gateway: ตรวจ API keys, SSL, webhook URLs Session issues: เพิ่ม session timeout, ใช้ Redis สำหรับ sessions Caching: exclude checkout/cart pages จาก cache ทุกครั้ง ป้องกัน: มี backup payment gateway, monitoring checkout success rate
Q: Database optimization ทำบ่อยแค่ไหน?
A: อย่างน้อยสัปดาห์ละครั้ง: ลบ transients, revisions, auto-drafts, spam comments OPTIMIZE TABLE สำหรับ fragmented tables ใช้ WP-Optimize plugin ตั้ง schedule อัตโนมัติ สำหรับ high-traffic stores: พิจารณา separate database server + read replicas wp_postmeta table มักเป็น bottleneck — ใช้ custom tables สำหรับ WooCommerce orders (HPOS)
