wmproxy
已用Rust
實現http/https
代理, socks5
代理, 反向代理, 靜態檔案伺服器,四層TCP/UDP轉發,內網穿透,後續將實現websocket
代理等,會將實現過程分享出來,感興趣的可以一起造個輪子
國內: https://gitee.com/tickbh/wmproxy
github: https://github.com/tickbh/wmproxy
紀錄檔在程式中的重要性非常的重要,當系統發生故障時,我們要隨時能排查出相關的紀錄檔,所以通常有了紀錄檔分級的概念(如錯誤error,警告warn,資訊info,偵錯debug,追蹤trace),如果系統出了嚴重的Bug,那我們此時應該排查warn及error看是否有相應的錯誤資訊。如果是程式流程上的問題,可能會很瑣碎,那我們可能需要排查trace的訊息。
相對來說,trace的紀錄檔資料量極大,當然也最瑣碎,排查起來會極難排查,要根據相關的關鍵字來定位相關紀錄檔,通常一個型別的紀錄檔會定義相同的關鍵字,在Java中類似Tag這種,在Rust庫中紀錄檔會根據庫自動顯示出來,我們可以輕鬆的根據庫名定位同一個庫的問題。同一個庫內可根據關鍵字來定位。
程式中存在標準輸出
(stdout)
及錯誤輸出(stderr)
,通常程式的執行中會將標準輸出的內容顯示在控制檯上,我們就可以根據輸出的內容來判定程式是否正常執行。在Rust中,最常用的是宏println!()
。
如果是服務型別的程式,常常會將資料輸出到檔案中,因為它執行時間通常按天或者月甚至是年來計算。產生的紀錄檔量也極為龐大,通常要按天來切割紀錄檔,且單檔案可能上GB大小,在後臺執行時,通過也會通過重定向將控制檯的內容輸出到檔案上。
後臺執行command命令,並將內容輸出到myout.log,且將stderr重定向到stdout。如:
nohup command > myout.log 2>&1 &
通常在Rust中有紀錄檔庫基本上都是基於log
庫去做實現,他定義了紀錄檔的等級,總共5個級別
pub enum Level {
Error = 1,
Warn,
Info,
Debug,
Trace,
}
通常用宏來進行輸出,下面來看下輸出宏的定義:
#[macro_export]
macro_rules! info {
(target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Info, $($arg)+));
($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+))
}
他分為兩種情況,一種是有目標target
,一種是預設target為root
在wmproxy中,我們通過服務的型別,找到紀錄檔輸出的不同target,就可以控制輸出目錄一致或者不一致的控制,如:
log::info!(target: "access", "{}", String::from_utf8_lossy(&buf[..]));
此外設定紀錄檔的等級,如果設定為等級為Level::Info
那麼log::trace!
及log::debug!
的紀錄檔將不會做任何輸出。
以下是我用過的兩個紀錄檔庫:
env_logger::init();
以下是如何啟動控制最簡單版:
RUST_LOG=debug cargo run
# windows
$env:RUST_LOG="debug"
cargo run
此外還可以設定特定庫的紀錄檔等級:
當前庫預設的紀錄檔等級是info,但是wenmeng及webparse庫的紀錄檔等級為warn,可以有效的過濾第三方庫紀錄檔資訊又不影響自身的資訊
RUST_LOG="info,wenmeng=warn,webparse=warn" cargo run
# 每隔30秒檢查當前檔案
refresh_rate: 30 seconds
appenders:
# 標準輸出的型別設定為控制檯
stdout:
kind: console
# 請求資料放置在log/requests.log檔案中
requests:
kind: file
path: "log/requests.log"
encoder:
# 輸出格式d為日期,m為內容,n為換行符
pattern: "{d} - {m}{n}"
root:
# 預設的紀錄檔等級為warn
level: warn
# 標準輸出只輸到stdout的設定,即上面設定的控制檯
appenders:
- stdout
loggers:
app::backend::db:
level: info
app::requests:
level: info
appenders:
- requests
# 是否追加到root裡,如果設定為true他將同時輸出兩個
additive: false
然後呼叫初始化:
log4rs::init_file("log4rs.yml", Default::default()).unwrap();
應用程式獲取紀錄檔記錄並將其記錄到某個地方,例如,將其記錄到檔案、控制檯或系統紀錄檔中。
console_appender
特徵file_appender
特徵rolling_file_appender
特徵且必須設定compound_policy
以下是隻保留10m大小的紀錄檔,多餘資料全部刪除的設定:
kind: rolling_file
path: log/foo.log
append: true
encoder:
kind: pattern
policy:
kind: compound
trigger:
kind: size
limit: 10 mb
roller:
kind: delete
如果要保留舊資料,可以修改roller
的設定:
kind: fixed_window
pattern: archive/foo.{}.log
count: 5
base: 1
舊檔案將會保持archive/foo.0.log
,archive/foo.1.log
……archive/foo.4.log
如果設定的字尾名稱為.gz
且開始了gzip的特徵,那麼目標檔案將會被自動壓縮成gz格式,如archive/foo.{}.log.gz
。如:
log4rs = { version ="1.0.0", features = ["gzip"] }
這是log4rs的簡單模型輸出,以{}
裡面包含目標資料及可能攜帶的引數:
d
, date
- 當前的日期格式.chrono
,獲取的紀錄檔的寫入的當前時間,第一個引數為時間的自定為格式,第二個引數 是utc
或者為local
。以下引數
{d}
- 2022-11-15T14:22:20.644420340-08:00
{d(%Y-%m-%d %H:%M:%S)}
- 2022-11-15 14:22:20
{d(%Y-%m-%d %H:%M:%S %Z)(utc)}
- 2022-11-15 22:22:20 UTC
f
, file
- 當前列印的原始檔,如果沒有顯示???
。h
, highlight
- 高亮當前紀錄檔,如果有錯誤顯示紅色,藍色顯示info等
{h(the level is {l})}
-<code style="color: red; font-weight: bold">the level is ERROR</code>
l
, level
- 當前紀錄檔等級.L
, line
- 當前列印的原始檔的行數,如果沒有顯示???
m
, message
- 當前的訊息詳情.M
, module
- 當前列印的源模組,如果沒有顯示???
P
, pid
- 當前的程序id.i
, tid
- 當前的執行緒id.n
- 換行符.t
, target
- 目標輸出的target.T
, thread
- 當前的執行緒名稱.I
, thread_id
- pthread的執行緒id.log4rs提供了自定義的一些功能,可以友好的設定一些紀錄檔的功能,下一篇將講解如何自定義實現access_log
和error_log
的功能。
點選 [關注],[在看],[點贊] 是對作者最大的支援