Vector chuẩn hóa log proxy: VRL che mật khẩu, mã lỗi, dead-letter
Vector chuẩn hóa log proxy là bước làm sạch log crawler trước khi gửi đi lưu trữ: tách trường, gom thông báo lỗi về một bộ mã chung và xóa mật khẩu proxy. ProxyVN dựng log mẫu chứa bí mật giả, viết chương trình VRL rồi kiểm từng dòng sau khi xử lý. Lab còn bắt được một lỗi regex làm lộ đuôi mật khẩu có ký tự @.
Vector chuẩn hóa log proxy: tác vụ cụ thể và ranh giới với bài đã có
Vì sao cần một bước chuẩn hóa
Log của crawler đi qua proxy thường lộn xộn. Cùng một lỗi xác thực, requests ghi một kiểu, aiohttp ghi kiểu khác, Playwright ghi kiểu thứ ba. Thông báo lỗi lại hay chứa nguyên URL proxy kèm tài khoản, vì thư viện in cả địa chỉ đang kết nối.
Gửi thẳng log như vậy vào kho chung gây hai vấn đề. Truy vấn đếm lỗi phải biết mọi biến thể chuỗi. Ai có quyền đọc log cũng đọc được mật khẩu proxy. Chuẩn hóa ở tầng thu gom giải quyết cả hai trước khi dữ liệu rời máy.
Ranh giới với bài Loki
Bài riêng về Grafana Loki quản lý log proxy nói về lưu và truy vấn: đặt label, viết LogQL, giữ log bao lâu. Bài này đứng trước bước đó. Đầu vào là dòng log thô của worker, đầu ra là sự kiện JSON đã có error_code, đã mất mật khẩu, và một luồng riêng cho dòng không đọc được.
Hai bài không dùng chung cấu hình. Sink cuối của Vector có thể là Loki, tệp, Elasticsearch hay kho đối tượng. Phần VRL bên dưới giữ nguyên dù sink đổi.
Phạm vi kiểm thử
ProxyVN tải gói vector-0.60.0-x86_64-pc-windows-msvc.zip, bản 0.60.0 phát hành ngày 19/10/2026, kiểm SHA256 khớp tệp vector-0.60.0-SHA256SUMS. Lệnh chạy vector.exe bị chế độ tự động của môi trường làm việc chặn vì là mã tải từ ngoài, nên Vector không được chạy. Gói đã xóa sau đó.
Thay vào đó, một script Python lặp lại đúng logic của chương trình VRL trong bài, dùng cùng biểu thức chính quy, trên 10 dòng log mẫu. Kết quả dưới đây là của script, chưa phải Vector. Cú pháp VRL viết theo tài liệu chính thức đọc ngày 29/10/2026, chưa qua lệnh vector validate hay vector test.
Biến đổi log bằng VRL trong Vector chuẩn hóa log proxy trước khi gửi sink
Vector và VRL là gì
Vector là công cụ thu gom và chuyển log, metric theo mô hình source, transform, sink. Transform remap chạy một chương trình viết bằng Vector Remap Language, gọi tắt VRL, trên từng sự kiện. Theo tài liệu remap, chương trình có thể đặt trong khóa source, hoặc đọc từ tệp qua khóa file.
VRL là ngôn ngữ có kiểm kiểu lúc biên dịch. Hàm nào có thể lỗi, gọi là fallible, phải được xử lý lỗi, nếu không Vector từ chối nạp cấu hình. Có hai cách: thêm dấu chấm than như parse_json! để dừng chương trình khi lỗi, hoặc gán hai biến kết quả, lỗi để tự rẽ nhánh.
Bốn việc chương trình VRL phải làm

