WordPress Observability
WordPress Block Theme Observability Prometheus Grafana Loki OpenTelemetry Core Web Vitals LCP FID CLS Performance Monitoring Production
| Layer | Tool | Metrics | Alert Threshold |
|---|---|---|---|
| Frontend | web-vitals + RUM | LCP FID CLS TTFB | LCP > 2.5s, CLS > 0.1 |
| Application | Prometheus PHP Exporter | Response time, memory, errors | p99 > 3s, error > 1% |
| Database | MySQL Exporter | Query time, connections, slow queries | Slow queries > 10/min |
| Web Server | Nginx Exporter | Requests/s, status codes, connections | 5xx > 0.5% |
| Infrastructure | Node Exporter | CPU, RAM, disk, network | CPU > 80%, disk > 85% |
| Logs | Loki + Promtail | Error logs, access logs | Error rate spike |
Monitoring Stack Setup
# === Docker Compose Observability Stack ===
# docker-compose.yml
# version: '3.8'
# services:
# wordpress:
# image: wordpress:6.4-php8.2
# ports: ["8080:80"]
# environment:
# WORDPRESS_DB_HOST: mysql
# WORDPRESS_DB_NAME: wordpress
# WORDPRESS_DB_USER: wp
# WORDPRESS_DB_PASSWORD: secret
# volumes:
# - wp-data:/var/www/html
#
# mysql:
# image: mysql:8.0
# environment:
# MYSQL_DATABASE: wordpress
# MYSQL_USER: wp
# MYSQL_PASSWORD: secret
# MYSQL_ROOT_PASSWORD: rootsecret
#
# prometheus:
# image: prom/prometheus
# ports: ["9090:9090"]
# volumes:
# - ./prometheus.yml:/etc/prometheus/prometheus.yml
#
# grafana:
# image: grafana/grafana
# ports: ["3000:3000"]
# environment:
# GF_SECURITY_ADMIN_PASSWORD: admin123
#
# loki:
# image: grafana/loki
# ports: ["3100:3100"]
#
# promtail:
# image: grafana/promtail
# volumes:
# - /var/log:/var/log
# - ./promtail.yml:/etc/promtail/config.yml
# prometheus.yml
# global:
# scrape_interval: 15s
# scrape_configs:
# - job_name: wordpress
# static_configs:
# - targets: ['wordpress:9117']
# - job_name: mysql
# static_configs:
# - targets: ['mysql-exporter:9104']
# - job_name: nginx
# static_configs:
# - targets: ['nginx-exporter:9113']
from dataclasses import dataclass
@dataclass
class StackComponent:
component: str
image: str
port: int
ram: str
purpose: str
stack = [
StackComponent("WordPress", "wordpress:6.4-php8.2", 8080, "512MB", "Application"),
StackComponent("MySQL", "mysql:8.0", 3306, "512MB", "Database"),
StackComponent("Prometheus", "prom/prometheus", 9090, "256MB", "Metrics storage"),
StackComponent("Grafana", "grafana/grafana", 3000, "256MB", "Dashboard"),
StackComponent("Loki", "grafana/loki", 3100, "256MB", "Log aggregation"),
StackComponent("Promtail", "grafana/promtail", 0, "128MB", "Log shipping"),
]
print("=== Observability Stack ===")
for s in stack:
print(f" [{s.component}] Image: {s.image} | Port: {s.port}")
print(f" RAM: {s.ram} | Purpose: {s.purpose}")
Core Web Vitals Monitoring
# === Core Web Vitals Collection ===
# JavaScript — Send CWV to Analytics
# // In theme's footer or via plugin
# import { onLCP, onFID, onCLS, onTTFB, onINP } from 'web-vitals';
#
# function sendToAnalytics(metric) {
# const body = JSON.stringify({
# name: metric.name,
# value: metric.value,
# rating: metric.rating, // good, needs-improvement, poor
# delta: metric.delta,
# id: metric.id,
# page: window.location.pathname,
# userAgent: navigator.userAgent,
# });
# navigator.sendBeacon('/api/vitals', body);
# }
#
# onLCP(sendToAnalytics);
# onFID(sendToAnalytics);
# onCLS(sendToAnalytics);
# onTTFB(sendToAnalytics);
# onINP(sendToAnalytics);
# PHP — Collect and expose to Prometheus
# // wp-content/mu-plugins/vitals-collector.php
# add_action('rest_api_init', function() {
# register_rest_route('vitals/v1', '/collect', [
# 'methods' => 'POST',
# 'callback' => function($request) {
# $data = $request->get_json_params();
# // Store in transient or custom table
# set_transient('cwv_' . $data['name'], $data['value'], 3600);
# return new WP_REST_Response(['ok' => true]);
# },
# 'permission_callback' => '__return_true',
# ]);
# });
@dataclass
class WebVital:
metric: str
good: str
needs_improvement: str
poor: str
optimization: str
vitals = [
WebVital("LCP", "< 2.5s", "2.5s - 4.0s", "> 4.0s",
"Optimize images (WebP), preload LCP element, CDN, server-side cache"),
WebVital("FID / INP", "< 100ms / < 200ms", "100-300ms / 200-500ms", "> 300ms / > 500ms",
"Reduce JavaScript, defer non-critical JS, web workers"),
WebVital("CLS", "< 0.1", "0.1 - 0.25", "> 0.25",
"Set image dimensions, reserve ad space, avoid dynamic content injection"),
WebVital("TTFB", "< 800ms", "800ms - 1.8s", "> 1.8s",
"Server-side cache, CDN, optimize PHP, database queries"),
]
print("\n=== Core Web Vitals Targets ===")
for v in vitals:
print(f" [{v.metric}] Good: {v.good} | NI: {v.needs_improvement} | Poor: {v.poor}")
print(f" Optimize: {v.optimization}")
Performance Optimization
# === WordPress Performance Checklist ===
@dataclass
class PerfItem:
category: str
item: str
impact: str
how: str
plugin: str
checklist = [
PerfItem("Cache", "Full Page Cache", "High — 80% TTFB reduction",
"Cache HTML output, bypass PHP for cached pages",
"WP Super Cache / W3 Total Cache / Redis Object Cache"),
PerfItem("Cache", "Object Cache (Redis)", "High — 50% DB query reduction",
"Cache WordPress objects in Redis",
"Redis Object Cache plugin + Redis server"),
PerfItem("Images", "WebP Conversion", "High — 30-50% image size reduction",
"Convert PNG/JPG to WebP, serve with ",
"ShortPixel / Imagify / EWWW"),
PerfItem("Images", "Lazy Loading", "Medium — faster initial load",
"Load images only when visible in viewport",
"Native loading=lazy (WP 5.5+)"),
PerfItem("JS/CSS", "Minify and Combine", "Medium — fewer requests",
"Remove whitespace, combine files",
"Autoptimize / WP Rocket"),
PerfItem("CDN", "Content Delivery Network", "High — global performance",
"Serve static assets from edge locations",
"Cloudflare / BunnyCDN / KeyCDN"),
PerfItem("Database", "Query Optimization", "Medium — faster page generation",
"Index slow queries, clean transients, optimize tables",
"Query Monitor plugin for analysis"),
PerfItem("PHP", "OPcache", "High — 2-3x PHP performance",
"Cache compiled PHP bytecode",
"php.ini: opcache.enable=1, opcache.memory=256"),
]
print("Performance Checklist:")
for p in checklist:
print(f" [{p.category}] {p.item} — Impact: {p.impact}")
print(f" How: {p.how}")
print(f" Plugin/Tool: {p.plugin}")
# Grafana Dashboard Panels
panels = {
"Response Time (p50/p95/p99)": "histogram_quantile(0.99, wordpress_request_duration_seconds_bucket)",
"Requests per Second": "rate(wordpress_requests_total[5m])",
"Error Rate": "rate(wordpress_errors_total[5m]) / rate(wordpress_requests_total[5m])",
"PHP Memory Usage": "wordpress_php_memory_bytes",
"MySQL Queries/s": "rate(mysql_queries_total[5m])",
"Cache Hit Rate": "wordpress_cache_hits / (wordpress_cache_hits + wordpress_cache_misses)",
}
print(f"\n\nGrafana Dashboard Panels:")
for k, v in panels.items():
print(f" [{k}]: {v}")
เคล็ดลับ
- Redis: ใช้ Redis Object Cache ลด Database Query 50%+
- WebP: แปลงรูปเป็น WebP ลดขนาด 30-50% ไม่เสียคุณภาพ
- OPcache: เปิด OPcache ใน php.ini เร่ง PHP 2-3 เท่า
- Query Monitor: ใช้ Query Monitor Plugin หา Slow Query
- Block Theme: ใช้ Block Theme ลด PHP Rendering ได้มาก
WordPress Observability คืออะไร
Monitor WordPress Metrics Response Time Memory Logs PHP MySQL Nginx Traces Request Flow Core Web Vitals LCP FID CLS Prometheus Grafana Loki
Block Theme ต่างจาก Classic Theme อย่างไร
Full Site Editing FSE theme.json HTML Template Global Styles Typography Color Performance CSS jQuery WordPress 6.0 Create Block Theme
ตั้ง Monitoring Stack อย่างไร
Prometheus Exporter Plugin WordPress Metrics Grafana Dashboard Loki Log Promtail OpenTelemetry PHP Traces Alert Response Time Error Rate Disk
Core Web Vitals วัดอย่างไร
LCP 2.5s FID 100ms CLS 0.1 Performance API web-vitals Library PageSpeed Insights CrUX Browser INP TTFB
สรุป
WordPress Block Theme Observability Prometheus Grafana Loki Core Web Vitals LCP CLS Redis OPcache WebP CDN Performance Monitoring Production
