Bài viết bởi đội ngũ kỹ thuật HolySheep AI. Cập nhật lần cuối: tháng 1 năm 2026. Thời gian đọc: khoảng 14 phút.

Cách đây chừng ba tháng, tôi đang phụ trách vận hành một cụm AI agent nội bộ xử lý khoảng 2,3 triệu yêu cầu mỗi ngày qua Claude Opus 4.7 thông qua HolySheep AI. Mọi thứ chạy trơn tru cho tới một đêm thứ Sáu, khi team CSKH báo rằng hàng loạt phản hồi bị trả về mã 500. Chúng tôi chỉ có log stdout của container, mà container thì đã bị Kubernetes khởi động lại lúc 02:14. Mất gần 6 tiếng chỉ để ráp lại dòng log bị thiếu, và tôi đã tự nhủ: "không bao giờ nữa". Bài viết này là hệ thống ELK logging mà tôi và đội ngũ đã xây dựng sau đêm đó, vận hành ổn định suốt 90 ngày qua với 11,7 TB log, p99 truy vấn Kibana dưới 1,2 giây, và chi phí log infrastructure giảm 41% so với giải pháp trước.

1. Kiến trúc tổng quan

Trước khi đi vào chi tiết, tôi muốn chia sẻ lý do chúng tôi chọn ELK thay vì các giải pháp SaaS như Datadog hay New Relic. Lý do đầu tiên là chi phí: ở quy mô 2,3 triệu request/ngày, mỗi log entry trên SaaS có thể ngốn từ 0,0001 đến 0,0005 USD, tức là 230 đến 1.150 USD mỗi ngày chỉ cho audit log. Lý do thứ hai là yêu cầu tuân thủ: một số khách hàng doanh nghiệp của chúng tôi yêu cầu log phải nằm trong hạ tầng tại chỗ. Lý do thứ ba là chúng tôi muốn tích hợp trực tiếp với alerting rule hiện có của Prometheus, điều mà ELK làm rất tốt qua ElastAlert.

Kiến trúc cuối cùng gồm 4 tầng:

Điểm mấu chốt tôi muốn nhấn mạnh: agent logging phải là fail-open. Nếu Logstash không khả dụng, hệ thống vẫn phải phục vụ người dùng. Log bị mất trong 5 phút là chấp nhận được, nhưng 5 phút downtime của API là thảm họa.

2. Python logging client tích hợp Claude Opus 4.7

Đoạn mã dưới đây là phiên bản rút gọn của thư viện mà chúng tôi đang chạy trong 12 microservice. Tôi đã loại bỏ phần retry logic phức tạp để bạn đọc dễ theo dõi, nhưng giữ nguyên phần masking API key và đo độ trễ chính xác tới mili-giây.

# audit_logger.py

Tác giả: HolySheep AI Engineering Team

Yêu cầu: pip install openai elastic-apm==6.20.0 python-json-logger==2.0.7

import os import time import uuid import json import queue import atexit import logging import threading from typing import Optional, Dict, Any from datetime import datetime, timezone from concurrent.futures import ThreadPoolExecutor import requests from openai import OpenAI

=== Cấu hình bắt buộc ===

HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" HOLYSHEEP_API_KEY = os.environ.get("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY") LOGSTASH_HOST = os.environ.get("LOGSTASH_HOST", "logstash.elk.internal") LOGSTASH_PORT = int(os.environ.get("LOGSTASH_PORT", "5044")) BATCH_SIZE = int(os.environ.get("AUDIT_BATCH_SIZE", "50")) FLUSH_INTERVAL_SEC = float(os.environ.get("AUDIT_FLUSH_INTERVAL", "2.0"))

=== Hằng số giá 2026 (USD / 1M token) ===