Bốn việc của VRL
- Tách dòng JSON của worker thành trường. Dòng không phải JSON thì không xử lý tiếp.
- Đọc URL proxy, giữ lại scheme, host, port và cờ có tài khoản hay không, rồi xóa URL gốc.
- Gom thông báo lỗi về một trường error_code với bộ giá trị cố định.
- Xóa tài khoản trong mọi URL còn sót, xóa header Authorization và khóa API trong query string.
Bộ mã lỗi chung
Bộ mã nhỏ giúp truy vấn và dashboard phía sau đơn giản. Không cần chính xác tới từng ngoại lệ của thư viện, chỉ cần đủ để người trực biết lỗi thuộc chặng nào.
error_code |
Dấu hiệu trong log |
Chặng gây lỗi |
|---|---|---|
ok |
status dưới 400 |
Không lỗi |
http_4xx, http_5xx |
status từ 400 trở lên |
Đích hoặc proxy trả mã HTTP |
proxy_auth_407 |
chuỗi 407 hoặc status 407 |
Tài khoản proxy |
proxy_refused |
10061, connection refused, actively refused |
Không kết nối được tới proxy |
timeout |
timed out, timeout |
Proxy hoặc đích chậm |
tls_error |
ssl, certificate |
Chứng chỉ hoặc bắt tay TLS |
bad_proxy_url |
InvalidURL, failed to parse |
Chuỗi proxy sai định dạng |
unknown |
không khớp mẫu nào |
Cần xem thêm |
Thứ tự so khớp có ý nghĩa. Một thông báo có thể chứa cả 407 lẫn chữ timeout trong phần mô tả. Đặt 407 lên trước vì lỗi tài khoản là thứ cần sửa ngay, còn timeout có thể là hệ quả của nó.
Chuẩn bị phiên bản, credential và môi trường kiểm thử Vector chuẩn hóa log proxy
Ghi phiên bản
VRL thêm hàm và đổi kiểu trả về qua các bản Vector. Hướng dẫn nội bộ nên ghi bản Vector và ngày thử. Lab này nhắm bản 0.60.0. Khi nâng bản, chạy lại bộ unit test của chính cấu hình trước khi triển khai.
Log mẫu chứa bí mật giả
Log mẫu có 10 dòng, mô phỏng các lỗi hay gặp khi crawler đi qua proxy. Mọi bí mật đều là giá trị giả đặt riêng cho lab: tài khoản user1, mật khẩu Lab-P@ss-2026, khóa API sk_test_FAKE9f3c2a71, token tok_lab_88aa. Địa chỉ proxy thuộc dải 203.0.113.0/24 dành cho tài liệu.
- Dòng 1: request thành công qua proxy có tài khoản, mật khẩu đã mã hóa phần trăm thành Lab-P%40ss-2026.
- Dòng 2: ProxyError có chuỗi 407 Proxy Authentication Required.
- Dòng 3: ReadTimeout sau 30 giây.
- Dòng 4: SOCKS5 bị từ chối kết nối, mã WinError 10061.
- Dòng 5: 429 với khóa API nằm trong query string.
- Dòng 6: 502 kèm dòng debug in cả header Proxy-Authorization và Authorization.
- Dòng 7: InvalidURL vì mật khẩu có @ mà chưa mã hóa.
- Dòng 8: lỗi chứng chỉ tự ký.
- Dòng 9: JSON bị cắt giữa chừng.
- Dòng 10: một dòng Traceback không phải JSON nhưng có URL proxy kèm tài khoản.
Cả 10 dòng đều chứa ít nhất một bí mật. Đó là chủ ý, để phép kiểm sau xử lý có ý nghĩa.
Các bước chạy khi môi trường cho phép
Phần này là trình tự ProxyVN đề nghị khi có máy chạy được Vector. Gói Windows là tệp zip, giải nén ra thư mục có vector.exe trong thư mục con bin. Không cần cài dịch vụ để thử.
1. Tạo các thư mục C:/lab/vector/data, C:/lab/logs và C:/lab/out. Vector báo lỗi nếu data_dir chưa tồn tại.
2. Chép tệp cấu hình YAML và normalize.vrl vào C:/lab/vector.
3. Chạy vector validate --config C:/lab/vector/vector.yaml, sửa mọi lỗi VRL được báo.
4. Chạy vector test --config C:/lab/vector/vector.yaml để chạy hai ca thử trong khóa tests.
5. Chép log mẫu vào C:/lab/logs/crawler-lab.log rồi chạy vector --config C:/lab/vector/vector.yaml.
6. Đọc C:/lab/out, kỳ vọng 8 sự kiện ở tệp clean và 2 sự kiện ở tệp dead, khớp bảng kết quả script.
Nếu số sự kiện khác, xem từng sự kiện trong tệp dead trước. Phần lớn sai lệch đến từ bước tách JSON, ví dụ source thêm trường hoặc dòng có ký tự BOM ở đầu tệp.
Mật khẩu proxy và định dạng URL
Bài định dạng proxy đã nói chuyện chuyển ip:port:user:pass sang URL. Điểm liên quan ở đây là ký tự đặc biệt. Mật khẩu có @, dấu hai chấm hay dấu # phải mã hóa phần trăm khi đặt vào URL. Khi không mã hóa, thư viện báo lỗi và in cả chuỗi sai vào log, như dòng 7.
Cấu hình tối thiểu cho Vector chuẩn hóa log proxy và phạm vi từng thiết lập
Tệp cấu hình đầy đủ
Cấu hình dưới gồm một source đọc tệp log, một transform remap chính, một transform cho dead-letter và hai sink tệp. Định dạng YAML, Vector cũng nhận TOML và JSON. Đường dẫn dạng Windows dùng dấu gạch chéo xuôi.
data_dir: C:/lab/vector/data
sources:
crawler_logs:
type: file
include:
- C:/lab/logs/crawler-*.log
read_from: beginning
transforms:
normalize:
type: remap
inputs: [crawler_logs]
drop_on_error: true
reroute_dropped: true
file: C:/lab/vector/normalize.vrl
scrub_dead:
type: remap
inputs: [normalize.dropped]
source: |
.message = replace(string!(.message), r'(?i)(?P<s>[a-z][a-z0-9+.-]*://)[^/\s]*@', "$$s[REDACTED]@")
.message = replace(.message, r'(?i)(proxy-)?authorization:\s*(basic|bearer)\s+[A-Za-z0-9._~+/=-]+', "[REDACTED]")
.reason = "parse_failed"
sinks:
clean_out:
type: file
inputs: [normalize]
path: C:/lab/out/clean-%Y-%m-%d.log
encoding:
codec: json
dead_out:
type: file
inputs: [scrub_dead]
path: C:/lab/out/dead-%Y-%m-%d.log
encoding:
codec: json
Khóa file trỏ tới tệp VRL riêng, dễ đọc và dễ kiểm hơn chuỗi dài trong YAML. Tài liệu remap ghi chỉ được đặt đúng một trong ba khóa source, file hoặc files.
Chương trình normalize.vrl
parsed = object!(parse_json!(string!(.message)))
. = merge(., parsed)
del(.message)
u, err = parse_url(string(.proxy_url) ?? "")
if err == null {
.proxy_scheme = u.scheme
.proxy_host = u.host
.proxy_port = u.port
.proxy_has_auth = u.username != ""
} else {
.proxy_host = "unparsed"
.proxy_has_auth = contains(string(.proxy_url) ?? "", "@")
}
del(.proxy_url)
msg = string(.msg) ?? ""
st = to_int(.status) ?? 0
.error_code = if st >= 400 {
"http_" + to_string(st)
} else if st > 0 {
"ok"
} else if match(msg, r'\b407\b') {
"proxy_auth_407"
} else if match(msg, r'(?i)10061|connection refused|actively refused') {
"proxy_refused"
} else if match(msg, r'(?i)timed out|timeout') {
"timeout"
} else if match(msg, r'(?i)ssl|certificate') {
"tls_error"
} else if match(msg, r'(?i)invalidurl|failed to parse') {
"bad_proxy_url"
} else {
"unknown"
}
if st == 407 { .error_code = "proxy_auth_407" }
.msg = replace(msg, r'(?i)(?P<s>[a-z][a-z0-9+.-]*://)[^/\s]*@', "$s[REDACTED]@")
.msg = replace(.msg, r'(?i)(proxy-)?authorization:\s*(basic|bearer)\s+[A-Za-z0-9._~+/=-]+', "[REDACTED]")
.url = replace(string(.url) ?? "", r'(?i)(?P<k>[?&](api_key|token|key|access_token)=)[^&\s]+', "$k[REDACTED]")
Trong tệp .vrl riêng, chuỗi thay thế viết $s. Khi đặt VRL trực tiếp trong YAML như transform scrub_dead, phải viết $$s. Tài liệu hàm replace nhắc điều này, vì Vector coi $ trong tệp cấu hình là biến môi trường.
Ý nghĩa từng thiết lập
- drop_on_error: true: sự kiện gặp lỗi lúc chạy không đi tiếp ra output chính. Mặc định là false, nghĩa là sự kiện gốc chưa sửa vẫn được gửi xuống sink.
- reroute_dropped: true: sự kiện bị bỏ được chuyển sang output tên normalize.dropped thay vì mất hẳn.
- object!(parse_json!(...)): dòng không phải JSON, hoặc JSON không phải đối tượng, làm chương trình lỗi và rẽ sang dead-letter.
- parse_url không có dấu chấm than: URL sai không làm cả sự kiện vào dead-letter, chỉ đánh dấu unparsed.
- read_from: beginning: đọc tệp từ đầu, hợp cho lab. Dùng thật nên để mặc định, đọc phần mới.
Trường nên giữ, trường nên bỏ
Chuẩn hóa không chỉ là che. Nó còn là chọn trường nào đáng gửi đi. Mỗi trường thừa là thêm dung lượng lưu trữ và thêm chỗ có thể lộ dữ liệu.
- Giữ: ts, job, status, elapsed_ms, error_code, proxy_scheme, proxy_host, proxy_port, proxy_has_auth.
- Giữ có điều kiện: url sau khi đã xóa khóa trong query string. Nếu URL chứa mã khách hàng hay email, chỉ giữ host và path.
- Bỏ: proxy_url gốc, cookie, toàn bộ header request, thân response.
- Cân nhắc: msg gốc sau khi che. Nó có ích khi điều tra lỗi unknown, nhưng dài và tốn chỗ.
Danh sách này nên được thống nhất với người dùng log ở phía sau. Đội phân tích dữ liệu có thể cần trường mà đội vận hành không cần, và ngược lại.
Bẫy lớn nhất: dead-letter giữ bản gốc
Tài liệu remap ghi rõ sự kiện gửi tới output dropped ở dạng nguyên bản, bỏ mọi thay đổi đã làm trước khi lỗi. Nghĩa là dòng hỏng chứa mật khẩu sẽ đi vào dead-letter với nguyên mật khẩu. Đây là lý do cấu hình có transform scrub_dead riêng.
Nhiều cấu hình mẫu trên mạng gửi thẳng normalize.dropped tới sink. Làm vậy thì log sạch nằm một chỗ, còn bí mật vẫn rò qua đường dead-letter. Mọi output của Vector đều cần qua bước che bí mật, kể cả output lỗi.
Chạy đối chứng, đọc log và kiểm tra output bắt buộc của Vector chuẩn hóa log proxy
Kết quả script trên 10 dòng mẫu
Script lab/t262.py đọc 10 dòng, lặp lại logic của normalize.vrl và scrub_dead bằng Python. Phép kiểm cuối tìm năm chuỗi bí mật nguyên vẹn và ba mảnh bí mật trong toàn bộ đầu ra. Kết quả chạy ngày 29/10/2026:
Chỉ số |
Giá trị |
|---|---|
Dòng vào |
10 |
Dòng chứa bí mật trước xử lý |
10 |
Sự kiện ra output chính |
8 |
Sự kiện vào dead-letter |
2 |
Bí mật nguyên vẹn còn sót sau xử lý |
0 |
Mảnh bí mật còn sót sau xử lý |
0 |
Phân bố error_code |
ok 1, proxy_auth_407 1, timeout 1, proxy_refused 1, http_429 1, http_502 1, bad_proxy_url 1, tls_error 1 |
Mỗi dòng lỗi rơi vào đúng một mã, không dòng nào ra unknown. Dòng 6 có status 502 nên được gán http_502 dù phần thông báo không khớp mẫu nào, và hai header bí mật đều bị thay bằng [REDACTED].
Một sự kiện trước và sau

