---
id: central-elastic
title: "Elastic Stack và Log Analytics"
shortTitle: "Elastic Stack"
track: central-logs
trackTitle: "Log tập trung"
order: 1
level: core
status: published
estimatedMinutes: 40
prerequisites:
  - monitoring-grafana
  - logs-journald
next: central-loki
reviewedAgainst: 2026-10-12
sources:
  - title: "Elasticsearch — what it is"
    url: https://www.elastic.co/docs/reference/elasticsearch
  - title: "Elastic Agent"
    url: https://www.elastic.co/docs/reference/fleet
  - title: "Azure — Kusto Query Language"
    url: https://learn.microsoft.com/en-us/kusto/query/
---

# Elastic Stack và Log Analytics

Bài `/var/log` và `journalctl` đã chỉ cách đọc log trên một máy. Bài này nói về việc gom log của nhiều máy về một chỗ để search. Lab không dựng cluster Elasticsearch, vì cluster đó ngốn RAM và rất dễ trở thành thêm một hệ thống mà team phải trực riêng.

## Để làm gì

Bạn sẽ nói được từng thành phần trong Elastic Stack làm việc gì, và viết được một câu search đơn giản. Với Azure, bạn sẽ biết log của resource đi vào Log Analytics, và câu query ở đó viết bằng KQL chứ không phải Lucene.

## Gồm những gì

- Elasticsearch lưu log và đánh index.
- Elastic Agent gửi log đi. Filebeat là cách cũ hơn nhưng vẫn còn gặp.
- Kibana là giao diện để search.
- Azure Log Analytics và một câu KQL.

Graylog và Splunk cùng giải bài toán "một chỗ để search log". Hai hệ này có bài riêng ở cuối track.

## Dùng khi nào

Bạn có nhiều server hoặc nhiều Pod, và không thể SSH vào từng máy để đọc log. Bạn cần lần theo một request id đi qua vài service.

Nếu chỉ có một máy và một file log, `journalctl` với `grep` vẫn nhanh hơn nhiều so với dựng Elastic.

## Kiến thức cốt lõi

Elasticsearch đánh index nội dung log, nên bạn search được một từ bất kỳ trong message. Cái giá là tốn RAM và disk. Kibana là UI để search; không ai đọc dữ liệu Elasticsearch bằng cách mở file trên disk.

Log phải có thứ gửi đi. Elastic Agent là agent hiện hành, được cấu hình tập trung qua Fleet, và docs Elastic có hướng dẫn chuyển từ Beats sang Agent. Filebeat vẫn còn trong nhiều hệ thống cũ: nó đọc file hoặc nhận container log rồi gửi đi. Gặp Filebeat thì đừng xóa chỉ vì tài liệu mới không nhắc tới nó nữa. Hãy hiểu nó đang ship log những gì, rồi mới tính chuyện thay.

Mỗi event nên có timestamp, message và vài field như `service`, `env`, `host`. Nếu request id nằm trong message hoặc trong một field riêng, bạn lần được theo từng request. Không có id thì bạn chỉ còn cách lọc theo khoảng thời gian.

Azure Monitor gom log vào một Log Analytics workspace, và ngôn ngữ query là KQL. Một câu lọc cơ bản:

```kusto
AppTraces
| where TimeGenerated > ago(1h)
| where Message has "error"
| project TimeGenerated, Message
| take 20
```

`has` tìm theo từ, không phải regex. `ago(1h)` là một giờ vừa qua. Tên bảng phụ thuộc vào loại log bạn đã bật: `AppTraces` chỉ có khi app gửi trace, còn log container trên AKS thường nằm ở `ContainerLogV2`. Hãy xem danh sách bảng trong workspace của bạn, đừng chép tên bảng từ bài này nếu workspace không có bảng đó.

## Lệnh và code mẫu

Lab không chạy Elasticsearch. Thay vào đó, bạn tạo một dòng log dạng JSON, vì agent parse JSON dễ hơn nhiều so với parse một câu văn tiếng Anh.

```bash
mkdir -p "$HOME/devops-lab/centrallogs"
python3 - <<'PY'
import json, datetime
print(json.dumps({
  "time": datetime.datetime.now(datetime.timezone.utc).isoformat(),
  "service": "api",
  "env": "lab",
  "request_id": "8f3a",
  "message": "upstream returned 502",
}))
PY
```

Nếu log này đã vào Elasticsearch, câu tương đương trên thanh search của Kibana sẽ là (cú pháp KQL của Kibana, không phải KQL của Azure):

```text
service: "api" and message: "502"
```

Hai ngôn ngữ cùng viết tắt là KQL, nhưng KQL của Kibana và Kusto của Azure không dùng thay cho nhau được. Trước khi gõ query, hãy xem UI bạn đang mở là Kibana hay Log Analytics.

## Thực hành

1. In dòng JSON ở trên. Chỉ ra field nào dùng để lọc, field nào là câu cho người đọc.
2. Viết một câu Kusto, giả định có bảng `ContainerLogV2`, lọc `LogMessage` có chứa `502` trong 15 phút gần nhất và lấy 20 dòng. Tên cột đúng hay sai thì đối chiếu lại khi bạn có workspace thật.
3. Ghi lại: trong hệ thống của bạn, máy nào đang phải SSH vào để xem log. Đó là ứng viên đầu tiên để ship log tập trung.
4. Nếu có sẵn workspace Azure, chạy `search "502"` trên một khoảng thời gian ngắn. Không có thì bỏ qua bước này, đừng tạo resource tính phí chỉ để làm bài.

## Kết quả mong đợi

- Một dòng JSON có timestamp, service, message và request id.
- Bạn phân biệt được Kusto với thanh search của Kibana.
- Máy bạn không có cluster Elasticsearch mới, trừ khi bạn tự dựng ngoài phạm vi bài.

## Checklist

- [ ] Hiểu Elasticsearch là nơi search, không phải nơi app mở file ra đọc.
- [ ] Hiểu agent (Elastic Agent hoặc Filebeat) là thứ chạy trên từng máy.
- [ ] Log có request id hoặc một định danh tương đương.
- [ ] Không nhầm Kusto với KQL của Kibana.
- [ ] Không dựng Elastic chỉ cho một file trên một máy.

## Lỗi thường gặp

**Index mọi field tự do trong JSON do user gửi lên.** User nhét đủ loại field lạ, index phình to, cluster đầy disk. Hãy giới hạn số field, hoặc dồn phần tự do vào một field `message` không index toàn bộ.

**Log không có timestamp chuẩn.** UI sắp xếp sai thứ tự, và `--since` của bạn lọc không khớp. Hãy ghi thời gian theo UTC, định dạng ISO-8601.

**Tìm log AKS trong `/var/log` trên node.** Log container có thể còn ở đó một lúc, rồi mất khi Pod bị xóa. Chỗ cần tìm là hệ thống đã nhận log được ship đi, thường là Log Analytics nếu cluster bật Container Insights.

## Nguồn

1. [Elasticsearch](https://www.elastic.co/docs/reference/elasticsearch) — Elastic, vai trò của engine tìm kiếm.
2. [Fleet and Elastic Agent](https://www.elastic.co/docs/reference/fleet) — agent hiện tại, thay cho cách cấu hình Beats rời.
3. [Kusto Query Language](https://learn.microsoft.com/en-us/kusto/query/) — Microsoft Learn, `where`, `ago`, `project`.

## Tiếp theo

[Loki](./02-loki.md)