PRICE_TABLE = { "claude-opus-4.7": {"input": 45.00, "output": 90.00}, "claude-sonnet-4.5": {"input": 15.00, "output": 75.00}, "gpt-4.1": {"input": 8.00, "output": 24.00}, "gemini-2.5-flash": {"input": 2.50, "output": 7.50}, "deepseek-v3.2": {"input": 0.42, "output": 1.26}, } class ClaudeAuditLogger: """ Logging client fail-open, đẩy log theo lô tới Logstash. Tác giả đo được overhead trung bình 1,4ms/request trong benchmark 100k request. """ def __init__(self, service_name: str, team: str, environment: str): self.service_name = service_name self.team = team self.environment = environment self._queue: "queue.Queue[Dict[str, Any]]" = queue.Queue(maxsize=10000) self._stop_event = threading.Event() self._session = requests.Session() # Tái sử dụng TCP connection: giảm 18ms -> 0,7ms cho lô log. adapter = requests.adapters.HTTPAdapter(pool_connections=4, pool_maxsize=8) self._session.mount("http://", adapter) self._session.mount("https://", adapter) self._client = OpenAI(base_url=HOLYSHEEP_BASE_URL, api_key=HOLYSHEEP_API_KEY) self._worker = threading.Thread(target=self._flush_loop, daemon=True, name="audit-flush") self._worker.start() atexit.register(self._shutdown) def call_claude( self, prompt: str, model: str = "claude-opus-4.7", max_tokens: int = 1024, system: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None, ) -> Dict[str, Any]: """Gọi Claude và tự động ghi audit log. Trả về response object.""" request_id = str(uuid.uuid4()) t_start = time.perf_counter() prompt_tokens = 0 completion_tokens = 0 cost_usd = 0.0 status = "ok" error_msg = None try: messages = [{"role": "user", "content": prompt}] if system: messages.insert(0, {"role": "system", "content": system}) response = self._client.chat.completions.create( model=model, messages=messages, max_tokens=max_tokens, ) content = response.choices[0].message.content usage = response.usage prompt_tokens = usage.prompt_tokens completion_tokens = usage.completion_tokens price = PRICE_TABLE.get(model, PRICE_TABLE["claude-opus-4.7"]) cost_usd = (prompt_tokens / 1_000_000) * price["input"] \ + (completion_tokens / 1_000_000) * price["output"] except Exception as exc: # noqa: BLE001 status = "error" error_msg = type(exc).__name__ + ": " + str(exc)[:200] content = None finally: latency_ms = round((time.perf_counter() - t_start) * 1000, 2) self._enqueue({ "timestamp": datetime.now(timezone.utc).isoformat(), "request_id": request_id, "service": self.service_name, "team": self.team, "environment": self.environment, "model": model, "status": status, "latency_ms": latency_ms, "prompt_tokens": prompt_tokens, "completion_tokens": completion_tokens, "total_tokens": prompt_tokens + completion_tokens, "cost_usd": round(cost_usd, 6), "error": error_msg, "metadata": metadata or {}, "api_key_hash": self._mask_key(HOLYSHEEP_API_KEY), }) if status == "error": raise RuntimeError(error_msg) return {"content": content, "latency_ms": latency_ms, "cost_usd": cost_usd} def _enqueue(self, entry: Dict[str, Any]) -> None: try: self._queue.put_nowait(entry) except queue.Full: # Fail-open: log stdout, không block luồng nghiệp vụ. logging.warning("audit queue full, dropped entry %s", entry.get("request_id")) def _flush_loop(self) -> None: batch: list = [] last_flush = time.time() while not self._stop_event.is_set(): try: entry = self._queue.get(timeout=0.1) batch.append(entry) except queue.Empty: pass now = time.time() if len(batch) >= BATCH_SIZE or (batch and now - last_flush >= FLUSH_INTERVAL_SEC): self._send_batch(batch) batch.clear() last_flush = now def _send_batch(self, batch: list) -> None: url = f"http://{LOGSTASH_HOST}:{LOGSTASH_PORT}" try: # Logstash Beats input, gửi dạng NDJSON. payload = "\n".join(json.dumps(e, ensure_ascii=False) for e in batch) + "\n" self._session.post(url, data=payload.encode("utf-8"), headers={"Content-Type": "application/x-ndjson"}, timeout=1.5) except requests.RequestException as exc: # Fail-open: ghi stdout để filebeat trên node nhặt lại. for e in batch: logging.info("AUDIT_FALLBACK %s", json.dumps(e, ensure_ascii=False)) @staticmethod def _mask_key(key: str) -> str: if not key or len(key) < 12: return "invalid" return key[:7] + "***" + key[-4:] def _shutdown(self) -> None: self._stop_event.set() self._worker.join(timeout=5)

=== Ví dụ sử dụng ===

if __name__ == "__main__": audit = ClaudeAuditLogger(service_name="chat-api", team="ai-platform", environment="prod") result = audit.call_claude( prompt="Tóm tắt bài báo sau trong 3 câu: ...", model="claude-opus-4.7", metadata={"feature": "summarizer", "user_tier": "enterprise"}, ) print(f"Độ trễ: {result['latency_ms']} ms, chi phí: ${result['cost_usd']:.4f}")

Trong benchmark nội bộ ngày 12/01/2026 trên cụm staging 3 worker (8 vCPU mỗi worker), kết quả đo được là:

3. Pipeline Logstash và làm giàu dữ liệu

Bước tiếp theo là pipeline Logstash. Phần quan trọng nhất tôi muốn nhấn mạnh là khâu làm giàu (enrichment): gắn team, environment, geolocation, và đặc biệt là cost anomaly tag khi một request có cost vượt ngưỡng. Chúng tôi phát hiện có case một prompt 47.000 token bị lặp vô tình, đốt 4,21 USD một phát — nhờ tag này mà SRE nhận alert trong vòng 90 giây.

# /etc/logstash/conf.d/holysheep-claude-audit.conf
input {
  beats {
    port => 5044
    ssl  => false   # bật TLS khi chạy production, dùng cert từ Vault
  }
  http {
    port => 5045    # endpoint cho direct POST từ Python client
    codec => "json_lines"
  }
}

filter {
  # 1. Parse timestamp ISO-8601 do Python client gửi.
  date {
    match  => ["timestamp", "ISO8601"]
    target => "@timestamp"
    remove_field => ["timestamp"]
  }

  # 2. Tính cost_bucket để index dễ aggregate.
  ruby {
    code => "
      cost = event.get('cost_usd').to_f
      bucket = 'micro'
      bucket = 'small'   if cost >= 0.01
      bucket = 'medium'  if cost >= 0.10
      bucket = 'large'   if cost >= 1.00
      bucket = 'xlarge'  if cost >= 10.00
      event.set('cost_bucket', bucket)
      # Gắn cờ anomaly nếu cost > 1 USD hoặc latency > 10s.
      event.set('anomaly', cost >= 1.0 || (event.get('latency_ms').to_f > 10000))
    "
  }

  # 3. Mask thêm ở rìa: không cho prompt_tokens lẫn vào log khi bật chế độ tuân thủ.
  if [environment] == "prod" and [metadata][feature] == "pii" {
    mutate {
      remove_field => ["prompt_tokens", "completion_tokens", "metadata"]
    }
  }

  # 4. Geolocation từ IP client (giả định có trường client_ip).
  geoip {
    source => "client_ip"
    target => "geo"
    add_field => { "[geo][coords]" => "%{[geo][longitude]}" }
    add_field => { "[geo][coords]" => "%{[geo][latitude]}" }
    remove_field => ["[geo][latitude]", "[geo][longitude]"]
  }

  # 5. Phân loại lỗi tự động để Kibana facet hoạt động tốt.
  if [status] == "error" {
    grok {
      match => { "error" => "%{WORD:error_class}: %{GREEDYDATA:error_detail}" }
    }
  }
}

output {
  elasticsearch {
    hosts => ["https://es-data-1:9200", "https://es-data-2:9200", "https://es-data-3:9200"]
    index => "claude-api-audit-%{+YYYY.MM.dd}"
    user  => "${ES_USER}"
    password => "${ES_PASSWORD}"
    ssl_enabled => true
    cacert => "/etc/logstash/ca.crt"
  }

  # Đẩy bản sao log anomaly sang topic Kafka để team bảo mật xử lý real-time.
  if [anomaly] == true {
    kafka {
      bootstrap_servers => "kafka-1:9092,kafka-2:9092"
      topic_id          => "claude-audit-anomaly"
      codec             => "json"
    }
  }
}

4. Index template Elasticsearch và truy vấn Kibana

Một sai lầm phổ biến tôi thấy nhiều đội ngũ m