Tách sự kiện lỗi sang dead-letter
Dòng 2 trước xử lý là JSON chứa proxy_url có tài khoản. Sau xử lý, proxy_url biến mất, thay bằng các trường mô tả:
{"ts": "2026-10-29T08:00:02Z", "job": "crawl-shop", "url": "https://shop2.example/p/9",
"status": null, "elapsed_ms": 3,
"msg": "ProxyError('Unable to connect to proxy', OSError('Tunnel connection failed: 407 Proxy Authentication Required'))",
"proxy_scheme": "http", "proxy_endpoint": "203.0.113.50:8080", "proxy_has_auth": true,
"error_code": "proxy_auth_407"}
Script Python ghép host và port thành proxy_endpoint, còn VRL trong bài để hai trường proxy_host và proxy_port riêng. Khác biệt này chỉ là cách trình bày, không ảnh hưởng phép kiểm bí mật.
Lỗi regex mà lab bắt được
Bản regex đầu tiên để xóa tài khoản trong URL là ([a-z][a-z0-9+.-]*://)[^/@\s]+(?::[^/\s]*)?@. Nó dừng ở dấu @ đầu tiên. Với dòng 7, mật khẩu Lab-P@ss-2026 chưa mã hóa, kết quả là http://[REDACTED]@[email protected]:8080. Phần ss-2026 của mật khẩu vẫn nằm trong log.
Bản sửa dùng ([a-z][a-z0-9+.-]*://)[^/\s]*@, tức lấy tham lam tới dấu @ cuối cùng trước dấu gạch chéo hay khoảng trắng. Kết quả thành http://[REDACTED]@203.0.113.50:8080. Phép kiểm nguyên chuỗi Lab-P@ss-2026 không phát hiện được lỗi này, vì mảnh còn sót không trùng toàn bộ mật khẩu.
Kiểm che bí mật phải tìm cả mảnh của bí mật, không chỉ tìm nguyên chuỗi. Mật khẩu chứa ký tự @ là ca thử bắt buộc.
Dead-letter sau khi che

Che cả mảnh mật khẩu
Hai dòng vào dead-letter là dòng JSON bị cắt và dòng Traceback. Cả hai đều có URL proxy kèm tài khoản. Sau scrub_dead, chúng còn dạng http://[REDACTED]@203.0.113.50:8080 cùng lý do parse_failed. Người vận hành vẫn đọc được dòng gốc để sửa nguồn log, mà không thấy mật khẩu.
Unit test của Vector
Vector có lệnh vector test chạy các ca thử khai báo trong khóa tests của cấu hình. Theo tài liệu unit test, mỗi ca có inputs với insert_at chỉ transform nhận sự kiện, và outputs với extract_from cùng điều kiện VRL. Khóa no_outputs_from dùng để khẳng định một transform không xuất sự kiện nào.
tests:
- name: "407 duoc gan ma va mat khau bi xoa"
inputs:
- insert_at: normalize
type: log
log_fields:
message: '{"job":"crawl-shop","proxy_url":"http://user1:Lab-P%40ss-2026@203.0.113.50:8080","status":null,"msg":"Tunnel connection failed: 407 Proxy Authentication Required"}'
outputs:
- extract_from: normalize
conditions:
- type: vrl
source: |
assert_eq!(.error_code, "proxy_auth_407")
assert!(!exists(.proxy_url))
assert!(!contains(encode_json(.), "Lab-P"))
- name: "dong khong phai JSON khong ra output chinh"
no_outputs_from: [normalize]
inputs:
- insert_at: normalize
type: log
log_fields:
message: 'Traceback (most recent call last): proxy http://user1:Lab-P%40ss-2026@203.0.113.50:8080'
Phép kiểm contains với chuỗi Lab-P là kiểm mảnh, đúng bài học ở trên. Hai ca thử này chưa được chạy bằng vector test trong lab, cần chạy khi có môi trường cho phép.
Đọc lỗi khi Vector chuẩn hóa log proxy không chạy như mong đợi
Lỗi lúc nạp cấu hình
VRL báo lỗi ngay lúc nạp nếu một hàm fallible chưa được xử lý. Thông báo có mã lỗi và chỉ vị trí dòng, cột. Ví dụ gọi parse_json mà không có dấu chấm than và không gán biến lỗi. Theo trang lỗi VRL, mỗi mã lỗi có trang giải thích riêng.
Lệnh vector validate kiểm cấu hình mà không chạy pipeline. Nên chạy lệnh này trong CI mỗi khi sửa tệp .vrl, cùng với vector test.
Lỗi lúc chạy
Lỗi lúc chạy là khi chương trình gặp dữ liệu không như giả định. Với drop_on_error: true, sự kiện đó sang dead-letter. Đếm số sự kiện dead-letter theo giờ là một chỉ số sức khỏe tốt. Số này tăng đột ngột thường có nghĩa ứng dụng vừa đổi định dạng log.
Vector có metric nội bộ component_discarded_events_total cho số sự kiện bị bỏ, như tài liệu remap liệt kê. Đưa metric này vào hệ giám sát đang có, ví dụ theo bài Prometheus và Grafana, để cảnh báo khi dead-letter tăng.
Bảng tra nhanh
Hiện tượng |
Nguyên nhân hay gặp |
Cách xử lý |
|---|---|---|
Vector không nạp cấu hình |
Hàm fallible chưa xử lý lỗi |
Thêm ! hoặc gán biến lỗi |
Mọi sự kiện vào dead-letter |
Source thêm trường khác, .message không phải JSON |
Xem một sự kiện thô, sửa bước tách |
Chuỗi thay thế ra rỗng |
Viết $s trong YAML thay vì $$s |
Dùng tệp .vrl riêng hoặc $$ |
Còn sót mảnh mật khẩu |
Regex dừng ở @ đầu tiên |
Dùng regex tham lam như bài |
error_code toàn unknown |
Thư viện đổi thông báo lỗi |
Thêm mẫu, giữ unit test |
Log bị nhân đôi |
Hai source cùng đọc một tệp |
Kiểm include của các source |
Không tin vào một lần chạy
Bộ mẫu regex chỉ đúng với các thông báo lỗi đã thấy. Khi nâng requests, aiohttp hay Playwright, thông báo có thể đổi chữ. Mỗi lần nâng thư viện crawler, chạy crawler qua một proxy sai mật khẩu và một proxy chết, rồi xem error_code ra gì.
Mẫu nhận diện lỗi theo thư viện khi Vector chuẩn hóa log proxy
Vì sao cần mẫu riêng cho từng thư viện
Cùng một sự cố proxy, mỗi thư viện ghi một câu khác. Bộ mẫu trong normalize.vrl chỉ phủ thông báo của requests và urllib3 trong log mẫu. Khi đội dùng nhiều công cụ, cần mở rộng bộ mẫu theo từng nguồn. Bảng dưới gom các chuỗi hay gặp theo hiểu biết của ProxyVN, phần lớn chưa được chạy lại trong lab này, nên cần đối chiếu bằng một lần chạy thật trước khi đưa vào VRL.
Công cụ |
Lỗi tài khoản proxy |
Không kết nối được proxy |
Hết thời gian |
|---|---|---|---|
requests, urllib3 |
Tunnel connection failed: 407 |
ProxyError, Unable to connect to proxy |
ConnectTimeout, ReadTimeout |
aiohttp |
ClientHttpProxyError với 407 |
ClientProxyConnectionError |
ServerTimeoutError hoặc TimeoutError |
httpx |
ProxyError kèm 407 |
ConnectError |
ConnectTimeout, ReadTimeout |
Chromium, Playwright |
Yêu cầu xác thực proxy |
net::ERR_PROXY_CONNECTION_FAILED |
net::ERR_TIMED_OUT |
curl |
CONNECT tunnel failed, response 407 |
mã thoát 7 |
mã thoát 28 |
requests và urllib3
Log mẫu của lab dùng đúng kiểu thông báo của requests 2.34.2 trên Windows: ProxyError bọc OSError, bên trong có chuỗi Tunnel connection failed kèm mã trạng thái. Mẫu \b407\b bắt được dòng này. Lỗi không kết nối được tới proxy trên Windows kèm WinError 10061, trên Linux là Connection refused, nên mẫu proxy_refused gồm cả hai.
Một điểm dễ sót là requests có thể in cả URL proxy trong thông báo khi chuỗi proxy sai định dạng, như dòng 7 của log mẫu. Đó là lý do bước xóa tài khoản chạy trên trường msg, không chỉ trên trường proxy_url.
aiohttp và httpx
Hai thư viện bất đồng bộ này dùng tên ngoại lệ riêng. Với aiohttp, lỗi 407 khi mở đường hầm thường hiện là ClientHttpProxyError kèm mã trạng thái, còn không tới được proxy là ClientProxyConnectionError. Bài aiohttp proxy và bài httpx proxy có cách cấu hình để tái hiện từng lỗi.
Nên thêm mẫu theo tên ngoại lệ, ví dụ ClientProxyConnectionError vào nhóm proxy_refused. Tên ngoại lệ ổn định hơn câu mô tả, vì câu mô tả hay đổi giữa các bản.
Trình duyệt tự động
Playwright và Puppeteer chạy Chromium, lỗi mạng có dạng net::ERR_ kèm tên. Lỗi đường hầm qua proxy là net::ERR_TUNNEL_CONNECTION_FAILED, bài ERR_TUNNEL_CONNECTION_FAILED giải thích nguyên nhân. Nên gom các mã net::ERR_PROXY_ vào proxy_refused và net::ERR_TUNNEL_ vào một mã riêng, vì đường hầm lỗi có thể do proxy từ chối đích chứ không phải proxy chết.
Giữ bộ mẫu bằng unit test
Mỗi mẫu thêm vào nên đi kèm một ca thử trong khóa tests, dùng đúng chuỗi lỗi lấy từ log thật đã che bí mật. Khi ai đó sửa thứ tự hay sửa regex, vector test sẽ báo ca nào đổi mã. Đây là cách rẻ nhất để bộ mã lỗi không trôi dần theo thời gian.
Đưa sự kiện sạch tới Loki và kho khác sau khi Vector chuẩn hóa log proxy
Sink Loki
Khi kho đích là Loki, thay sink tệp bằng sink loki. Tài liệu sink Loki có các khóa endpoint, encoding, labels, structured_metadata và out_of_order_action. Label chỉ nên là giá trị cố định, giống nguyên tắc ở bài Loki.
loki_out:
type: loki
inputs: [normalize]
endpoint: http://localhost:3100
encoding:
codec: json
labels:
job: crawler
env: lab
Không đưa error_code lên label nếu số mã còn đang thêm. Để error_code trong dòng JSON, LogQL tách bằng json khi truy vấn. Proxy_host có thể làm label nếu hệ chỉ dùng vài endpoint proxy cố định.
Giữ thứ tự xử lý
Thứ tự nên là: tách, che, gắn mã, rồi mới gửi. Nếu có transform khác như sampling hay route đặt trước normalize, chúng sẽ làm việc trên dữ liệu chưa che. Route theo error_code nên đặt sau normalize để không phải viết lại mẫu regex.
Khi dùng Fluent Bit hay Alloy song song
Một số đội để Alloy hay Fluent Bit thu gom, rồi gửi sang Vector để biến đổi. Khi đó cần chắc tầng đầu không ghi log thô ra đâu khác, ví dụ ra bộ đệm đĩa không mã hóa. Vector che bí mật được ở tầng của nó, không che được bản sao mà tầng khác đã lưu.
Gỡ cấu hình thử, quản lý bí mật và checklist dùng thật cho Vector chuẩn hóa log proxy
Gỡ môi trường thử
Dừng Vector, xóa thư mục data_dir để bỏ vị trí đọc tệp đã lưu. Xóa C:/lab/out nếu không cần giữ đầu ra. Tệp log mẫu chỉ chứa bí mật giả, nhưng vẫn nên xóa để không ai nhầm là log thật.
Nếu đã thử sink Loki, xóa stream job="crawler" env="lab" theo quy trình xóa của Loki hoặc để retention tự dọn. Không để dữ liệu lab lẫn vào dashboard thật.
Bí mật trong cấu hình Vector
Cấu hình Vector có thể cần token cho sink, ví dụ khóa API của kho log. Đừng ghi token thẳng vào YAML. Vector hỗ trợ đọc biến môi trường bằng cú pháp ${TEN_BIEN}, đó cũng là lý do $ trong chuỗi VRL phải viết thành $$.
Mật khẩu proxy không có lý do để nằm trong cấu hình Vector. Vector chỉ đọc log và gửi đi, không cần đi qua proxy của crawler. Nếu sink nằm ngoài mạng và phải qua proxy, Vector có khóa proxy riêng cho sink, nên dùng tài khoản khác tài khoản crawler.
Kiểm lại sau mỗi lần đổi mật khẩu proxy
Bộ kiểm bí mật dựa vào chuỗi đã biết. Khi tài khoản proxy đổi mật khẩu, chuỗi cũ không còn ý nghĩa. Sau mỗi lần đổi, lấy vài mảnh của mật khẩu mới, chừng 5 đến 6 ký tự, tìm trong đầu ra của Vector một ngày.
Kết quả phải là không có. Nếu có, xem dòng đó thuộc nguồn nào và vì sao regex không khớp. Thường là một định dạng log mới, hoặc thư viện in mật khẩu ở chỗ không có tiền tố scheme.
Checklist trước khi dùng thật

Checklist Vector cho log proxy
- Ghi bản Vector và ngày thử, giữ tệp .vrl trong kho mã.
- drop_on_error và reroute_dropped đều bật, output dropped có bước che riêng.
- Regex xóa tài khoản lấy tới dấu @ cuối, đã thử mật khẩu có @ chưa mã hóa.
- Unit test kiểm mảnh bí mật, chạy vector test trong CI.
- error_code chỉ gồm bộ giá trị đã thống nhất, không có unknown tăng dần.
- Có cảnh báo khi số sự kiện dead-letter tăng.
- Label gửi sang Loki chỉ là giá trị cố định.
Nguồn proxy cho crawler sau khi Vector chuẩn hóa log proxy
Log sạch giúp phân biệt lỗi tài khoản và lỗi mạng
Khi mọi worker cùng ghi error_code thống nhất, đếm được tỷ lệ proxy_auth_407 so với proxy_refused và timeout theo từng endpoint proxy. Tỷ lệ 407 cao thường do cấu hình tài khoản. Tỷ lệ refused cao thường do endpoint hoặc mạng. Hai trường hợp cần hai cách xử lý khác nhau.
ProxyVN có proxy dân cư tĩnh, datacenter, 4G và proxy xoay, hỗ trợ HTTP và SOCKS5, cấp tài khoản user và mật khẩu. Anh em cần endpoint ổn định để error_code phản ánh đúng lỗi phía mình có thể mua proxy tốc độ cao tại trang chủ ProxyVN.
Không ghi mật khẩu vào log từ đầu
Chuẩn hóa ở Vector là lớp bảo vệ thứ hai. Lớp đầu là code crawler không in URL proxy có tài khoản. Với requests, có thể bắt ProxyError rồi tự ghi thông báo ngắn, không kèm repr của ngoại lệ. Bài requests.exceptions.ProxyError có các dạng thông báo thường gặp để biết chuỗi nào cần tránh.
Câu hỏi thường gặp về Vector chuẩn hóa log proxy
Có nên dùng hàm redact thay vì replace?
Hàm redact của VRL thay toàn bộ đoạn khớp bằng [REDACTED], hỗ trợ cả băm SHA-2, SHA-3. Với URL proxy, replace giữ lại scheme để người đọc vẫn biết đó là http hay socks5h. Có thể dùng redact cho header và token, nơi không cần giữ phần nào.
Có thể băm tên tài khoản proxy thay vì xóa?
Có, redactor sha2 của hàm redact tạo giá trị băm. Băm giúp đếm theo tài khoản mà không lộ tên. Nhưng tên tài khoản ngắn dễ đoán ngược bằng cách thử, nên coi giá trị băm vẫn là dữ liệu nhạy cảm.
Vector có chạy trên Windows không?
Có gói Windows chính thức cho bản 0.60.0. Bài chưa chạy được gói này do giới hạn của môi trường lab.
Dead-letter nên giữ bao lâu?
Đủ để sửa nguồn log, thường vài ngày. Dead-letter đã che bí mật nhưng vẫn là log thô của ứng dụng, có thể chứa URL hay dữ liệu khác cần bảo vệ.
Giới hạn của bài
Bài chưa chạy Vector, chưa chạy vector validate hay vector test. Logic VRL được kiểm gián tiếp bằng script Python dùng cùng regex. Regex của VRL theo cú pháp Rust, Python có khác biệt nhỏ ở vài cú pháp nâng cao, các mẫu trong bài chỉ dùng phần chung. Chưa thử log Playwright, aiohttp thật, chưa thử sink Loki thật.
Mở rộng bộ quy tắc khi Vector chuẩn hóa log proxy đã chạy ổn
Thêm nguồn log
Khi thêm crawler viết bằng ngôn ngữ khác, định dạng log có thể không phải JSON. Thay vì sửa normalize.vrl cho mọi kiểu, dùng transform route chia theo nguồn, mỗi nhánh một chương trình tách riêng, rồi gộp về một chương trình che và gắn mã chung.
Cách này giữ phần che bí mật ở một chỗ duy nhất. Sửa regex một lần là áp cho mọi nguồn, và unit test chỉ cần viết cho chương trình chung.
Đo hiệu năng
Tài liệu parse_regex nhắc biểu thức động bị biên dịch lại mỗi lần gọi, nên dùng biểu thức hằng như r'...' trong bài. Remap có khóa measure_cpu_usage để đo thời gian CPU của transform. Bật khóa này khi lượng log lớn để biết chương trình VRL tốn bao nhiêu.
Ghi lại quyết định
Mỗi mã error_code mới nên có một dòng ghi chú: mẫu nào khớp, lấy từ thư viện nào, ngày thêm. Người sau đọc sẽ biết vì sao 407 đứng trước timeout, và tránh đổi thứ tự làm lệch số liệu.
Vector chuẩn hóa log proxy và những điều cần nhớ
Vector chuẩn hóa log proxy cần ba thứ: VRL tách JSON và gắn error_code cố định, regex xóa tài khoản lấy tới dấu @ cuối, và output dropped cũng phải qua bước che vì nó giữ bản gốc. Kiểm bằng cả mảnh bí mật, không chỉ nguyên chuỗi. Cần proxy ổn định cho pipeline Vector chuẩn hóa log proxy, liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam.